Test email to commits list. Please ignore.
--
Daniel Bartholomew, MariaDB Release Manager
MariaDB | https://mariadb.com
1
0

[Commits] ad68ee6035c: MDEV-20468: Allocating more space than required for JOIN_TAB array for a query with SJM table
by Varun 02 Sep '19
by Varun 02 Sep '19
02 Sep '19
revision-id: ad68ee6035c187ffcf9a2d8fbe4a2f4d670b5a52 (mariadb-10.4.7-49-gad68ee6035c)
parent(s): b1e377997e987b66c999713bdb7e6cfdb87797ae
author: Varun Gupta
committer: Varun Gupta
timestamp: 2019-09-02 19:07:25 +0530
message:
MDEV-20468: Allocating more space than required for JOIN_TAB array for a query with SJM table
---
sql/opt_subselect.cc | 33 +++++++++++++++++++++++++++++++++
sql/opt_subselect.h | 1 +
sql/sql_select.cc | 15 ++++++++-------
3 files changed, 42 insertions(+), 7 …
[View More]deletions(-)
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index e0873185461..86f9c27ae9e 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -3926,6 +3926,39 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
}
+/*
+ Return the number of tables at the top-level of the JOIN
+
+ SYNOPSIS
+ get_number_of_tables_at_top_level()
+ join The join with the picked join order
+
+ DESCRIPTION
+ The number of tables in the JOIN currently include all the inner tables of the
+ mergeable semi-joins. The function would make sure that we only count the semi-join
+ nest and not the inner tables of teh semi-join nest.
+*/
+
+uint get_number_of_tables_at_top_level(JOIN *join)
+{
+ uint j= 0, tables= 0;
+ while(j < join->table_count)
+ {
+ POSITION *cur_pos= &join->best_positions[j];
+ tables++;
+ if (cur_pos->sj_strategy == SJ_OPT_MATERIALIZE ||
+ cur_pos->sj_strategy == SJ_OPT_MATERIALIZE_SCAN)
+ {
+ SJ_MATERIALIZATION_INFO *sjm= cur_pos->table->emb_sj_nest->sj_mat_info;
+ j= j + sjm->tables;
+ }
+ else
+ j++;
+ }
+ return tables;
+}
+
+
/*
Setup semi-join materialization strategy for one semi-join nest
diff --git a/sql/opt_subselect.h b/sql/opt_subselect.h
index 6210fc972c8..a0dbda360f0 100644
--- a/sql/opt_subselect.h
+++ b/sql/opt_subselect.h
@@ -319,6 +319,7 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join);
bool setup_sj_materialization_part1(JOIN_TAB *sjm_tab);
bool setup_sj_materialization_part2(JOIN_TAB *sjm_tab);
+uint get_number_of_tables_at_top_level(JOIN *join);
/*
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index bd6d9852f40..bfcd0ee414f 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -3597,7 +3597,7 @@ bool JOIN::make_aggr_tables_info()
unit->select_limit_cnt == 1 (we only need one row in the result set)
*/
sort_tab->filesort->limit=
- (has_group_by || (join_tab + table_count > curr_tab + 1)) ?
+ (has_group_by || (join_tab + top_join_tab_count > curr_tab + 1)) ?
select_limit : unit->select_limit_cnt;
}
if (!only_const_tables() &&
@@ -10162,14 +10162,16 @@ bool JOIN::get_best_combination()
if (aggr_tables > 2)
aggr_tables= 2;
- if (!(join_tab= (JOIN_TAB*) thd->alloc(sizeof(JOIN_TAB)*
- (top_join_tab_count + aggr_tables))))
- DBUG_RETURN(TRUE);
full_join=0;
hash_join= FALSE;
fix_semijoin_strategies_for_picked_join_order(this);
+ top_join_tab_count= get_number_of_tables_at_top_level(this);
+
+ if (!(join_tab= (JOIN_TAB*) thd->alloc(sizeof(JOIN_TAB)*
+ (top_join_tab_count + aggr_tables))))
+ DBUG_RETURN(TRUE);
JOIN_TAB_RANGE *root_range;
if (!(root_range= new (thd->mem_root) JOIN_TAB_RANGE))
@@ -13878,7 +13880,7 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond,
ORDER BY and GROUP BY
*/
for (JOIN_TAB *tab= join->join_tab + join->const_tables;
- tab < join->join_tab + join->table_count;
+ tab < join->join_tab + join->top_join_tab_count;
tab++)
tab->cached_eq_ref_table= FALSE;
@@ -19615,8 +19617,7 @@ do_select(JOIN *join, Procedure *procedure)
if (join->pushdown_query->store_data_in_temp_table)
{
- JOIN_TAB *last_tab= join->join_tab + join->table_count -
- join->exec_join_tab_cnt();
+ JOIN_TAB *last_tab= join->join_tab + join->exec_join_tab_cnt();
last_tab->next_select= end_send;
enum_nested_loop_state state= last_tab->aggr->end_send();
[View Less]
1
0
revision-id: de5f7348bddc1b885a6554ce38cd8017386f4106 (mariadb-10.4.7-49-gde5f7348bdd)
parent(s): b1e377997e987b66c999713bdb7e6cfdb87797ae
author: Sergei Petrunia
committer: Sergei Petrunia
timestamp: 2019-09-02 14:22:19 +0300
message:
Make main.subselect_sj2* tests stable
Use EITS statistics to avoid changing query plans
---
mysql-test/main/subselect_sj2.result | 32 +++++++++++++++++++++++--------
mysql-test/main/subselect_sj2.test | 3 +++
mysql-test/main/subselect_sj2_jcl6.…
[View More]result | 32 +++++++++++++++++++++++--------
mysql-test/main/subselect_sj2_mat.result | 32 +++++++++++++++++++++++--------
4 files changed, 75 insertions(+), 24 deletions(-)
diff --git a/mysql-test/main/subselect_sj2.result b/mysql-test/main/subselect_sj2.result
index 31453801220..bab21da8243 100644
--- a/mysql-test/main/subselect_sj2.result
+++ b/mysql-test/main/subselect_sj2.result
@@ -813,6 +813,14 @@ CREATE TABLE t2 (f14 int(11) NOT NULL, f12 varchar(1) NOT NULL, KEY (f12,f14)) E
INSERT INTO t2 VALUES (6,'y');
CREATE TABLE t3 (f12 varchar(1) NOT NULL) ENGINE=InnoDB;
INSERT INTO t3 VALUES ('r'),('s'),('t'),('v'),('w'),('x'),('y');
+analyze table t1,t2,t3 persistent for all;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+test.t2 analyze status Engine-independent statistics collected
+test.t2 analyze status OK
+test.t3 analyze status Engine-independent statistics collected
+test.t3 analyze status OK
# The following must use LooseScan but not join buffering
explain
SELECT * FROM t3
@@ -1102,6 +1110,14 @@ INSERT INTO t2 VALUES
(9,'d','d'),(10,'s','s'),(11,'r','r'),(12,'m','m'),
(13,'b','b'),(14,'x','x'),(15,'g','g'),(16,'p','p'),
(17,'q','q'),(18,'w','w'),(19,'d','d');
+analyze table t1 persistent for all;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+analyze table t2 persistent for all;
+Table Op Msg_type Msg_text
+test.t2 analyze status Engine-independent statistics collected
+test.t2 analyze status OK
EXPLAIN
SELECT COUNT(*) FROM t1 AS alias1, t1 AS alias2, t2 AS alias3
WHERE alias3.d IN (
@@ -1110,11 +1126,11 @@ WHERE alias5.b = alias4.b
AND ( alias5.b >= alias3.b OR alias5.c != alias3.c )
);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY alias3 ALL PRIMARY NULL NULL NULL #
-1 PRIMARY alias5 index PRIMARY c 4 NULL # Using where; Using index
-1 PRIMARY alias4 eq_ref PRIMARY,c PRIMARY 4 test.alias5.b # Using where; FirstMatch(alias3)
-1 PRIMARY alias1 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
+1 PRIMARY alias3 ALL PRIMARY NULL NULL NULL # Using where
+1 PRIMARY alias4 ref PRIMARY,c c 4 test.alias3.d # Using index
+1 PRIMARY alias5 eq_ref PRIMARY PRIMARY 4 test.alias4.b # Using where; FirstMatch(alias3)
1 PRIMARY alias2 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
+1 PRIMARY alias1 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
SELECT COUNT(*) FROM t1 AS alias1, t1 AS alias2, t2 AS alias3
WHERE alias3.d IN (
SELECT alias4.c FROM t2 AS alias4, t2 AS alias5
@@ -1131,11 +1147,11 @@ WHERE alias5.b = alias4.b
AND ( alias5.b >= alias3.b OR alias3.c != alias5.c )
);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY alias3 ALL PRIMARY NULL NULL NULL #
-1 PRIMARY alias5 index PRIMARY c 4 NULL # Using where; Using index
-1 PRIMARY alias4 eq_ref PRIMARY,c PRIMARY 4 test.alias5.b # Using where; FirstMatch(alias3)
-1 PRIMARY alias1 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
+1 PRIMARY alias3 ALL PRIMARY NULL NULL NULL # Using where
+1 PRIMARY alias4 ref PRIMARY,c c 4 test.alias3.d # Using index
+1 PRIMARY alias5 eq_ref PRIMARY PRIMARY 4 test.alias4.b # Using where; FirstMatch(alias3)
1 PRIMARY alias2 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
+1 PRIMARY alias1 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
SELECT COUNT(*) FROM t1 AS alias1, t1 AS alias2, t2 AS alias3
WHERE alias3.d IN (
SELECT alias4.c FROM t2 AS alias4, t2 AS alias5
diff --git a/mysql-test/main/subselect_sj2.test b/mysql-test/main/subselect_sj2.test
index 2b4f619a615..8886c42eb55 100644
--- a/mysql-test/main/subselect_sj2.test
+++ b/mysql-test/main/subselect_sj2.test
@@ -994,6 +994,7 @@ INSERT INTO t2 VALUES (6,'y');
CREATE TABLE t3 (f12 varchar(1) NOT NULL) ENGINE=InnoDB;
INSERT INTO t3 VALUES ('r'),('s'),('t'),('v'),('w'),('x'),('y');
+analyze table t1,t2,t3 persistent for all;
--echo # The following must use LooseScan but not join buffering
--replace_column 9 #
@@ -1225,6 +1226,8 @@ INSERT INTO t2 VALUES
(13,'b','b'),(14,'x','x'),(15,'g','g'),(16,'p','p'),
(17,'q','q'),(18,'w','w'),(19,'d','d');
+analyze table t1 persistent for all;
+analyze table t2 persistent for all;
--replace_column 9 #
EXPLAIN
SELECT COUNT(*) FROM t1 AS alias1, t1 AS alias2, t2 AS alias3
diff --git a/mysql-test/main/subselect_sj2_jcl6.result b/mysql-test/main/subselect_sj2_jcl6.result
index 3321ba221f3..ac2d12fc5df 100644
--- a/mysql-test/main/subselect_sj2_jcl6.result
+++ b/mysql-test/main/subselect_sj2_jcl6.result
@@ -826,6 +826,14 @@ CREATE TABLE t2 (f14 int(11) NOT NULL, f12 varchar(1) NOT NULL, KEY (f12,f14)) E
INSERT INTO t2 VALUES (6,'y');
CREATE TABLE t3 (f12 varchar(1) NOT NULL) ENGINE=InnoDB;
INSERT INTO t3 VALUES ('r'),('s'),('t'),('v'),('w'),('x'),('y');
+analyze table t1,t2,t3 persistent for all;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+test.t2 analyze status Engine-independent statistics collected
+test.t2 analyze status OK
+test.t3 analyze status Engine-independent statistics collected
+test.t3 analyze status OK
# The following must use LooseScan but not join buffering
explain
SELECT * FROM t3
@@ -1115,6 +1123,14 @@ INSERT INTO t2 VALUES
(9,'d','d'),(10,'s','s'),(11,'r','r'),(12,'m','m'),
(13,'b','b'),(14,'x','x'),(15,'g','g'),(16,'p','p'),
(17,'q','q'),(18,'w','w'),(19,'d','d');
+analyze table t1 persistent for all;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+analyze table t2 persistent for all;
+Table Op Msg_type Msg_text
+test.t2 analyze status Engine-independent statistics collected
+test.t2 analyze status OK
EXPLAIN
SELECT COUNT(*) FROM t1 AS alias1, t1 AS alias2, t2 AS alias3
WHERE alias3.d IN (
@@ -1123,11 +1139,11 @@ WHERE alias5.b = alias4.b
AND ( alias5.b >= alias3.b OR alias5.c != alias3.c )
);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY alias3 ALL PRIMARY NULL NULL NULL #
-1 PRIMARY alias5 index PRIMARY c 4 NULL # Using where; Using index; Using join buffer (flat, BNL join)
-1 PRIMARY alias4 eq_ref PRIMARY,c PRIMARY 4 test.alias5.b # Using where; FirstMatch(alias3); Using join buffer (incremental, BKA join); Key-ordered scan
+1 PRIMARY alias3 ALL PRIMARY NULL NULL NULL # Using where
+1 PRIMARY alias4 ref PRIMARY,c c 4 test.alias3.d # Using index
+1 PRIMARY alias5 eq_ref PRIMARY PRIMARY 4 test.alias4.b # Using where; FirstMatch(alias3)
+1 PRIMARY alias2 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
1 PRIMARY alias1 ALL NULL NULL NULL NULL # Using join buffer (incremental, BNL join)
-1 PRIMARY alias2 ALL NULL NULL NULL NULL # Using join buffer (incremental, BNL join)
SELECT COUNT(*) FROM t1 AS alias1, t1 AS alias2, t2 AS alias3
WHERE alias3.d IN (
SELECT alias4.c FROM t2 AS alias4, t2 AS alias5
@@ -1144,11 +1160,11 @@ WHERE alias5.b = alias4.b
AND ( alias5.b >= alias3.b OR alias3.c != alias5.c )
);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY alias3 ALL PRIMARY NULL NULL NULL #
-1 PRIMARY alias5 index PRIMARY c 4 NULL # Using where; Using index; Using join buffer (flat, BNL join)
-1 PRIMARY alias4 eq_ref PRIMARY,c PRIMARY 4 test.alias5.b # Using where; FirstMatch(alias3); Using join buffer (incremental, BKA join); Key-ordered scan
+1 PRIMARY alias3 ALL PRIMARY NULL NULL NULL # Using where
+1 PRIMARY alias4 ref PRIMARY,c c 4 test.alias3.d # Using index
+1 PRIMARY alias5 eq_ref PRIMARY PRIMARY 4 test.alias4.b # Using where; FirstMatch(alias3)
+1 PRIMARY alias2 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
1 PRIMARY alias1 ALL NULL NULL NULL NULL # Using join buffer (incremental, BNL join)
-1 PRIMARY alias2 ALL NULL NULL NULL NULL # Using join buffer (incremental, BNL join)
SELECT COUNT(*) FROM t1 AS alias1, t1 AS alias2, t2 AS alias3
WHERE alias3.d IN (
SELECT alias4.c FROM t2 AS alias4, t2 AS alias5
diff --git a/mysql-test/main/subselect_sj2_mat.result b/mysql-test/main/subselect_sj2_mat.result
index 7245e74b242..e55025f4fa8 100644
--- a/mysql-test/main/subselect_sj2_mat.result
+++ b/mysql-test/main/subselect_sj2_mat.result
@@ -815,6 +815,14 @@ CREATE TABLE t2 (f14 int(11) NOT NULL, f12 varchar(1) NOT NULL, KEY (f12,f14)) E
INSERT INTO t2 VALUES (6,'y');
CREATE TABLE t3 (f12 varchar(1) NOT NULL) ENGINE=InnoDB;
INSERT INTO t3 VALUES ('r'),('s'),('t'),('v'),('w'),('x'),('y');
+analyze table t1,t2,t3 persistent for all;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+test.t2 analyze status Engine-independent statistics collected
+test.t2 analyze status OK
+test.t3 analyze status Engine-independent statistics collected
+test.t3 analyze status OK
# The following must use LooseScan but not join buffering
explain
SELECT * FROM t3
@@ -1104,6 +1112,14 @@ INSERT INTO t2 VALUES
(9,'d','d'),(10,'s','s'),(11,'r','r'),(12,'m','m'),
(13,'b','b'),(14,'x','x'),(15,'g','g'),(16,'p','p'),
(17,'q','q'),(18,'w','w'),(19,'d','d');
+analyze table t1 persistent for all;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+analyze table t2 persistent for all;
+Table Op Msg_type Msg_text
+test.t2 analyze status Engine-independent statistics collected
+test.t2 analyze status OK
EXPLAIN
SELECT COUNT(*) FROM t1 AS alias1, t1 AS alias2, t2 AS alias3
WHERE alias3.d IN (
@@ -1112,11 +1128,11 @@ WHERE alias5.b = alias4.b
AND ( alias5.b >= alias3.b OR alias5.c != alias3.c )
);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY alias3 ALL PRIMARY NULL NULL NULL #
-1 PRIMARY alias5 index PRIMARY c 4 NULL # Using where; Using index
-1 PRIMARY alias4 eq_ref PRIMARY,c PRIMARY 4 test.alias5.b # Using where; FirstMatch(alias3)
-1 PRIMARY alias1 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
+1 PRIMARY alias3 ALL PRIMARY NULL NULL NULL # Using where
+1 PRIMARY alias4 ref PRIMARY,c c 4 test.alias3.d # Using index
+1 PRIMARY alias5 eq_ref PRIMARY PRIMARY 4 test.alias4.b # Using where; FirstMatch(alias3)
1 PRIMARY alias2 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
+1 PRIMARY alias1 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
SELECT COUNT(*) FROM t1 AS alias1, t1 AS alias2, t2 AS alias3
WHERE alias3.d IN (
SELECT alias4.c FROM t2 AS alias4, t2 AS alias5
@@ -1133,11 +1149,11 @@ WHERE alias5.b = alias4.b
AND ( alias5.b >= alias3.b OR alias3.c != alias5.c )
);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY alias3 ALL PRIMARY NULL NULL NULL #
-1 PRIMARY alias5 index PRIMARY c 4 NULL # Using where; Using index
-1 PRIMARY alias4 eq_ref PRIMARY,c PRIMARY 4 test.alias5.b # Using where; FirstMatch(alias3)
-1 PRIMARY alias1 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
+1 PRIMARY alias3 ALL PRIMARY NULL NULL NULL # Using where
+1 PRIMARY alias4 ref PRIMARY,c c 4 test.alias3.d # Using index
+1 PRIMARY alias5 eq_ref PRIMARY PRIMARY 4 test.alias4.b # Using where; FirstMatch(alias3)
1 PRIMARY alias2 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
+1 PRIMARY alias1 ALL NULL NULL NULL NULL # Using join buffer (flat, BNL join)
SELECT COUNT(*) FROM t1 AS alias1, t1 AS alias2, t2 AS alias3
WHERE alias3.d IN (
SELECT alias4.c FROM t2 AS alias4, t2 AS alias5
[View Less]
1
0

[Commits] a9af7ed477a: MDEV-20444: More information regarding access of a table to be printed inside the optimizer_trace
by Varun 01 Sep '19
by Varun 01 Sep '19
01 Sep '19
revision-id: a9af7ed477a46a0ee2cbb592a01167f08278f48b (mariadb-10.4.7-46-ga9af7ed477a)
parent(s): fafa92684b418d846a5537ab15588f0ccaf1b6f1
author: Varun Gupta
committer: Varun Gupta
timestamp: 2019-09-02 00:21:56 +0530
message:
MDEV-20444: More information regarding access of a table to be printed inside the optimizer_trace
Added:
1) estimated_join_cardinality
2) best_chosen_access_method for a table
3) best_join_order
---
mysql-test/main/opt_trace.result …
[View More]| 1528 ++++++++++++++++----
mysql-test/main/opt_trace_index_merge.result | 17 +-
.../main/opt_trace_index_merge_innodb.result | 15 +-
mysql-test/main/opt_trace_security.result | 34 +-
sql/opt_trace.cc | 40 +
sql/opt_trace.h | 3 +
sql/sql_select.cc | 44 +-
7 files changed, 1385 insertions(+), 296 deletions(-)
diff --git a/mysql-test/main/opt_trace.result b/mysql-test/main/opt_trace.result
index ab07db38d05..691a8370dc9 100644
--- a/mysql-test/main/opt_trace.result
+++ b/mysql-test/main/opt_trace.result
@@ -130,18 +130,29 @@ select * from v1 {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 1,
"cost": 2.2044,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 1,
+ "cost": 2.2044,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 1,
- "cost_for_plan": 2.4044
+ "cost_for_plan": 2.4044,
+ "estimated_join_cardinality": 1
}
]
},
+ {
+ "best_join_order": ["t1"]
+ },
{
"attaching_conditions_to_tables": {
"original_condition": "t1.a = 1",
@@ -265,18 +276,29 @@ select * from (select * from t1 where t1.a=1)q {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 1,
"cost": 2.2044,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 1,
+ "cost": 2.2044,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 1,
- "cost_for_plan": 2.4044
+ "cost_for_plan": 2.4044,
+ "estimated_join_cardinality": 1
}
]
},
+ {
+ "best_join_order": ["t1"]
+ },
{
"attaching_conditions_to_tables": {
"original_condition": "t1.a = 1",
@@ -405,19 +427,30 @@ select * from v2 {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 1,
"cost": 2.2044,
"chosen": true,
"use_tmp_table": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 1,
+ "cost": 2.2044,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 1,
- "cost_for_plan": 2.4044
+ "cost_for_plan": 2.4044,
+ "estimated_join_cardinality": 1
}
]
},
+ {
+ "best_join_order": ["t1"]
+ },
{
"attaching_conditions_to_tables": {
"original_condition": "t1.a = 1",
@@ -462,18 +495,29 @@ select * from v2 {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 2,
"cost": 2,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 2,
+ "cost": 2,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 2,
- "cost_for_plan": 2.4
+ "cost_for_plan": 2.4,
+ "estimated_join_cardinality": 2
}
]
},
+ {
+ "best_join_order": ["<derived2>"]
+ },
{
"attaching_conditions_to_tables": {
"original_condition": null,
@@ -591,18 +635,29 @@ explain select * from v2 {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 10,
"cost": 2.022,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 10,
+ "cost": 2.022,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 10,
- "cost_for_plan": 4.022
+ "cost_for_plan": 4.022,
+ "estimated_join_cardinality": 10
}
]
},
+ {
+ "best_join_order": ["t2"]
+ },
{
"attaching_conditions_to_tables": {
"original_condition": null,
@@ -699,19 +754,30 @@ explain select * from v1 {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 10,
"cost": 2.022,
"chosen": true,
"use_tmp_table": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 10,
+ "cost": 2.022,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 10,
- "cost_for_plan": 4.022
+ "cost_for_plan": 4.022,
+ "estimated_join_cardinality": 10
}
]
},
+ {
+ "best_join_order": ["t1"]
+ },
{
"attaching_conditions_to_tables": {
"original_condition": null,
@@ -756,18 +822,29 @@ explain select * from v1 {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 10,
"cost": 10,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 10,
+ "cost": 10,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 10,
- "cost_for_plan": 12
+ "cost_for_plan": 12,
+ "estimated_join_cardinality": 10
}
]
},
+ {
+ "best_join_order": ["<derived2>"]
+ },
{
"attaching_conditions_to_tables": {
"original_condition": null,
@@ -917,12 +994,19 @@ explain select * from t1,t2 where t1.a=t2.b+2 and t2.a= t1.b {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 100,
"cost": 2.3174,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 100,
+ "cost": 2.3174,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 100,
"cost_for_plan": 22.317,
@@ -942,15 +1026,23 @@ explain select * from t1,t2 where t1.a=t2.b+2 and t2.a= t1.b {
"chosen": true
},
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 100,
"cost": 2.3174,
"chosen": false
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "ref",
+ "records": 1,
+ "cost": 200,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 100,
- "cost_for_plan": 242.32
+ "cost_for_plan": 242.32,
+ "estimated_join_cardinality": 100
}
]
},
@@ -960,12 +1052,19 @@ explain select * from t1,t2 where t1.a=t2.b+2 and t2.a= t1.b {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 100,
"cost": 2.3174,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 100,
+ "cost": 2.3174,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 100,
"cost_for_plan": 22.317,
@@ -985,12 +1084,19 @@ explain select * from t1,t2 where t1.a=t2.b+2 and t2.a= t1.b {
"chosen": true
},
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 100,
"cost": 2.3174,
"chosen": false
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "ref",
+ "records": 1,
+ "cost": 200,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 100,
"cost_for_plan": 242.32,
@@ -1000,6 +1106,9 @@ explain select * from t1,t2 where t1.a=t2.b+2 and t2.a= t1.b {
}
]
},
+ {
+ "best_join_order": ["t1", "t2"]
+ },
{
"attaching_conditions_to_tables": {
"original_condition": "t2.a = t1.b and t1.a = t2.b + 2",
@@ -1146,18 +1255,29 @@ EXPLAIN SELECT DISTINCT a FROM t1 {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "range",
+ "access_type": "index_merge",
"resulting_rows": 5,
"cost": 6.75,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "index_merge",
+ "records": 5,
+ "cost": 6.75,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 5,
- "cost_for_plan": 7.75
+ "cost_for_plan": 7.75,
+ "estimated_join_cardinality": 5
}
]
},
+ {
+ "best_join_order": ["t1"]
+ },
{
"attaching_conditions_to_tables": {
"original_condition": null,
@@ -1325,19 +1445,30 @@ EXPLAIN SELECT MIN(d) FROM t1 where b=2 and c=3 group by a {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 0.5849,
"cost": 3.3121,
"chosen": true,
"use_tmp_table": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 0.5849,
+ "cost": 3.3121,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 0.5849,
- "cost_for_plan": 3.4291
+ "cost_for_plan": 3.4291,
+ "estimated_join_cardinality": 0.5849
}
]
},
+ {
+ "best_join_order": ["t1"]
+ },
{
"attaching_conditions_to_tables": {
"original_condition": "t1.b = 2 and t1.c = 3",
@@ -1516,19 +1647,30 @@ EXPLAIN SELECT id,MIN(a),MAX(a) FROM t1 WHERE a>=20010104e0 GROUP BY id {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 16,
"cost": 2.0312,
"chosen": true,
"use_tmp_table": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 16,
+ "cost": 2.0312,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 16,
- "cost_for_plan": 5.2313
+ "cost_for_plan": 5.2313,
+ "estimated_join_cardinality": 16
}
]
},
+ {
+ "best_join_order": ["t1"]
+ },
{
"attaching_conditions_to_tables": {
"original_condition": "t1.a >= 20010104e0",
@@ -1696,19 +1838,30 @@ EXPLAIN SELECT * FROM t1 WHERE a = 20010104e0 GROUP BY id {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 16,
"cost": 2.0312,
"chosen": true,
"use_tmp_table": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 16,
+ "cost": 2.0312,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 16,
- "cost_for_plan": 5.2313
+ "cost_for_plan": 5.2313,
+ "estimated_join_cardinality": 16
}
]
},
+ {
+ "best_join_order": ["t1"]
+ },
{
"attaching_conditions_to_tables": {
"original_condition": "t1.a = 20010104e0",
@@ -1972,13 +2125,24 @@ explain select * from t1 where a=1 and b=2 order by c limit 1 {
"chosen": false,
"cause": "cost"
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "ref",
+ "records": 21,
+ "cost": 22,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 21,
- "cost_for_plan": 26.2
+ "cost_for_plan": 26.2,
+ "estimated_join_cardinality": 21
}
]
},
+ {
+ "best_join_order": ["t1"]
+ },
{
"attaching_conditions_to_tables": {
"original_condition": "t1.a = 1 and t1.b = 2",
@@ -2197,18 +2361,29 @@ select t1.a from t1 left join t2 on t1.a=t2.a {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 4,
"cost": 2.0068,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 4,
+ "cost": 2.0068,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 4,
- "cost_for_plan": 2.8068
+ "cost_for_plan": 2.8068,
+ "estimated_join_cardinality": 4
}
]
},
+ {
+ "best_join_order": ["t2", "t1"]
+ },
{
"condition_on_constant_tables": "1"
},
@@ -2313,12 +2488,19 @@ explain select * from t1 left join t2 on t2.a=t1.a {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 4,
"cost": 2.0068,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 4,
+ "cost": 2.0068,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 4,
"cost_for_plan": 2.8068,
@@ -2336,20 +2518,31 @@ explain select * from t1 left join t2 on t2.a=t1.a {
"chosen": true
},
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 2,
"cost": 8.0176,
"chosen": false
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "eq_ref",
+ "records": 1,
+ "cost": 4,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 4,
- "cost_for_plan": 7.6068
+ "cost_for_plan": 7.6068,
+ "estimated_join_cardinality": 4
}
]
}
]
},
+ {
+ "best_join_order": ["t1", "t2"]
+ },
{
"condition_on_constant_tables": "1"
},
@@ -2486,18 +2679,29 @@ explain select t1.a from t1 left join (t2 join t3 on t2.b=t3.b) on t2.a=t1.a and
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 4,
"cost": 2.0068,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 4,
+ "cost": 2.0068,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 4,
- "cost_for_plan": 2.8068
+ "cost_for_plan": 2.8068,
+ "estimated_join_cardinality": 4
}
]
},
+ {
+ "best_join_order": ["t3", "t2", "t1"]
+ },
{
"condition_on_constant_tables": "1"
},
@@ -2678,15 +2882,23 @@ explain extended select * from t1 where a in (select pk from t10) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 10,
"cost": 2.022,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 10,
+ "cost": 2.022,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 10,
- "cost_for_plan": 4.022
+ "cost_for_plan": 4.022,
+ "estimated_join_cardinality": 10
}
]
}
@@ -2701,12 +2913,19 @@ explain extended select * from t1 where a in (select pk from t10) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0066,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0066,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 3,
"cost_for_plan": 2.6066,
@@ -2718,12 +2937,19 @@ explain extended select * from t1 where a in (select pk from t10) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 10,
"cost": 2.022,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 10,
+ "cost": 2.022,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 30,
"cost_for_plan": 10.629,
@@ -2746,7 +2972,8 @@ explain extended select * from t1 where a in (select pk from t10) {
{
"chosen_strategy": "SJ-Materialize"
}
- ]
+ ],
+ "estimated_join_cardinality": 3
}
]
},
@@ -2756,12 +2983,19 @@ explain extended select * from t1 where a in (select pk from t10) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 10,
"cost": 2.022,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 10,
+ "cost": 2.022,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 10,
"cost_for_plan": 4.022,
@@ -2782,6 +3016,9 @@ explain extended select * from t1 where a in (select pk from t10) {
}
]
},
+ {
+ "best_join_order": ["t1", "<subquery2>"]
+ },
{
"condition_on_constant_tables": "1"
},
@@ -3105,13 +3342,24 @@ explain select * from t1 where pk = 2 and a=5 and b=1 {
"chosen": false,
"cause": "cost"
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "ref",
+ "records": 1,
+ "cost": 1.0043,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 1,
- "cost_for_plan": 1.2043
+ "cost_for_plan": 1.2043,
+ "estimated_join_cardinality": 1
}
]
},
+ {
+ "best_join_order": ["t1"]
+ },
{
"attaching_conditions_to_tables": {
"original_condition": "t1.pk = 2 and t1.a = 5 and t1.b = 1",
@@ -3214,18 +3462,29 @@ select f1(a) from t1 {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 4,
"cost": 2.0068,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 4,
+ "cost": 2.0068,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 4,
- "cost_for_plan": 2.8068
+ "cost_for_plan": 2.8068,
+ "estimated_join_cardinality": 4
}
]
},
+ {
+ "best_join_order": ["t1"]
+ },
{
"attaching_conditions_to_tables": {
"original_condition": null,
@@ -3302,18 +3561,29 @@ select f2(a) from t1 {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 4,
"cost": 2.0068,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 4,
+ "cost": 2.0068,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 4,
- "cost_for_plan": 2.8068
+ "cost_for_plan": 2.8068,
+ "estimated_join_cardinality": 4
}
]
},
+ {
+ "best_join_order": ["t1"]
+ },
{
"attaching_conditions_to_tables": {
"original_condition": null,
@@ -3354,7 +3624,7 @@ a
2
select length(trace) from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
length(trace)
-1831
+2204
set optimizer_trace_max_mem_size=100;
select * from t1;
a
@@ -3368,7 +3638,7 @@ select * from t1 {
"join_preparation": {
"select_id": 1,
"steps": [
- 1731 0
+ 2104 0
set optimizer_trace_max_mem_size=0;
select * from t1;
a
@@ -3376,7 +3646,7 @@ a
2
select * from INFORMATION_SCHEMA.OPTIMIZER_TRACE;
QUERY TRACE MISSING_BYTES_BEYOND_MAX_MEM_SIZE INSUFFICIENT_PRIVILEGES
-select * from t1 1831 0
+select * from t1 2204 0
drop table t1;
set optimizer_trace='enabled=off';
set @@optimizer_trace_max_mem_size= @save_optimizer_trace_max_mem_size;
@@ -3679,7 +3949,14 @@ explain delete t0,t1 from t0, t1 where t0.a=t1.a and t1.a<3 {
"cost": 1.407,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "range",
+ "records": 3,
+ "cost": 1.407,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 3,
"cost_for_plan": 2.007,
@@ -3703,10 +3980,18 @@ explain delete t0,t1 from t0, t1 where t0.a=t1.a and t1.a<3 {
"chosen": false,
"cause": "cost"
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "ref",
+ "records": 1,
+ "cost": 3.007,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 3,
- "cost_for_plan": 5.614
+ "cost_for_plan": 5.614,
+ "estimated_join_cardinality": 3
}
]
},
@@ -3721,7 +4006,14 @@ explain delete t0,t1 from t0, t1 where t0.a=t1.a and t1.a<3 {
"cost": 1.407,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "range",
+ "records": 3,
+ "cost": 1.407,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 3,
"cost_for_plan": 2.007,
@@ -3745,7 +4037,14 @@ explain delete t0,t1 from t0, t1 where t0.a=t1.a and t1.a<3 {
"chosen": false,
"cause": "cost"
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "ref",
+ "records": 2,
+ "cost": 3.014,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 6,
"cost_for_plan": 6.2211,
@@ -3755,6 +4054,9 @@ explain delete t0,t1 from t0, t1 where t0.a=t1.a and t1.a<3 {
}
]
},
+ {
+ "best_join_order": ["t0", "t1"]
+ },
{
"attaching_conditions_to_tables": {
"original_condition": "t1.a = t0.a and t0.a < 3",
@@ -3870,18 +4172,29 @@ explain select * from (select rand() from t1)q {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 3,
- "cost_for_plan": 2.6051
+ "cost_for_plan": 2.6051,
+ "estimated_join_cardinality": 3
}
]
},
+ {
+ "best_join_order": ["t1"]
+ },
{
"attaching_conditions_to_tables": {
"original_condition": null,
@@ -3926,18 +4239,29 @@ explain select * from (select rand() from t1)q {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 3,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 3,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 3,
- "cost_for_plan": 3.6
+ "cost_for_plan": 3.6,
+ "estimated_join_cardinality": 3
}
]
},
+ {
+ "best_join_order": ["<derived2>"]
+ },
{
"attaching_conditions_to_tables": {
"original_condition": null,
@@ -4124,12 +4448,19 @@ explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 3,
"cost_for_plan": 2.6051,
@@ -4140,15 +4471,23 @@ explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 9,
- "cost_for_plan": 6.4103
+ "cost_for_plan": 6.4103,
+ "estimated_join_cardinality": 9
}
]
},
@@ -4158,12 +4497,19 @@ explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 3,
"cost_for_plan": 2.6051,
@@ -4182,12 +4528,19 @@ explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 3,
"cost_for_plan": 2.6051,
@@ -4199,12 +4552,19 @@ explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 9,
"cost_for_plan": 6.4103,
@@ -4216,12 +4576,19 @@ explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 27,
"cost_for_plan": 13.815,
@@ -4244,7 +4611,8 @@ explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_
{
"chosen_strategy": "SJ-Materialize"
}
- ]
+ ],
+ "estimated_join_cardinality": 3
}
]
},
@@ -4254,12 +4622,19 @@ explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 9,
"cost_for_plan": 6.4103,
@@ -4274,12 +4649,19 @@ explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 3,
"cost_for_plan": 2.6051,
@@ -4292,12 +4674,19 @@ explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 3,
"cost_for_plan": 2.6051,
@@ -4321,6 +4710,9 @@ explain select * from t1 where a in (select t_inner_1.a from t1 t_inner_1, t1 t_
}
]
},
+ {
+ "best_join_order": ["t1", "<subquery2>"]
+ },
{
"condition_on_constant_tables": "1"
},
@@ -4591,12 +4983,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 3,
"cost_for_plan": 2.6051,
@@ -4608,12 +5007,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 9,
"cost_for_plan": 6.4103,
@@ -4625,12 +5031,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 81,
"cost_for_plan": 24.626,
@@ -4656,12 +5069,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 27,
"cost_for_plan": 34.174,
@@ -4678,12 +5098,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 81,
"cost_for_plan": 52.379,
@@ -4701,12 +5128,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 729,
"cost_for_plan": 200.19,
@@ -4724,7 +5158,8 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
{
"chosen_strategy": "FirstMatch"
}
- ]
+ ],
+ "estimated_join_cardinality": 27
}
]
},
@@ -4739,12 +5174,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 243,
"cost_for_plan": 84.79,
@@ -4759,12 +5201,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 9,
"cost_for_plan": 30.564,
@@ -4781,12 +5230,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 81,
"cost_for_plan": 48.779,
@@ -4804,12 +5260,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 729,
"cost_for_plan": 196.59,
@@ -4838,12 +5301,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 81,
"cost_for_plan": 48.779,
@@ -4858,12 +5328,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 27,
"cost_for_plan": 34.174,
@@ -4878,12 +5355,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 81,
"cost_for_plan": 24.626,
@@ -4895,12 +5379,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 729,
"cost_for_plan": 172.44,
@@ -4922,12 +5413,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 243,
"cost_for_plan": 75.231,
@@ -4944,12 +5442,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 2187,
"cost_for_plan": 514.65,
@@ -4967,12 +5472,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 2187,
"cost_for_plan": 514.65,
@@ -4987,12 +5499,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 729,
"cost_for_plan": 172.44,
@@ -5007,12 +5526,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 27,
"cost_for_plan": 13.815,
@@ -5024,12 +5550,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 243,
"cost_for_plan": 64.431,
@@ -5046,12 +5579,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 2187,
"cost_for_plan": 503.85,
@@ -5069,12 +5609,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 2187,
"cost_for_plan": 503.85,
@@ -5089,12 +5636,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 243,
"cost_for_plan": 64.431,
@@ -5107,12 +5661,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 243,
"cost_for_plan": 64.431,
@@ -5127,12 +5688,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 81,
"cost_for_plan": 24.626,
@@ -5144,12 +5712,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 729,
"cost_for_plan": 172.44,
@@ -5166,12 +5741,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 2187,
"cost_for_plan": 611.85,
@@ -5189,12 +5771,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 6561,
"cost_for_plan": 1486.7,
@@ -5209,12 +5798,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 243,
"cost_for_plan": 75.231,
@@ -5231,12 +5827,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 2187,
"cost_for_plan": 514.65,
@@ -5254,12 +5857,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 2187,
"cost_for_plan": 514.65,
@@ -5274,12 +5884,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 729,
"cost_for_plan": 172.44,
@@ -5296,12 +5913,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 27,
"cost_for_plan": 10.021,
@@ -5314,12 +5938,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 27,
"cost_for_plan": 10.021,
@@ -5332,12 +5963,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 9,
"cost_for_plan": 6.4103,
@@ -5350,12 +5988,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 27,
"cost_for_plan": 10.021,
@@ -5370,12 +6015,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 3,
"cost_for_plan": 2.6051,
@@ -5388,12 +6040,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 9,
"cost_for_plan": 3.8154,
@@ -5406,12 +6065,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 9,
"cost_for_plan": 3.8154,
@@ -5424,12 +6090,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 3,
"cost_for_plan": 2.6051,
@@ -5442,12 +6115,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 9,
"cost_for_plan": 3.8154,
@@ -5467,12 +6147,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 162.42,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 162.42,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
{
"table": "t_inner_3"
@@ -5480,12 +6167,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 489.74,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 489.74,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
}
]
},
@@ -5498,12 +6192,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 18.046,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 18.046,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
{
"table": "t_inner_2"
@@ -5511,17 +6212,34 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 54.415,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 54.415,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
}
]
}
]
},
+ {
+ "best_join_order": [
+ "t_outer_1",
+ "t_inner_1",
+ "t_inner_2",
+ "t_outer_2",
+ "t_inner_4",
+ "t_inner_3"
+ ]
+ },
{
"attaching_conditions_to_tables": {
"original_condition": "t_inner_1.a = t_outer_1.a and t_inner_3.a = t_outer_2.a",
@@ -5796,12 +6514,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 3,
"cost_for_plan": 2.6051,
@@ -5812,15 +6537,23 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 27,
- "cost_for_plan": 10.021
+ "cost_for_plan": 10.021,
+ "estimated_join_cardinality": 27
}
]
},
@@ -5830,12 +6563,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 9,
"cost_for_plan": 3.8154,
@@ -5851,12 +6591,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 3,
"cost_for_plan": 2.6051,
@@ -5867,15 +6614,23 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 27,
- "cost_for_plan": 10.021
+ "cost_for_plan": 10.021,
+ "estimated_join_cardinality": 27
}
]
},
@@ -5885,12 +6640,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 9,
"cost_for_plan": 3.8154,
@@ -5909,12 +6671,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 3,
"cost_for_plan": 2.6051,
@@ -5926,12 +6695,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 9,
"cost_for_plan": 6.4103,
@@ -5943,12 +6719,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 81,
"cost_for_plan": 24.626,
@@ -5979,12 +6762,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 27,
"cost_for_plan": 15.541,
@@ -6001,12 +6791,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 81,
"cost_for_plan": 33.746,
@@ -6024,12 +6821,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 729,
"cost_for_plan": 181.56,
@@ -6052,7 +6856,8 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
{
"chosen_strategy": "SJ-Materialize"
}
- ]
+ ],
+ "estimated_join_cardinality": 27
}
]
},
@@ -6067,12 +6872,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 243,
"cost_for_plan": 66.156,
@@ -6087,12 +6899,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 9,
"cost_for_plan": 11.931,
@@ -6109,12 +6928,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 81,
"cost_for_plan": 30.146,
@@ -6132,12 +6958,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 81,
"cost_for_plan": 30.146,
@@ -6152,12 +6985,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 27,
"cost_for_plan": 15.541,
@@ -6172,12 +7012,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 81,
"cost_for_plan": 24.626,
@@ -6190,12 +7037,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 27,
"cost_for_plan": 13.815,
@@ -6208,12 +7062,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 81,
"cost_for_plan": 24.626,
@@ -6228,12 +7089,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 27,
"cost_for_plan": 10.021,
@@ -6246,12 +7114,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 27,
"cost_for_plan": 10.021,
@@ -6264,12 +7139,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 9,
"cost_for_plan": 6.4103,
@@ -6282,12 +7164,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": true,
+ "filter_used": false
+ }
},
"rows_for_plan": 27,
"cost_for_plan": 10.021,
@@ -6302,12 +7191,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 3,
"cost_for_plan": 2.6051,
@@ -6320,12 +7216,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 9,
"cost_for_plan": 3.8154,
@@ -6338,12 +7241,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 9,
"cost_for_plan": 3.8154,
@@ -6356,12 +7266,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 3,
"cost_for_plan": 2.6051,
@@ -6374,12 +7291,19 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 9,
"cost": 2.0154,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 9,
+ "cost": 2.0154,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 9,
"cost_for_plan": 3.8154,
@@ -6414,6 +7338,14 @@ t_outer_2.a in (select t_inner_3.a from t2 t_inner_3, t1 t_inner_4) {
}
]
},
+ {
+ "best_join_order": [
+ "t_outer_1",
+ "<subquery2>",
+ "t_outer_2",
+ "<subquery3>"
+ ]
+ },
{
"condition_on_constant_tables": "1"
},
@@ -7052,12 +7984,20 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.considered_execution_plans'))
[
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 5.9375,
"cost": 2.8296,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method":
+ {
+ "type": "scan",
+ "records": 5.9375,
+ "cost": 2.8296,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 5.9375,
"cost_for_plan": 4.0171,
@@ -7076,15 +8016,24 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.considered_execution_plans'))
[
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 804.69,
"cost": 256.85,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method":
+ {
+ "type": "scan",
+ "records": 804.69,
+ "cost": 256.85,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 4777.8,
- "cost_for_plan": 1216.4
+ "cost_for_plan": 1216.4,
+ "estimated_join_cardinality": 4777.8
}
]
},
@@ -7100,12 +8049,20 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.considered_execution_plans'))
[
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 804.69,
"cost": 43.26,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method":
+ {
+ "type": "scan",
+ "records": 804.69,
+ "cost": 43.26,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 804.69,
"cost_for_plan": 204.2,
@@ -7136,12 +8093,20 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.considered_execution_plans'))
[
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 10,
"cost": 2.0171,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method":
+ {
+ "type": "scan",
+ "records": 10,
+ "cost": 2.0171,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 10,
"cost_for_plan": 4.0171,
@@ -7170,16 +8135,25 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.considered_execution_plans'))
},
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 804.69,
"cost": 43.26,
"chosen": false
}
- ]
+ ],
+ "chosen_access_method":
+ {
+ "type": "ref",
+ "records": 1,
+ "cost": 20,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 10,
"cost_for_plan": 26.017,
- "selectivity": 0.8047
+ "selectivity": 0.8047,
+ "estimated_join_cardinality": 8.0469
}
]
},
@@ -7195,12 +8169,20 @@ JSON_DETAILED(JSON_EXTRACT(trace, '$**.considered_execution_plans'))
[
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 804.69,
"cost": 43.26,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method":
+ {
+ "type": "scan",
+ "records": 804.69,
+ "cost": 43.26,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 804.69,
"cost_for_plan": 204.2,
diff --git a/mysql-test/main/opt_trace_index_merge.result b/mysql-test/main/opt_trace_index_merge.result
index 5697e3a771a..7f1bd5163f3 100644
--- a/mysql-test/main/opt_trace_index_merge.result
+++ b/mysql-test/main/opt_trace_index_merge.result
@@ -207,18 +207,29 @@ explain select * from t1 where a=1 or b=1 {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "range",
+ "access_type": "index_merge",
"resulting_rows": 2,
"cost": 4.1484,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "index_merge",
+ "records": 2,
+ "cost": 4.1484,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 2,
- "cost_for_plan": 4.5484
+ "cost_for_plan": 4.5484,
+ "estimated_join_cardinality": 2
}
]
},
+ {
+ "best_join_order": ["t1"]
+ },
{
"attaching_conditions_to_tables": {
"original_condition": "t1.a = 1 or t1.b = 1",
diff --git a/mysql-test/main/opt_trace_index_merge_innodb.result b/mysql-test/main/opt_trace_index_merge_innodb.result
index 23a500b0720..afcf0b03dae 100644
--- a/mysql-test/main/opt_trace_index_merge_innodb.result
+++ b/mysql-test/main/opt_trace_index_merge_innodb.result
@@ -208,13 +208,24 @@ explain select * from t1 where pk1 != 0 and key1 = 1 {
"chosen": false,
"cause": "cost"
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "ref",
+ "records": 1,
+ "cost": 2,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 1,
- "cost_for_plan": 2.2
+ "cost_for_plan": 2.2,
+ "estimated_join_cardinality": 1
}
]
},
+ {
+ "best_join_order": ["t1"]
+ },
{
"attaching_conditions_to_tables": {
"original_condition": "t1.key1 = 1 and t1.pk1 <> 0",
diff --git a/mysql-test/main/opt_trace_security.result b/mysql-test/main/opt_trace_security.result
index c8112fd5f6c..2b9ecfd46a3 100644
--- a/mysql-test/main/opt_trace_security.result
+++ b/mysql-test/main/opt_trace_security.result
@@ -93,18 +93,29 @@ select * from db1.t1 {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 3,
- "cost_for_plan": 2.6051
+ "cost_for_plan": 2.6051,
+ "estimated_join_cardinality": 3
}
]
},
+ {
+ "best_join_order": ["t1"]
+ },
{
"attaching_conditions_to_tables": {
"original_condition": null,
@@ -206,18 +217,29 @@ select * from db1.v1 {
"best_access_path": {
"considered_access_paths": [
{
- "access_type": "scan",
+ "access_type": "ALL",
"resulting_rows": 3,
"cost": 2.0051,
"chosen": true
}
- ]
+ ],
+ "chosen_access_method": {
+ "type": "scan",
+ "records": 3,
+ "cost": 2.0051,
+ "uses_join_buffering": false,
+ "filter_used": false
+ }
},
"rows_for_plan": 3,
- "cost_for_plan": 2.6051
+ "cost_for_plan": 2.6051,
+ "estimated_join_cardinality": 3
}
]
},
+ {
+ "best_join_order": ["t1"]
+ },
{
"attaching_conditions_to_tables": {
"original_condition": null,
diff --git a/sql/opt_trace.cc b/sql/opt_trace.cc
index befc7934a3a..60855729eea 100644
--- a/sql/opt_trace.cc
+++ b/sql/opt_trace.cc
@@ -630,6 +630,46 @@ void add_table_scan_values_to_trace(THD *thd, JOIN_TAB *tab)
table_rec.add("rows", tab->found_records)
.add("cost", tab->read_time);
}
+
+/*
+ Print the join order of all the tables for a select.
+
+ For example:
+
+ select * from ot1
+ where ot1.a IN (select it1.a from it1, it2 where it1.b=it2.a);
+
+ So this function would print
+ ot1, <subquery2> ----> For select #1
+ it1,it2 ----> For select #2
+*/
+
+void print_final_join_order(JOIN *join)
+{
+ Json_writer_object join_order(join->thd);
+ Json_writer_array best_order(join->thd, "best_join_order");
+ JOIN_TAB *j;
+ uint i;
+ for (j= join->join_tab,i=0 ; i < join->top_join_tab_count;
+ i++, j++)
+ best_order.add_table_name(j);
+}
+
+
+void print_best_access_for_table(THD *thd, POSITION *pos,
+ enum join_type type)
+{
+ Json_writer_object trace_best_access(thd, "chosen_access_method");
+ trace_best_access.add("type", type == JT_ALL ? "scan" :
+ join_type_str[type]);
+ trace_best_access.add("records", pos->records_read);
+ trace_best_access.add("cost", pos->read_time);
+ trace_best_access.add("uses_join_buffering", pos->use_join_buffer);
+ trace_best_access.add("filter_used",
+ pos->range_rowid_filter_info != NULL);
+}
+
+
/*
Introduce enum_query_type flags parameter, maybe also allow
EXPLAIN also use this function.
diff --git a/sql/opt_trace.h b/sql/opt_trace.h
index 52318bc6b7f..6fe179d79d8 100644
--- a/sql/opt_trace.h
+++ b/sql/opt_trace.h
@@ -105,6 +105,9 @@ void opt_trace_print_expanded_query(THD *thd, SELECT_LEX *select_lex,
Json_writer_object *trace_object);
void add_table_scan_values_to_trace(THD *thd, JOIN_TAB *tab);
+void print_final_join_order(JOIN *join);
+void print_best_access_for_table(THD *thd, POSITION *pos,
+ enum join_type type);
/*
Security related (need to add a proper comment here)
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 150e8008096..8e95490e8ce 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -7203,6 +7203,7 @@ best_access_path(JOIN *join,
SplM_plan_info *spl_plan= 0;
Range_rowid_filter_cost_info *filter= 0;
const char* cause= NULL;
+ enum join_type best_type= JT_UNKNOWN, type= JT_UNKNOWN;
disable_jbuf= disable_jbuf || idx == join->const_tables;
@@ -7342,7 +7343,8 @@ best_access_path(JOIN *join,
*/
tmp= prev_record_reads(join->positions, idx, found_ref);
records= 1.0;
- trace_access_idx.add("access_type", "fulltext")
+ type= JT_FT;
+ trace_access_idx.add("access_type", join_type_str[type])
.add("index", keyinfo->name);
}
else
@@ -7365,14 +7367,16 @@ best_access_path(JOIN *join,
(!(key_flags & HA_NULL_PART_KEY) || // (2)
all_key_parts == notnull_part)) // (3)
{
- trace_access_idx.add("access_type", "eq_ref")
+ type= JT_EQ_REF;
+ trace_access_idx.add("access_type", join_type_str[type])
.add("index", keyinfo->name);
tmp = prev_record_reads(join->positions, idx, found_ref);
records=1.0;
}
else
{
- trace_access_idx.add("access_type", "ref")
+ type= JT_REF;
+ trace_access_idx.add("access_type", join_type_str[type])
.add("index", keyinfo->name);
if (!found_ref)
{ /* We found a const key */
@@ -7467,8 +7471,8 @@ best_access_path(JOIN *join,
}
else
{
- trace_access_idx.add("access_type",
- ref_or_null_part ? "ref_or_null" : "ref")
+ type = ref_or_null_part ? JT_REF_OR_NULL : JT_REF;
+ trace_access_idx.add("access_type", join_type_str[type])
.add("index", keyinfo->name);
/*
Use as much key-parts as possible and a uniq key is better
@@ -7683,6 +7687,7 @@ best_access_path(JOIN *join,
best_max_key_part= max_key_part;
best_ref_depends_map= found_ref;
best_filter= filter;
+ best_type= type;
}
else
{
@@ -7736,6 +7741,7 @@ best_access_path(JOIN *join,
best_ref_depends_map= 0;
best_uses_jbuf= TRUE;
best_filter= 0;
+ best_type= JT_HASH;
trace_access_hash.add("type", "hash");
trace_access_hash.add("index", "hj-key");
trace_access_hash.add("cost", rnd_records);
@@ -7799,10 +7805,6 @@ best_access_path(JOIN *join,
filter= 0;
if (s->quick)
{
- trace_access_scan.add("access_type", "range");
- /*
- should have some info about all the different QUICK_SELECT
- */
/*
For each record we:
- read record range through 'quick'
@@ -7828,23 +7830,29 @@ best_access_path(JOIN *join,
{
tmp-= filter->get_adjusted_gain(rows);
DBUG_ASSERT(tmp >= 0);
- }
+ }
+ type= JT_RANGE;
}
else
{
+ type= JT_INDEX_MERGE;
best_filter= 0;
}
-
loose_scan_opt.check_range_access(join, idx, s->quick);
}
else
{
- trace_access_scan.add("access_type", "scan");
/* Estimate cost of reading table. */
if (s->table->force_index && !best_key) // index scan
+ {
+ type= JT_NEXT;
tmp= s->table->file->read_time(s->ref.key, 1, s->records);
+ }
else // table scan
+ {
tmp= s->scan_time();
+ type= JT_ALL;
+ }
if ((s->table->map & join->outer_join) || disable_jbuf) // Can't use join cache
{
@@ -7874,6 +7882,7 @@ best_access_path(JOIN *join,
}
}
+ trace_access_scan.add("access_type", join_type_str[type]);
/* Splitting technique cannot be used with join cache */
if (s->table->is_splittable())
tmp+= s->table->get_materialization_cost();
@@ -7913,6 +7922,7 @@ best_access_path(JOIN *join,
best_uses_jbuf= MY_TEST(!disable_jbuf && !((s->table->map &
join->outer_join)));
spl_plan= 0;
+ best_type= type;
}
trace_access_scan.add("chosen", best_key == NULL);
}
@@ -7944,6 +7954,11 @@ best_access_path(JOIN *join,
trace_access_scan.add("use_tmp_table", true);
join->sort_by_table= (TABLE*) 1; // Must use temporary table
}
+ trace_access_scan.end();
+ trace_paths.end();
+
+ if (unlikely(thd->trace_started()))
+ print_best_access_for_table(thd, pos, best_type);
DBUG_VOID_RETURN;
}
@@ -9483,6 +9498,8 @@ best_extension_by_limited_search(JOIN *join,
Hence it may be wrong.
*/
current_read_time= COST_ADD(current_read_time, current_record_count);
+ trace_one_table.add("estimated_join_cardinality",
+ partial_join_cardinality);
if (current_read_time < join->best_read)
{
memcpy((uchar*) join->best_positions, (uchar*) join->positions,
@@ -10304,6 +10321,9 @@ bool JOIN::get_best_combination()
top_join_tab_count= (uint)(join_tab_ranges.head()->end -
join_tab_ranges.head()->start);
+ if (unlikely(thd->trace_started()))
+ print_final_join_order(this);
+
update_depend_map(this);
DBUG_RETURN(0);
}
[View Less]
1
0

[Commits] 992ee35: MDEV-15777 Use inferred IS NOT NULL predicates in the range optimizer
by IgorBabaev 01 Sep '19
by IgorBabaev 01 Sep '19
01 Sep '19
revision-id: 992ee352e8779e10e0a2ad9b43654ba0ea2e6e88 (mariadb-10.3.12-226-g992ee35)
parent(s): 7060b0320d1479bb9476e0cbd4acc584e059e1ff
author: Igor Babaev
committer: Igor Babaev
timestamp: 2019-08-31 23:09:30 -0700
message:
MDEV-15777 Use inferred IS NOT NULL predicates in the range optimizer
This patch introduces the optimization that allows range optimizer to
consider index range scans that are built employing NOT NULL predicates
inferred from WHERE conditions and ON expressions.
The …
[View More]patch adds a new optimizer switch not_null_range_scan.
---
mysql-test/main/mysqld--help.result | 3 +-
mysql-test/main/range.result | 285 +++++++++++++++++++++
mysql-test/main/range.test | 187 ++++++++++++++
mysql-test/main/range_mrr_icp.result | 285 +++++++++++++++++++++
.../suite/sys_vars/r/optimizer_switch_basic.result | 36 +--
.../sys_vars/r/sysvars_server_embedded.result | 8 +-
.../sys_vars/r/sysvars_server_notembedded.result | 8 +-
sql/item.cc | 10 +
sql/item.h | 43 ++++
sql/item_cmpfunc.cc | 161 +++++++++++-
sql/item_cmpfunc.h | 11 +
sql/item_func.cc | 19 ++
sql/item_func.h | 22 ++
sql/item_row.cc | 19 ++
sql/item_row.h | 1 +
sql/opt_range.cc | 10 +
sql/sql_priv.h | 1 +
sql/sql_select.cc | 285 +++++++++++++++++++++
sql/sql_select.h | 3 +-
sql/sys_vars.cc | 1 +
sql/table.cc | 2 +
sql/table.h | 7 +
.../mysql-test/tokudb/r/ext_key_1_innodb.result | 2 +-
.../mysql-test/tokudb/r/ext_key_1_tokudb.result | 2 +-
.../mysql-test/tokudb/r/ext_key_2_innodb.result | 2 +-
.../mysql-test/tokudb/r/ext_key_2_tokudb.result | 2 +-
26 files changed, 1382 insertions(+), 33 deletions(-)
diff --git a/mysql-test/main/mysqld--help.result b/mysql-test/main/mysqld--help.result
index 1c7e9cd..19b4319 100644
--- a/mysql-test/main/mysqld--help.result
+++ b/mysql-test/main/mysqld--help.result
@@ -678,7 +678,8 @@ The following specify which files/extra groups are read (specified before remain
join_cache_hashed, join_cache_bka,
optimize_join_buffer_size, table_elimination,
extended_keys, exists_to_in, orderby_uses_equalities,
- condition_pushdown_for_derived, split_materialized
+ condition_pushdown_for_derived, split_materialized,
+ not_null_range_scan
--optimizer-use-condition-selectivity=#
Controls selectivity of which conditions the optimizer
takes into account to calculate cardinality of a partial
diff --git a/mysql-test/main/range.result b/mysql-test/main/range.result
index 32e0cf2..807ca16 100644
--- a/mysql-test/main/range.result
+++ b/mysql-test/main/range.result
@@ -3024,3 +3024,288 @@ drop table t1;
#
# End of 10.2 tests
#
+#
+# MDEV-15777: Use inferred IS NOT NULL predicates in the range optimizer
+#
+set @save_optimizer_switch= @@optimizer_switch;
+set @@optimizer_switch='not_null_range_scan=on';
+create table ten(a int);
+insert into ten values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table one_k(a int);
+insert into one_k select A.a + B.a* 10 + C.a * 100 from ten A, ten B, ten C;
+create table t1 (
+id int NOT NULL,
+subset_id int DEFAULT NULL,
+PRIMARY KEY (id),
+KEY t1_subset_id (subset_id));
+create table t2 (
+id int,
+col int NOT NULL,
+key (id)
+);
+insert into t1 select a,a from one_k limit 5;
+insert into t1 select a+5,NULL from one_k limit 995;
+insert into t2 select a,a from one_k;
+analyze table t1,t2;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+test.t2 analyze status Table is already up to date
+# expected for t1: range access and rows = 4 (not 1000)
+explain SELECT * FROM t1,t2 WHERE t1.subset_id=t2.id;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range t1_subset_id t1_subset_id 5 NULL 4 Using index condition
+1 SIMPLE t2 ref id id 5 test.t1.subset_id 1
+SELECT * FROM t1,t2 WHERE t1.subset_id=t2.id;
+id subset_id id col
+0 0 0 0
+1 1 1 1
+2 2 2 2
+3 3 3 3
+4 4 4 4
+# with a subquery
+# expected the same plan as above
+explain SELECT * FROM t1 WHERE t1.subset_id IN (SELECT t2.id FROM t2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 range t1_subset_id t1_subset_id 5 NULL 4 Using index condition
+1 PRIMARY t2 ref id id 5 test.t1.subset_id 1 Using index; FirstMatch(t1)
+SELECT * FROM t1 WHERE t1.subset_id IN (SELECT t2.id FROM t2);
+id subset_id
+0 0
+1 1
+2 2
+3 3
+4 4
+# non-mergable subquery
+# expected for t1: range access and rows = 4 (not 1000)
+explain SELECT * FROM t1
+WHERE t1.subset_id IN (SELECT max(t2.id) FROM t2 group by t2.col);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 range t1_subset_id t1_subset_id 5 NULL 4 Using index condition
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 test.t1.subset_id 1
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 1000 Using temporary
+SELECT * FROM t1
+WHERE t1.subset_id IN (SELECT max(t2.id) FROM t2 group by t2.col);
+id subset_id
+0 0
+1 1
+2 2
+3 3
+4 4
+create view v1 as SELECT t2.id FROM t2;
+create view v2 as SELECT t2.id FROM t2 group by t2.col;
+# with mergeable view
+# expected for t1: range access and rows = 4 (not 1000)
+explain SELECT * FROM t1, v1 where t1.subset_id=v1.id;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range t1_subset_id t1_subset_id 5 NULL 4 Using index condition
+1 SIMPLE t2 ref id id 5 test.t1.subset_id 1 Using index
+SELECT * FROM t1, v1 where t1.subset_id=v1.id;
+id subset_id id
+0 0 0
+1 1 1
+2 2 2
+3 3 3
+4 4 4
+# with non-mergeable view
+# expected for t1: range access and rows = 4 (not 1000)
+explain SELECT * FROM t1, v2 where t1.subset_id=v2.id;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 range t1_subset_id t1_subset_id 5 NULL 4 Using index condition
+1 PRIMARY <derived2> ref key0 key0 5 test.t1.subset_id 10
+2 DERIVED t2 ALL NULL NULL NULL NULL 1000 Using temporary; Using filesort
+SELECT * FROM t1, v2 where t1.subset_id=v2.id;
+id subset_id id
+0 0 0
+1 1 1
+2 2 2
+3 3 3
+4 4 4
+# expected for t2 and for t1: range access
+explain SELECT * FROM t2 LEFT JOIN t1 ON t1.subset_id != 5 WHERE t2.id in (0,2,4);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range id id 5 NULL 3 Using index condition
+1 SIMPLE t1 range t1_subset_id t1_subset_id 5 NULL 4 Using where; Using join buffer (flat, BNL join)
+SELECT * FROM t2 LEFT JOIN t1 ON t1.subset_id != 5 WHERE t2.id in (0,2,4);
+id col id subset_id
+0 0 0 0
+2 2 0 0
+4 4 0 0
+0 0 1 1
+2 2 1 1
+4 4 1 1
+0 0 2 2
+2 2 2 2
+4 4 2 2
+0 0 3 3
+2 2 3 3
+4 4 3 3
+0 0 4 4
+2 2 4 4
+4 4 4 4
+# no range access expected for t1
+explain SELECT * FROM t1 LEFT JOIN t2 ON t1.subset_id=t2.id LIMIT 10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 1000
+1 SIMPLE t2 ref id id 5 test.t1.subset_id 1 Using where
+SELECT * FROM t1 LEFT JOIN t2 ON t1.subset_id=t2.id LIMIT 10;
+id subset_id id col
+0 0 0 0
+1 1 1 1
+2 2 2 2
+3 3 3 3
+4 4 4 4
+5 NULL NULL NULL
+6 NULL NULL NULL
+7 NULL NULL NULL
+8 NULL NULL NULL
+9 NULL NULL NULL
+# expected for t1: range access
+explain SELECT * FROM ten LEFT JOIN (t1,t2) ON ten.a=t2.col AND t1.subset_id=t2.id;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE ten ALL NULL NULL NULL NULL 10
+1 SIMPLE t1 range t1_subset_id t1_subset_id 5 NULL 4 Using where
+1 SIMPLE t2 ref id id 5 test.t1.subset_id 1 Using where
+SELECT * FROM ten LEFT JOIN (t1,t2) ON ten.a=t2.col AND t1.subset_id=t2.id;
+a id subset_id id col
+0 0 0 0 0
+1 1 1 1 1
+2 2 2 2 2
+3 3 3 3 3
+4 4 4 4 4
+5 NULL NULL NULL NULL
+6 NULL NULL NULL NULL
+7 NULL NULL NULL NULL
+8 NULL NULL NULL NULL
+9 NULL NULL NULL NULL
+# no range access expected for t1
+explain SELECT * FROM t1 LEFT JOIN (t2,ten) ON ten.a=t2.col AND t1.subset_id=t2.id
+LIMIT 10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 1000
+1 SIMPLE t2 ref id id 5 test.t1.subset_id 1 Using where
+1 SIMPLE ten ALL NULL NULL NULL NULL 10 Using where
+SELECT * FROM t1 LEFT JOIN (t2,ten) ON ten.a=t2.col AND t1.subset_id=t2.id
+LIMIT 10;
+id subset_id id col a
+0 0 0 0 0
+1 1 1 1 1
+2 2 2 2 2
+3 3 3 3 3
+4 4 4 4 4
+5 NULL NULL NULL NULL
+6 NULL NULL NULL NULL
+7 NULL NULL NULL NULL
+8 NULL NULL NULL NULL
+9 NULL NULL NULL NULL
+drop index id on t2;
+# expected for t1: range access
+explain SELECT * FROM t1,t2 WHERE t1.subset_id=t2.id;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range t1_subset_id t1_subset_id 5 NULL 4 Using index condition
+1 SIMPLE t2 ALL NULL NULL NULL NULL 1000 Using where; Using join buffer (flat, BNL join)
+SELECT * FROM t1,t2 WHERE t1.subset_id=t2.id;
+id subset_id id col
+0 0 0 0
+1 1 1 1
+2 2 2 2
+3 3 3 3
+4 4 4 4
+# expected impossible where after reading const tables
+explain SELECT * FROM t1,t2 WHERE t1.subset_id > t2.id AND t1.subset_id IS NULL;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+SELECT * FROM t1,t2 WHERE t1.subset_id > t2.id AND t1.subset_id IS NULL;
+id subset_id id col
+# expected impossible where after reading const tables
+explain SELECT * FROM t1,t2 WHERE t1.subset_id > t2.id AND t2.id IS NULL;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+SELECT * FROM t1,t2 WHERE t1.subset_id > t2.id AND t2.id IS NULL;
+id subset_id id col
+drop index t1_subset_id on t1;
+alter table t1 add column m int not null default 0;
+alter table t1 add index idx(m,subset_id);
+alter table t2 add index (id);
+update t1 set m = id mod 2;
+analyze table t1,t2;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+test.t2 analyze status Table is already up to date
+# expected for t1: range access by idx (keylen=9)
+explain SELECT * FROM t1,t2 WHERE t1.subset_id=t2.id and t1.m=0 ;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx idx 9 NULL 4 Using index condition
+1 SIMPLE t2 ref id id 5 test.t1.subset_id 1
+SELECT * FROM t1,t2 WHERE t1.subset_id=t2.id and t1.m=0 ;
+id subset_id m id col
+0 0 0 0 0
+2 2 0 2 2
+4 4 0 4 4
+drop view v1,v2;
+drop table t1,t2;
+create table t1 (
+id int NOT NULL,
+subset_id int DEFAULT NULL,
+KEY key1(id, subset_id),
+KEY t1_subset_id (subset_id)
+);
+create table t2 (
+id int NOT NULL,
+col int NOT NULL,
+key (id)
+);
+insert into t1 select 1,a from one_k limit 5;
+insert into t1 select 1,NULL from one_k limit 495;
+insert into t2 select a,a from one_k;
+analyze table t1,t2;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+test.t2 analyze status Table is already up to date
+# expected for t1 :range access by index key1
+# rows 4 instead of 500
+explain SELECT * FROM t1,t2 WHERE t1.id>=1 and t1.subset_id=t2.id;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range key1,t1_subset_id key1 9 NULL 4 Using where; Using index
+1 SIMPLE t2 ref id id 4 test.t1.subset_id 1
+SELECT * FROM t1,t2 WHERE t1.id>=1 and t1.subset_id=t2.id;
+id subset_id id col
+1 0 0 0
+1 1 1 1
+1 2 2 2
+1 3 3 3
+1 4 4 4
+drop table t1,t2;
+create table t1 (id int unsigned,col int, KEY key1(id));
+create table t2 (id int unsigned,col int DEFAULT NULL,key (id));
+insert into t1 select a,2 from one_k limit 50;
+insert into t1 select NULL,2 from one_k limit 450;
+insert into t2 select a,a from one_k;
+insert into t2 select a,a from one_k;
+analyze table t1,t2;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+test.t2 analyze status OK
+# using key1 for range access on t1 and also using index for sorting,
+# no filesort, rows should be 75 not 500
+explain SELECT * FROM t1,t2 WHERE t1.id=t2.id AND t1.col=2 ORDER BY t2.id LIMIT 10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range key1 key1 5 NULL 75 Using index condition; Using where
+1 SIMPLE t2 ref id id 5 test.t1.id 2
+SELECT * FROM t1,t2 WHERE t1.id=t2.id AND t1.col=2 ORDER BY t2.id LIMIT 10;
+id col id col
+0 2 0 0
+0 2 0 0
+1 2 1 1
+1 2 1 1
+2 2 2 2
+2 2 2 2
+3 2 3 3
+3 2 3 3
+4 2 4 4
+4 2 4 4
+drop table t1,t2;
+drop table ten,one_k;
+set @@optimizer_switch= @save_optimizer_switch;
+#
+# End of 10.3 tests
+#
diff --git a/mysql-test/main/range.test b/mysql-test/main/range.test
index bd2299b..12799d9 100644
--- a/mysql-test/main/range.test
+++ b/mysql-test/main/range.test
@@ -2053,3 +2053,190 @@ drop table t1;
--echo #
--echo # End of 10.2 tests
--echo #
+
+--echo #
+--echo # MDEV-15777: Use inferred IS NOT NULL predicates in the range optimizer
+--echo #
+
+set @save_optimizer_switch= @@optimizer_switch;
+set @@optimizer_switch='not_null_range_scan=on';
+create table ten(a int);
+insert into ten values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+
+create table one_k(a int);
+insert into one_k select A.a + B.a* 10 + C.a * 100 from ten A, ten B, ten C;
+
+create table t1 (
+ id int NOT NULL,
+ subset_id int DEFAULT NULL,
+ PRIMARY KEY (id),
+ KEY t1_subset_id (subset_id));
+
+create table t2 (
+ id int,
+ col int NOT NULL,
+ key (id)
+);
+
+insert into t1 select a,a from one_k limit 5;
+insert into t1 select a+5,NULL from one_k limit 995;
+insert into t2 select a,a from one_k;
+
+analyze table t1,t2;
+
+let $q=
+SELECT * FROM t1,t2 WHERE t1.subset_id=t2.id;
+--echo # expected for t1: range access and rows = 4 (not 1000)
+eval explain $q;
+eval $q;
+
+let $q=
+SELECT * FROM t1 WHERE t1.subset_id IN (SELECT t2.id FROM t2);
+--echo # with a subquery
+--echo # expected the same plan as above
+eval explain $q;
+eval $q;
+
+let $q=
+SELECT * FROM t1
+ WHERE t1.subset_id IN (SELECT max(t2.id) FROM t2 group by t2.col);
+--echo # non-mergable subquery
+--echo # expected for t1: range access and rows = 4 (not 1000)
+eval explain $q;
+eval $q;
+
+create view v1 as SELECT t2.id FROM t2;
+create view v2 as SELECT t2.id FROM t2 group by t2.col;
+
+let $q=
+SELECT * FROM t1, v1 where t1.subset_id=v1.id;
+--echo # with mergeable view
+--echo # expected for t1: range access and rows = 4 (not 1000)
+eval explain $q;
+eval $q;
+
+let $q= SELECT * FROM t1, v2 where t1.subset_id=v2.id;
+--echo # with non-mergeable view
+--echo # expected for t1: range access and rows = 4 (not 1000)
+eval explain $q;
+eval $q;
+
+let $q=
+SELECT * FROM t2 LEFT JOIN t1 ON t1.subset_id != 5 WHERE t2.id in (0,2,4);
+--echo # expected for t2 and for t1: range access
+eval explain $q;
+eval $q;
+
+let $q=
+SELECT * FROM t1 LEFT JOIN t2 ON t1.subset_id=t2.id LIMIT 10;
+--echo # no range access expected for t1
+eval explain $q;
+eval $q;
+
+let $q=
+SELECT * FROM ten LEFT JOIN (t1,t2) ON ten.a=t2.col AND t1.subset_id=t2.id;
+--echo # expected for t1: range access
+eval explain $q;
+eval $q;
+
+let $q=
+SELECT * FROM t1 LEFT JOIN (t2,ten) ON ten.a=t2.col AND t1.subset_id=t2.id
+LIMIT 10;
+--echo # no range access expected for t1
+eval explain $q;
+eval $q;
+
+drop index id on t2;
+
+let $q=
+SELECT * FROM t1,t2 WHERE t1.subset_id=t2.id;
+--echo # expected for t1: range access
+eval explain $q;
+eval $q;
+
+let $q=
+SELECT * FROM t1,t2 WHERE t1.subset_id > t2.id AND t1.subset_id IS NULL;
+--echo # expected impossible where after reading const tables
+eval explain $q;
+eval $q;
+
+let $q=
+SELECT * FROM t1,t2 WHERE t1.subset_id > t2.id AND t2.id IS NULL;
+--echo # expected impossible where after reading const tables
+eval explain $q;
+eval $q;
+
+drop index t1_subset_id on t1;
+alter table t1 add column m int not null default 0;
+alter table t1 add index idx(m,subset_id);
+alter table t2 add index (id);
+update t1 set m = id mod 2;
+analyze table t1,t2;
+
+let $q=
+SELECT * FROM t1,t2 WHERE t1.subset_id=t2.id and t1.m=0 ;
+--echo # expected for t1: range access by idx (keylen=9)
+eval explain $q;
+eval $q;
+
+
+drop view v1,v2;
+drop table t1,t2;
+
+create table t1 (
+ id int NOT NULL,
+ subset_id int DEFAULT NULL,
+ KEY key1(id, subset_id),
+ KEY t1_subset_id (subset_id)
+);
+
+create table t2 (
+ id int NOT NULL,
+ col int NOT NULL,
+ key (id)
+);
+
+insert into t1 select 1,a from one_k limit 5;
+insert into t1 select 1,NULL from one_k limit 495;
+insert into t2 select a,a from one_k;
+
+analyze table t1,t2;
+
+let $q=
+SELECT * FROM t1,t2 WHERE t1.id>=1 and t1.subset_id=t2.id;
+--echo # expected for t1 :range access by index key1
+--echo # rows 4 instead of 500
+eval explain $q;
+eval $q;
+
+drop table t1,t2;
+
+create table t1 (id int unsigned,col int, KEY key1(id));
+create table t2 (id int unsigned,col int DEFAULT NULL,key (id));
+insert into t1 select a,2 from one_k limit 50;
+insert into t1 select NULL,2 from one_k limit 450;
+insert into t2 select a,a from one_k;
+insert into t2 select a,a from one_k;
+
+analyze table t1,t2;
+
+let $q=
+SELECT * FROM t1,t2 WHERE t1.id=t2.id AND t1.col=2 ORDER BY t2.id LIMIT 10;
+--echo # using key1 for range access on t1 and also using index for sorting,
+--echo # no filesort, rows should be 75 not 500
+eval explain $q;
+eval $q;
+
+drop table t1,t2;
+
+drop table ten,one_k;
+set @@optimizer_switch= @save_optimizer_switch;
+
+--echo #
+--echo # End of 10.3 tests
+--echo #
+
+set global innodb_stats_persistent= @innodb_stats_persistent_save;
+set global innodb_stats_persistent_sample_pages=
+@innodb_stats_persistent_sample_pages_save;
+set optimizer_switch=@mrr_icp_extra_tmp;
diff --git a/mysql-test/main/range_mrr_icp.result b/mysql-test/main/range_mrr_icp.result
index 6b5bf33..d484d51 100644
--- a/mysql-test/main/range_mrr_icp.result
+++ b/mysql-test/main/range_mrr_icp.result
@@ -3036,4 +3036,289 @@ drop table t1;
#
# End of 10.2 tests
#
+#
+# MDEV-15777: Use inferred IS NOT NULL predicates in the range optimizer
+#
+set @save_optimizer_switch= @@optimizer_switch;
+set @@optimizer_switch='not_null_range_scan=on';
+create table ten(a int);
+insert into ten values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
+create table one_k(a int);
+insert into one_k select A.a + B.a* 10 + C.a * 100 from ten A, ten B, ten C;
+create table t1 (
+id int NOT NULL,
+subset_id int DEFAULT NULL,
+PRIMARY KEY (id),
+KEY t1_subset_id (subset_id));
+create table t2 (
+id int,
+col int NOT NULL,
+key (id)
+);
+insert into t1 select a,a from one_k limit 5;
+insert into t1 select a+5,NULL from one_k limit 995;
+insert into t2 select a,a from one_k;
+analyze table t1,t2;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+test.t2 analyze status Table is already up to date
+# expected for t1: range access and rows = 4 (not 1000)
+explain SELECT * FROM t1,t2 WHERE t1.subset_id=t2.id;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range t1_subset_id t1_subset_id 5 NULL 4 Using index condition; Rowid-ordered scan
+1 SIMPLE t2 ref id id 5 test.t1.subset_id 1
+SELECT * FROM t1,t2 WHERE t1.subset_id=t2.id;
+id subset_id id col
+0 0 0 0
+1 1 1 1
+2 2 2 2
+3 3 3 3
+4 4 4 4
+# with a subquery
+# expected the same plan as above
+explain SELECT * FROM t1 WHERE t1.subset_id IN (SELECT t2.id FROM t2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 range t1_subset_id t1_subset_id 5 NULL 4 Using index condition; Rowid-ordered scan
+1 PRIMARY t2 ref id id 5 test.t1.subset_id 1 Using index; FirstMatch(t1)
+SELECT * FROM t1 WHERE t1.subset_id IN (SELECT t2.id FROM t2);
+id subset_id
+0 0
+1 1
+2 2
+3 3
+4 4
+# non-mergable subquery
+# expected for t1: range access and rows = 4 (not 1000)
+explain SELECT * FROM t1
+WHERE t1.subset_id IN (SELECT max(t2.id) FROM t2 group by t2.col);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 range t1_subset_id t1_subset_id 5 NULL 4 Using index condition; Rowid-ordered scan
+1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 4 test.t1.subset_id 1
+2 MATERIALIZED t2 ALL NULL NULL NULL NULL 1000 Using temporary
+SELECT * FROM t1
+WHERE t1.subset_id IN (SELECT max(t2.id) FROM t2 group by t2.col);
+id subset_id
+0 0
+1 1
+2 2
+3 3
+4 4
+create view v1 as SELECT t2.id FROM t2;
+create view v2 as SELECT t2.id FROM t2 group by t2.col;
+# with mergeable view
+# expected for t1: range access and rows = 4 (not 1000)
+explain SELECT * FROM t1, v1 where t1.subset_id=v1.id;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range t1_subset_id t1_subset_id 5 NULL 4 Using index condition; Rowid-ordered scan
+1 SIMPLE t2 ref id id 5 test.t1.subset_id 1 Using index
+SELECT * FROM t1, v1 where t1.subset_id=v1.id;
+id subset_id id
+0 0 0
+1 1 1
+2 2 2
+3 3 3
+4 4 4
+# with non-mergeable view
+# expected for t1: range access and rows = 4 (not 1000)
+explain SELECT * FROM t1, v2 where t1.subset_id=v2.id;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 range t1_subset_id t1_subset_id 5 NULL 4 Using index condition; Rowid-ordered scan
+1 PRIMARY <derived2> ref key0 key0 5 test.t1.subset_id 10
+2 DERIVED t2 ALL NULL NULL NULL NULL 1000 Using temporary; Using filesort
+SELECT * FROM t1, v2 where t1.subset_id=v2.id;
+id subset_id id
+0 0 0
+1 1 1
+2 2 2
+3 3 3
+4 4 4
+# expected for t2 and for t1: range access
+explain SELECT * FROM t2 LEFT JOIN t1 ON t1.subset_id != 5 WHERE t2.id in (0,2,4);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 range id id 5 NULL 3 Using index condition; Rowid-ordered scan
+1 SIMPLE t1 range t1_subset_id t1_subset_id 5 NULL 4 Using where; Rowid-ordered scan; Using join buffer (flat, BNL join)
+SELECT * FROM t2 LEFT JOIN t1 ON t1.subset_id != 5 WHERE t2.id in (0,2,4);
+id col id subset_id
+0 0 0 0
+2 2 0 0
+4 4 0 0
+0 0 1 1
+2 2 1 1
+4 4 1 1
+0 0 2 2
+2 2 2 2
+4 4 2 2
+0 0 3 3
+2 2 3 3
+4 4 3 3
+0 0 4 4
+2 2 4 4
+4 4 4 4
+# no range access expected for t1
+explain SELECT * FROM t1 LEFT JOIN t2 ON t1.subset_id=t2.id LIMIT 10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 1000
+1 SIMPLE t2 ref id id 5 test.t1.subset_id 1 Using where
+SELECT * FROM t1 LEFT JOIN t2 ON t1.subset_id=t2.id LIMIT 10;
+id subset_id id col
+0 0 0 0
+1 1 1 1
+2 2 2 2
+3 3 3 3
+4 4 4 4
+5 NULL NULL NULL
+6 NULL NULL NULL
+7 NULL NULL NULL
+8 NULL NULL NULL
+9 NULL NULL NULL
+# expected for t1: range access
+explain SELECT * FROM ten LEFT JOIN (t1,t2) ON ten.a=t2.col AND t1.subset_id=t2.id;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE ten ALL NULL NULL NULL NULL 10
+1 SIMPLE t1 range t1_subset_id t1_subset_id 5 NULL 4 Using where; Rowid-ordered scan
+1 SIMPLE t2 ref id id 5 test.t1.subset_id 1 Using where
+SELECT * FROM ten LEFT JOIN (t1,t2) ON ten.a=t2.col AND t1.subset_id=t2.id;
+a id subset_id id col
+0 0 0 0 0
+1 1 1 1 1
+2 2 2 2 2
+3 3 3 3 3
+4 4 4 4 4
+5 NULL NULL NULL NULL
+6 NULL NULL NULL NULL
+7 NULL NULL NULL NULL
+8 NULL NULL NULL NULL
+9 NULL NULL NULL NULL
+# no range access expected for t1
+explain SELECT * FROM t1 LEFT JOIN (t2,ten) ON ten.a=t2.col AND t1.subset_id=t2.id
+LIMIT 10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 1000
+1 SIMPLE t2 ref id id 5 test.t1.subset_id 1 Using where
+1 SIMPLE ten ALL NULL NULL NULL NULL 10 Using where
+SELECT * FROM t1 LEFT JOIN (t2,ten) ON ten.a=t2.col AND t1.subset_id=t2.id
+LIMIT 10;
+id subset_id id col a
+0 0 0 0 0
+1 1 1 1 1
+2 2 2 2 2
+3 3 3 3 3
+4 4 4 4 4
+5 NULL NULL NULL NULL
+6 NULL NULL NULL NULL
+7 NULL NULL NULL NULL
+8 NULL NULL NULL NULL
+9 NULL NULL NULL NULL
+drop index id on t2;
+# expected for t1: range access
+explain SELECT * FROM t1,t2 WHERE t1.subset_id=t2.id;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range t1_subset_id t1_subset_id 5 NULL 4 Using index condition; Rowid-ordered scan
+1 SIMPLE t2 ALL NULL NULL NULL NULL 1000 Using where; Using join buffer (flat, BNL join)
+SELECT * FROM t1,t2 WHERE t1.subset_id=t2.id;
+id subset_id id col
+0 0 0 0
+1 1 1 1
+2 2 2 2
+3 3 3 3
+4 4 4 4
+# expected impossible where after reading const tables
+explain SELECT * FROM t1,t2 WHERE t1.subset_id > t2.id AND t1.subset_id IS NULL;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+SELECT * FROM t1,t2 WHERE t1.subset_id > t2.id AND t1.subset_id IS NULL;
+id subset_id id col
+# expected impossible where after reading const tables
+explain SELECT * FROM t1,t2 WHERE t1.subset_id > t2.id AND t2.id IS NULL;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+SELECT * FROM t1,t2 WHERE t1.subset_id > t2.id AND t2.id IS NULL;
+id subset_id id col
+drop index t1_subset_id on t1;
+alter table t1 add column m int not null default 0;
+alter table t1 add index idx(m,subset_id);
+alter table t2 add index (id);
+update t1 set m = id mod 2;
+analyze table t1,t2;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+test.t2 analyze status Table is already up to date
+# expected for t1: range access by idx (keylen=9)
+explain SELECT * FROM t1,t2 WHERE t1.subset_id=t2.id and t1.m=0 ;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range idx idx 9 NULL 4 Using index condition; Rowid-ordered scan
+1 SIMPLE t2 ref id id 5 test.t1.subset_id 1
+SELECT * FROM t1,t2 WHERE t1.subset_id=t2.id and t1.m=0 ;
+id subset_id m id col
+0 0 0 0 0
+2 2 0 2 2
+4 4 0 4 4
+drop view v1,v2;
+drop table t1,t2;
+create table t1 (
+id int NOT NULL,
+subset_id int DEFAULT NULL,
+KEY key1(id, subset_id),
+KEY t1_subset_id (subset_id)
+);
+create table t2 (
+id int NOT NULL,
+col int NOT NULL,
+key (id)
+);
+insert into t1 select 1,a from one_k limit 5;
+insert into t1 select 1,NULL from one_k limit 495;
+insert into t2 select a,a from one_k;
+analyze table t1,t2;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+test.t2 analyze status Table is already up to date
+# expected for t1 :range access by index key1
+# rows 4 instead of 500
+explain SELECT * FROM t1,t2 WHERE t1.id>=1 and t1.subset_id=t2.id;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range key1,t1_subset_id key1 9 NULL 4 Using where; Using index
+1 SIMPLE t2 ref id id 4 test.t1.subset_id 1
+SELECT * FROM t1,t2 WHERE t1.id>=1 and t1.subset_id=t2.id;
+id subset_id id col
+1 0 0 0
+1 1 1 1
+1 2 2 2
+1 3 3 3
+1 4 4 4
+drop table t1,t2;
+create table t1 (id int unsigned,col int, KEY key1(id));
+create table t2 (id int unsigned,col int DEFAULT NULL,key (id));
+insert into t1 select a,2 from one_k limit 50;
+insert into t1 select NULL,2 from one_k limit 450;
+insert into t2 select a,a from one_k;
+insert into t2 select a,a from one_k;
+analyze table t1,t2;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+test.t2 analyze status OK
+# using key1 for range access on t1 and also using index for sorting,
+# no filesort, rows should be 75 not 500
+explain SELECT * FROM t1,t2 WHERE t1.id=t2.id AND t1.col=2 ORDER BY t2.id LIMIT 10;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range key1 key1 5 NULL 75 Using index condition; Using where
+1 SIMPLE t2 ref id id 5 test.t1.id 2
+SELECT * FROM t1,t2 WHERE t1.id=t2.id AND t1.col=2 ORDER BY t2.id LIMIT 10;
+id col id col
+0 2 0 0
+0 2 0 0
+1 2 1 1
+1 2 1 1
+2 2 2 2
+2 2 2 2
+3 2 3 3
+3 2 3 3
+4 2 4 4
+4 2 4 4
+drop table t1,t2;
+drop table ten,one_k;
+set @@optimizer_switch= @save_optimizer_switch;
+#
+# End of 10.3 tests
+#
set optimizer_switch=@mrr_icp_extra_tmp;
diff --git a/mysql-test/suite/sys_vars/r/optimizer_switch_basic.result b/mysql-test/suite/sys_vars/r/optimizer_switch_basic.result
index 87c8379..ba40512 100644
--- a/mysql-test/suite/sys_vars/r/optimizer_switch_basic.result
+++ b/mysql-test/suite/sys_vars/r/optimizer_switch_basic.result
@@ -1,63 +1,63 @@
SET @start_global_value = @@global.optimizer_switch;
SELECT @start_global_value;
@start_global_value
-index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
+index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,not_null_range_scan=off
select @@global.optimizer_switch;
@@global.optimizer_switch
-index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
+index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,not_null_range_scan=off
select @@session.optimizer_switch;
@@session.optimizer_switch
-index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
+index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,not_null_range_scan=off
show global variables like 'optimizer_switch';
Variable_name Value
-optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
+optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,not_null_range_scan=off
show session variables like 'optimizer_switch';
Variable_name Value
-optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
+optimizer_switch index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,not_null_range_scan=off
select * from information_schema.global_variables where variable_name='optimizer_switch';
VARIABLE_NAME VARIABLE_VALUE
-OPTIMIZER_SWITCH index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
+OPTIMIZER_SWITCH index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,not_null_range_scan=off
select * from information_schema.session_variables where variable_name='optimizer_switch';
VARIABLE_NAME VARIABLE_VALUE
-OPTIMIZER_SWITCH index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
+OPTIMIZER_SWITCH index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,not_null_range_scan=off
set global optimizer_switch=10;
set session optimizer_switch=5;
select @@global.optimizer_switch;
@@global.optimizer_switch
-index_merge=off,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off
+index_merge=off,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,not_null_range_scan=off
select @@session.optimizer_switch;
@@session.optimizer_switch
-index_merge=on,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off
+index_merge=on,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,not_null_range_scan=off
set global optimizer_switch="index_merge_sort_union=on";
set session optimizer_switch="index_merge=off";
select @@global.optimizer_switch;
@@global.optimizer_switch
-index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off
+index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,not_null_range_scan=off
select @@session.optimizer_switch;
@@session.optimizer_switch
-index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off
+index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,not_null_range_scan=off
show global variables like 'optimizer_switch';
Variable_name Value
-optimizer_switch index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off
+optimizer_switch index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,not_null_range_scan=off
show session variables like 'optimizer_switch';
Variable_name Value
-optimizer_switch index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off
+optimizer_switch index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,not_null_range_scan=off
select * from information_schema.global_variables where variable_name='optimizer_switch';
VARIABLE_NAME VARIABLE_VALUE
-OPTIMIZER_SWITCH index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off
+OPTIMIZER_SWITCH index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,not_null_range_scan=off
select * from information_schema.session_variables where variable_name='optimizer_switch';
VARIABLE_NAME VARIABLE_VALUE
-OPTIMIZER_SWITCH index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off
+OPTIMIZER_SWITCH index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=off,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,not_null_range_scan=off
set session optimizer_switch="default";
select @@session.optimizer_switch;
@@session.optimizer_switch
-index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off
+index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off,extended_keys=off,exists_to_in=off,orderby_uses_equalities=off,condition_pushdown_for_derived=off,split_materialized=off,not_null_range_scan=off
set optimizer_switch = replace(@@optimizer_switch, '=off', '=on');
Warnings:
Warning 1681 'engine_condition_pushdown=on' is deprecated and will be removed in a future release
select @@optimizer_switch;
@@optimizer_switch
-index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=on,mrr_cost_based=on,mrr_sort_keys=on,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
+index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=on,mrr_cost_based=on,mrr_sort_keys=on,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,not_null_range_scan=on
set global optimizer_switch=1.1;
ERROR 42000: Incorrect argument type to variable 'optimizer_switch'
set global optimizer_switch=1e1;
@@ -69,4 +69,4 @@ ERROR 42000: Variable 'optimizer_switch' can't be set to the value of 'foobar'
SET @@global.optimizer_switch = @start_global_value;
SELECT @@global.optimizer_switch;
@@global.optimizer_switch
-index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
+index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,not_null_range_scan=off
diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result
index 89e5fef..714b55c 100644
--- a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result
+++ b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result
@@ -2715,17 +2715,17 @@ ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME OPTIMIZER_SWITCH
-SESSION_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
-GLOBAL_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
+SESSION_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,not_null_range_scan=off
+GLOBAL_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,not_null_range_scan=off
GLOBAL_VALUE_ORIGIN COMPILE-TIME
-DEFAULT_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
+DEFAULT_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,not_null_range_scan=off
VARIABLE_SCOPE SESSION
VARIABLE_TYPE FLAGSET
VARIABLE_COMMENT Fine-tune the optimizer behavior
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
-ENUM_VALUE_LIST index_merge,index_merge_union,index_merge_sort_union,index_merge_intersection,index_merge_sort_intersection,engine_condition_pushdown,index_condition_pushdown,derived_merge,derived_with_keys,firstmatch,loosescan,materialization,in_to_exists,semijoin,partial_match_rowid_merge,partial_match_table_scan,subquery_cache,mrr,mrr_cost_based,mrr_sort_keys,outer_join_with_cache,semijoin_with_cache,join_cache_incremental,join_cache_hashed,join_cache_bka,optimize_join_buffer_size,table_elimination,extended_keys,exists_to_in,orderby_uses_equalities,condition_pushdown_for_derived,split_materialized,default
+ENUM_VALUE_LIST index_merge,index_merge_union,index_merge_sort_union,index_merge_intersection,index_merge_sort_intersection,engine_condition_pushdown,index_condition_pushdown,derived_merge,derived_with_keys,firstmatch,loosescan,materialization,in_to_exists,semijoin,partial_match_rowid_merge,partial_match_table_scan,subquery_cache,mrr,mrr_cost_based,mrr_sort_keys,outer_join_with_cache,semijoin_with_cache,join_cache_incremental,join_cache_hashed,join_cache_bka,optimize_join_buffer_size,table_elimination,extended_keys,exists_to_in,orderby_uses_equalities,condition_pushdown_for_derived,split_materialized,not_null_range_scan,default
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME OPTIMIZER_USE_CONDITION_SELECTIVITY
diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
index ca875e7..dd9d9eb 100644
--- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
+++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
@@ -2925,17 +2925,17 @@ ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME OPTIMIZER_SWITCH
-SESSION_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
-GLOBAL_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
+SESSION_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,not_null_range_scan=off
+GLOBAL_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,not_null_range_scan=off
GLOBAL_VALUE_ORIGIN COMPILE-TIME
-DEFAULT_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
+DEFAULT_VALUE index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,not_null_range_scan=off
VARIABLE_SCOPE SESSION
VARIABLE_TYPE FLAGSET
VARIABLE_COMMENT Fine-tune the optimizer behavior
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
-ENUM_VALUE_LIST index_merge,index_merge_union,index_merge_sort_union,index_merge_intersection,index_merge_sort_intersection,engine_condition_pushdown,index_condition_pushdown,derived_merge,derived_with_keys,firstmatch,loosescan,materialization,in_to_exists,semijoin,partial_match_rowid_merge,partial_match_table_scan,subquery_cache,mrr,mrr_cost_based,mrr_sort_keys,outer_join_with_cache,semijoin_with_cache,join_cache_incremental,join_cache_hashed,join_cache_bka,optimize_join_buffer_size,table_elimination,extended_keys,exists_to_in,orderby_uses_equalities,condition_pushdown_for_derived,split_materialized,default
+ENUM_VALUE_LIST index_merge,index_merge_union,index_merge_sort_union,index_merge_intersection,index_merge_sort_intersection,engine_condition_pushdown,index_condition_pushdown,derived_merge,derived_with_keys,firstmatch,loosescan,materialization,in_to_exists,semijoin,partial_match_rowid_merge,partial_match_table_scan,subquery_cache,mrr,mrr_cost_based,mrr_sort_keys,outer_join_with_cache,semijoin_with_cache,join_cache_incremental,join_cache_hashed,join_cache_bka,optimize_join_buffer_size,table_elimination,extended_keys,exists_to_in,orderby_uses_equalities,condition_pushdown_for_derived,split_materialized,not_null_range_scan,default
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME OPTIMIZER_USE_CONDITION_SELECTIVITY
diff --git a/sql/item.cc b/sql/item.cc
index 3584230..9c95611 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -3556,6 +3556,16 @@ table_map Item_field::all_used_tables() const
}
+bool Item_field::find_not_null_fields(table_map allowed)
+{
+ if (field->table->const_table)
+ return false;
+ if (!get_depended_from() && field->real_maybe_null())
+ bitmap_set_bit(&field->table->tmp_set, field->field_index);
+ return false;
+}
+
+
/*
@Note thd->fatal_error can be set in case of OOM
*/
diff --git a/sql/item.h b/sql/item.h
index 2adc111..c2dbdb1 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1818,6 +1818,44 @@ class Item: public Value_source,
virtual bool set_fields_as_dependent_processor(void *arg) { return 0; }
/*============== End of Item processor list ======================*/
+ /*
+ Given a condition P from the WHERE clause or from an ON expression of
+ the processed SELECT S and a set of join tables from S marked in the
+ parameter 'allowed'={T} a call of P->find_not_null_fields({T}) has to
+ find the set fields {F} of the tables from 'allowed' such that:
+ - each field from {F} is declared as nullable
+ - each record of table t from {T} that contains NULL as the value for at
+ at least one field from {F} can be ignored when building the result set
+ for S
+ It is assumed here that the condition P is conjunctive and all its column
+ references belong to T.
+
+ Examples:
+ CREATE TABLE t1 (a int, b int);
+ CREATE TABLE t2 (a int, b int);
+
+ SELECT * FROM t1,t2 WHERE t1.a=t2.a and t1.b > 5;
+ A call of find_not_null_fields() for the whole WHERE condition and {t1,t2}
+ should find {t1.a,t1.b,t2.a}
+
+ SELECT * FROM t1 LEFT JOIN ON (t1.a=t2.a and t2.a > t2.b);
+ A call of find_not_null_fields() for the ON expression and {t2}
+ should find {t2.a,t2.b}
+
+ The function returns TRUE if it succeeds to prove that all records of
+ a table from {T} can be ignored. Otherwise it always returns FALSE.
+
+ Example:
+ SELECT * FROM t1,t2 WHERE t1.a=t2.a AND t2.a IS NULL;
+ A call of find_not_null_fields() for the WHERE condition and {t1,t2}
+ will return TRUE.
+
+ It is assumed that the implementation of this virtual function saves
+ the info on the found set of fields in the structures associates with
+ tables from {T}.
+ */
+ virtual bool find_not_null_fields(table_map allowed) { return false; }
+
virtual Item *get_copy(THD *thd)=0;
bool cache_const_expr_analyzer(uchar **arg);
@@ -3079,6 +3117,7 @@ class Item_field :public Item_ident,
bool is_result_field() { return false; }
void save_in_result_field(bool no_conversions);
Item *get_tmp_table_item(THD *thd);
+ bool find_not_null_fields(table_map allowed);
bool collect_item_field_processor(void * arg);
bool add_field_to_set_processor(void * arg);
bool find_item_in_field_list_processor(void *arg);
@@ -4858,6 +4897,10 @@ class Item_ref :public Item_ident
{
return depended_from ? 0 : (*ref)->not_null_tables();
}
+ bool find_not_null_fields(table_map allowed)
+ {
+ return depended_from ? false : (*ref)->find_not_null_fields(allowed);
+ }
void save_in_result_field(bool no_conversions)
{
(*ref)->save_in_field(result_field, no_conversions);
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 49e0a94..c4b43a7 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -1192,6 +1192,15 @@ bool Item_in_optimizer::eval_not_null_tables(void *opt_arg)
}
+bool Item_in_optimizer::find_not_null_fields(table_map allowed)
+{
+ if (!(~allowed & used_tables()) && is_top_level_item())
+ {
+ return args[0]->find_not_null_fields(allowed);
+ }
+ return false;
+}
+
void Item_in_optimizer::print(String *str, enum_query_type query_type)
{
restore_first_argument();
@@ -2035,7 +2044,17 @@ bool Item_func_between::eval_not_null_tables(void *opt_arg)
(args[1]->not_null_tables() &
args[2]->not_null_tables()));
return 0;
-}
+}
+
+
+bool Item_func_between::find_not_null_fields(table_map allowed)
+{
+ if (negated || !is_top_level_item() || (~allowed & used_tables()))
+ return false;
+ return args[0]->find_not_null_fields(allowed) ||
+ args[1]->find_not_null_fields(allowed) ||
+ args[3]->find_not_null_fields(allowed);
+}
bool Item_func_between::count_sargable_conds(void *arg)
@@ -4151,6 +4170,15 @@ Item_func_in::eval_not_null_tables(void *opt_arg)
}
+bool
+Item_func_in::find_not_null_fields(table_map allowed)
+{
+ if (negated || !is_top_level_item() || (~allowed & used_tables()))
+ return 0;
+ return args[0]->find_not_null_fields(allowed);
+}
+
+
void Item_func_in::fix_after_pullout(st_select_lex *new_parent, Item **ref,
bool merge)
{
@@ -4705,6 +4733,82 @@ Item_cond::eval_not_null_tables(void *opt_arg)
}
+/**
+ @note
+ This implementation of the virtual function find_not_null_fields()
+ infers null-rejectedness if fields from tables marked in 'allowed' from
+ this condition.
+ Currently only top level AND conjuncts that are not disjunctions are used
+ for the inference. Usage of any top level and-or formula with l OR levels
+ would require a stack of bitmaps for fields of the height h=2*l+1 So we
+ would have to allocate h-1 additional field bitmaps for each table marked
+ in 'allowed'.
+*/
+
+bool
+Item_cond::find_not_null_fields(table_map allowed)
+{
+ Item *item;
+ bool is_and_cond= functype() == Item_func::COND_AND_FUNC;
+ if (!is_and_cond)
+ {
+ /* Now only fields of top AND level conjuncts are taken into account */
+ return false;
+ }
+ uint isnull_func_cnt= 0;
+ List_iterator<Item> li(list);
+ while ((item=li++))
+ {
+ bool is_mult_eq= item->type() == Item::FUNC_ITEM &&
+ ((Item_func *) item)->functype() == Item_func::MULT_EQUAL_FUNC;
+ if (is_mult_eq)
+ {
+ if (!item->find_not_null_fields(allowed))
+ continue;
+ }
+
+ if (~allowed & item->used_tables())
+ continue;
+
+ /* It is assumed that all constant conjuncts are already eliminated */
+
+ /*
+ First infer null-rejectedness of fields from all conjuncts but
+ IS NULL predicates
+ */
+ bool isnull_func= item->type() == Item::FUNC_ITEM &&
+ ((Item_func *) item)->functype() == Item_func::ISNULL_FUNC;
+ if (isnull_func)
+ {
+ isnull_func_cnt++;
+ continue;
+ }
+ if (!item->find_not_null_fields(allowed))
+ continue;
+ }
+
+ /* Now try no get contradictions using IS NULL conjuncts */
+ if (isnull_func_cnt)
+ {
+ li.rewind();
+ while ((item=li++) && isnull_func_cnt)
+ {
+ if (~allowed & item->used_tables())
+ continue;
+
+ bool isnull_func= item->type() == Item::FUNC_ITEM &&
+ ((Item_func *) item)->functype() == Item_func::ISNULL_FUNC;
+ if (isnull_func)
+ {
+ if (item->find_not_null_fields(allowed))
+ return true;
+ isnull_func_cnt--;
+ }
+ }
+ }
+ return false;
+}
+
void Item_cond::fix_after_pullout(st_select_lex *new_parent, Item **ref,
bool merge)
{
@@ -5148,6 +5252,19 @@ longlong Item_func_isnull::val_int()
}
+bool Item_func_isnull::find_not_null_fields(table_map allowed)
+{
+ if (!(~allowed & used_tables()) &&
+ args[0]->real_item()->type() == Item::FIELD_ITEM)
+ {
+ Field *field= ((Item_field *)(args[0]->real_item()))->field;
+ if (bitmap_is_set(&field->table->tmp_set, field->field_index))
+ return true;
+ }
+ return false;
+}
+
+
void Item_func_isnull::print(String *str, enum_query_type query_type)
{
if (const_item() && !args[0]->maybe_null &&
@@ -6734,6 +6851,48 @@ void Item_equal::update_used_tables()
}
+/**
+ @note
+ This multiple equality can contains elements belonging not to tables {T}
+ marked in 'allowed' . So we can ascertain null-rejectedness of field f
+ belonging to table t from {T} only if one of the following equality
+ predicate can be extracted from this multiple equality:
+ - f=const
+ - f=f' where f' is a field of some table from {T}
+*/
+
+bool Item_equal::find_not_null_fields(table_map allowed)
+{
+ if (!(allowed & used_tables()))
+ return false;
+ bool checked= false;
+ Item_equal_fields_iterator it(*this);
+ Item *item;
+ while ((item= it++))
+ {
+ if (~allowed & item->used_tables())
+ continue;
+ if ((with_const || checked) && !item->find_not_null_fields(allowed))
+ continue;
+ Item_equal_fields_iterator it1(*this);
+ Item *item1;
+ while ((item1= it1++) && item1 != item)
+ {
+ if (~allowed & item1->used_tables())
+ continue;
+ if (!item->find_not_null_fields(allowed) &&
+ !item1->find_not_null_fields(allowed))
+ {
+ checked= true;
+ break;
+ }
+ }
+ }
+ return false;
+}
+
+
+
bool Item_equal::count_sargable_conds(void *arg)
{
SELECT_LEX *sel= (SELECT_LEX *) arg;
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 7d99cbd..8f01e4f 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -284,6 +284,7 @@ class Item_func_isnottrue : public Item_func_truth
Item_func_truth(thd, a, true, false) {}
~Item_func_isnottrue() {}
virtual const char* func_name() const { return "isnottrue"; }
+ bool find_not_null_fields(table_map allowed) { return false; }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_isnottrue>(thd, this); }
};
@@ -315,6 +316,7 @@ class Item_func_isnotfalse : public Item_func_truth
Item_func_truth(thd, a, false, false) {}
~Item_func_isnotfalse() {}
virtual const char* func_name() const { return "isnotfalse"; }
+ bool find_not_null_fields(table_map allowed) { return false; }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_isnotfalse>(thd, this); }
};
@@ -376,6 +378,7 @@ class Item_in_optimizer: public Item_bool_func
virtual void get_cache_parameters(List<Item> ¶meters);
bool is_top_level_item();
bool eval_not_null_tables(void *opt_arg);
+ bool find_not_null_fields(table_map allowed);
void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge);
bool invisible_mode();
void reset_cache() { cache= NULL; }
@@ -571,6 +574,7 @@ class Item_func_xor :public Item_bool_func
void print(String *str, enum_query_type query_type)
{ Item_func::print_op(str, query_type); }
longlong val_int();
+ bool find_not_null_fields(table_map allowed) { return false; }
Item *neg_transformer(THD *thd);
Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond)
{
@@ -592,6 +596,7 @@ class Item_func_not :public Item_bool_func
longlong val_int();
enum Functype functype() const { return NOT_FUNC; }
const char *func_name() const { return "not"; }
+ bool find_not_null_fields(table_map allowed) { return false; }
enum precedence precedence() const { return BANG_PRECEDENCE; }
Item *neg_transformer(THD *thd);
bool fix_fields(THD *, Item **);
@@ -736,6 +741,7 @@ class Item_func_equal :public Item_bool_rowready_func2
longlong val_int();
bool fix_length_and_dec();
table_map not_null_tables() const { return 0; }
+ bool find_not_null_fields(table_map allowed) { return false; }
enum Functype functype() const { return EQUAL_FUNC; }
enum Functype rev_functype() const { return EQUAL_FUNC; }
cond_result eq_cmp_result() const { return COND_TRUE; }
@@ -912,6 +918,7 @@ class Item_func_between :public Item_func_opt_neg
bool fix_length_and_dec_numeric(THD *);
virtual void print(String *str, enum_query_type query_type);
bool eval_not_null_tables(void *opt_arg);
+ bool find_not_null_fields(table_map allowed);
void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge);
bool count_sargable_conds(void *arg);
void add_key_fields(JOIN *join, KEY_FIELD **key_fields,
@@ -2396,6 +2403,7 @@ class Item_func_in :public Item_func_opt_neg,
const char *func_name() const { return "in"; }
enum precedence precedence() const { return CMP_PRECEDENCE; }
bool eval_not_null_tables(void *opt_arg);
+ bool find_not_null_fields(table_map allowed);
void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge);
bool count_sargable_conds(void *arg);
Item *get_copy(THD *thd)
@@ -2533,6 +2541,7 @@ class Item_func_isnull :public Item_func_null_predicate
COND *remove_eq_conds(THD *thd, Item::cond_result *cond_value,
bool top_level);
table_map not_null_tables() const { return 0; }
+ bool find_not_null_fields(table_map allowed);
Item *neg_transformer(THD *thd);
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_isnull>(thd, this); }
@@ -2953,6 +2962,7 @@ class Item_cond :public Item_bool_func
Item *compile(THD *thd, Item_analyzer analyzer, uchar **arg_p,
Item_transformer transformer, uchar *arg_t);
bool eval_not_null_tables(void *opt_arg);
+ bool find_not_null_fields(table_map allowed);
Item *build_clone(THD *thd);
bool excl_dep_on_table(table_map tab_map);
bool excl_dep_on_grouping_fields(st_select_lex *sel);
@@ -3119,6 +3129,7 @@ class Item_equal: public Item_bool_func
eval_item= NULL;
}
void update_used_tables();
+ bool find_not_null_fields(table_map allowed);
COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
bool link_item_fields,
COND_EQUAL **cond_equal_ref);
diff --git a/sql/item_func.cc b/sql/item_func.cc
index a030d2f..41bbd2e 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -403,6 +403,25 @@ Item_func::eval_not_null_tables(void *opt_arg)
}
+bool
+Item_func::find_not_null_fields(table_map allowed)
+{
+ if (~allowed & used_tables())
+ return false;
+
+ Item **arg,**arg_end;
+ if (arg_count)
+ {
+ for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++)
+ {
+ if (!(*arg)->find_not_null_fields(allowed))
+ continue;
+ }
+ }
+ return false;
+}
+
+
void Item_func::fix_after_pullout(st_select_lex *new_parent, Item **ref,
bool merge)
{
diff --git a/sql/item_func.h b/sql/item_func.h
index 6345dd4..325a796 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -210,6 +210,7 @@ class Item_func :public Item_func_or_sum
void traverse_cond(Cond_traverser traverser,
void * arg, traverse_order order);
bool eval_not_null_tables(void *opt_arg);
+ bool find_not_null_fields(table_map allowed);
// bool is_expensive_processor(void *arg);
// virtual bool is_expensive() { return 0; }
inline void raise_numeric_overflow(const char *type_name)
@@ -671,6 +672,7 @@ class Item_func_case_expression: public Item_func_hybrid_field_type
Item_func_case_expression(THD *thd, List<Item> &list):
Item_func_hybrid_field_type(thd, list)
{ }
+ bool find_not_null_fields(table_map allowed) { return false; }
};
@@ -1759,6 +1761,10 @@ class Item_func_coercibility :public Item_long_func
not_null_tables_cache= 0;
return false;
}
+ bool find_not_null_fields(table_map allowed)
+ {
+ return false;
+ }
Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond)
{ return this; }
bool const_item() const { return true; }
@@ -2119,6 +2125,10 @@ class Item_udf_func :public Item_func
not_null_tables_cache= 0;
return 0;
}
+ bool find_not_null_fields(table_map allowed)
+ {
+ return false;
+ }
bool is_expensive() { return 1; }
virtual void print(String *str, enum_query_type query_type);
bool check_vcol_func_processor(void *arg)
@@ -2711,6 +2721,10 @@ class Item_func_match :public Item_real_func
not_null_tables_cache= 0;
return 0;
}
+ bool find_not_null_fields(table_map allowed)
+ {
+ return false;
+ }
bool fix_fields(THD *thd, Item **ref);
bool eq(const Item *, bool binary_cmp) const;
/* The following should be safe, even if we compare doubles */
@@ -3000,6 +3014,10 @@ class Item_func_sp :public Item_func,
not_null_tables_cache= 0;
return 0;
}
+ bool find_not_null_fields(table_map allowed)
+ {
+ return false;
+ }
};
@@ -3103,6 +3121,10 @@ class Item_func_last_value :public Item_func
not_null_tables_cache= 0;
return 0;
}
+ bool find_not_null_fields(table_map allowed)
+ {
+ return false;
+ }
bool const_item() const { return 0; }
void evaluate_sideeffects();
void update_used_tables()
diff --git a/sql/item_row.cc b/sql/item_row.cc
index 70a9fe5..0b55ae5 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -87,6 +87,25 @@ Item_row::eval_not_null_tables(void *opt_arg)
}
+bool
+Item_row::find_not_null_fields(table_map allowed)
+{
+ if (~allowed & used_tables())
+ return false;
+
+ Item **arg,**arg_end;
+ if (arg_count)
+ {
+ for (arg= args, arg_end= args + arg_count; arg != arg_end ; arg++)
+ {
+ if (!(*arg)->find_not_null_fields(allowed))
+ continue;
+ }
+ }
+ return false;
+}
+
+
void Item_row::cleanup()
{
DBUG_ENTER("Item_row::cleanup");
diff --git a/sql/item_row.h b/sql/item_row.h
index 0d6a6db..0efa29f 100644
--- a/sql/item_row.h
+++ b/sql/item_row.h
@@ -110,6 +110,7 @@ class Item_row: public Item,
}
Item *transform(THD *thd, Item_transformer transformer, uchar *arg);
bool eval_not_null_tables(void *opt_arg);
+ bool find_not_null_fields(table_map allowed);
uint cols() const { return arg_count; }
Item* element_index(uint i) { return args[i]; }
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index ec7b3db..91103a5 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -2399,6 +2399,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
{
uint idx;
double scan_time;
+ Item *notnull_cond= NULL;
DBUG_ENTER("SQL_SELECT::test_quick_select");
DBUG_PRINT("enter",("keys_to_use: %lu prev_tables: %lu const_tables: %lu",
(ulong) keys_to_use.to_ulonglong(), (ulong) prev_tables,
@@ -2412,6 +2413,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
if (keys_to_use.is_clear_all() || head->is_filled_at_execution())
DBUG_RETURN(0);
records= head->stat_records();
+ notnull_cond= head->notnull_cond;
if (!records)
records++; /* purecov: inspected */
scan_time= (double) records / TIME_FOR_COMPARE + 1;
@@ -2419,7 +2421,10 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
if (head->force_index)
scan_time= read_time= DBL_MAX;
if (limit < records)
+ {
read_time= (double) records + scan_time + 1; // Force to use index
+ notnull_cond= NULL;
+ }
possible_keys.clear_all();
@@ -2431,6 +2436,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
uchar buff[STACK_BUFF_ALLOC];
MEM_ROOT alloc;
SEL_TREE *tree= NULL;
+ SEL_TREE *notnull_cond_tree= NULL;
KEY_PART *key_parts;
KEY *key_info;
PARAM param;
@@ -2539,6 +2545,9 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
TRP_GROUP_MIN_MAX *group_trp;
double best_read_time= read_time;
+ if (notnull_cond)
+ notnull_cond_tree= notnull_cond->get_mm_tree(¶m, ¬null_cond);
+
if (cond)
{
if ((tree= cond->get_mm_tree(¶m, &cond)))
@@ -2557,6 +2566,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
tree= NULL;
}
}
+ tree= tree_and(¶m, tree, notnull_cond_tree);
/*
Try to construct a QUICK_GROUP_MIN_MAX_SELECT.
diff --git a/sql/sql_priv.h b/sql/sql_priv.h
index 2f37e11..ec7b2cc 100644
--- a/sql/sql_priv.h
+++ b/sql/sql_priv.h
@@ -222,6 +222,7 @@
#define OPTIMIZER_SWITCH_ORDERBY_EQ_PROP (1ULL << 29)
#define OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED (1ULL << 30)
#define OPTIMIZER_SWITCH_SPLIT_MATERIALIZED (1ULL << 31)
+#define OPTIMIZER_SWITCH_NOT_NULL_RANGE_SCAN (1ULL << 32)
#define OPTIMIZER_SWITCH_DEFAULT (OPTIMIZER_SWITCH_INDEX_MERGE | \
OPTIMIZER_SWITCH_INDEX_MERGE_UNION | \
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 0fbc4ba..dae2cd7 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -295,6 +295,14 @@ void set_postjoin_aggr_write_func(JOIN_TAB *tab);
static Item **get_sargable_cond(JOIN *join, TABLE *table);
+static
+bool build_notnull_conds_for_range_scans(JOIN *join, COND *cond,
+ table_map allowed);
+static
+void build_notnull_conds_for_inner_nest_of_outer_join(JOIN *join,
+ TABLE_LIST *nest_tbl);
+
+
#ifndef DBUG_OFF
/*
@@ -4907,6 +4915,9 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
}
}
+ join->join_tab= stat;
+ join->make_notnull_conds_for_range_scans();
+
/* Calc how many (possible) matched records in each table */
for (s=stat ; s < stat_end ; s++)
@@ -27572,6 +27583,280 @@ Item *remove_pushed_top_conjuncts(THD *thd, Item *cond)
return cond;
}
+
+/**
+ @brief
+ Construct not null conditions for provingly not nullable fields
+
+ @details
+ For each non-constant joined table the function creates a conjunction
+ of IS NOT NULL predicates containing a predicate for each field used
+ in the WHERE clause or an OR expression such that
+ - is declared as nullable
+ - for which it can proved be that it is null-rejected
+ - is a part of some index.
+ This conjunction could be anded with either the WHERE condition or with
+ an ON expression and the modified join query would produce the same
+ result set as the original one.
+ If a conjunction of IS NOT NULL predicates is constructed for an inner
+ table of an outer join OJ that is not an inner table of embedded outer
+ joins then it is to be anded with the ON expression of OJ.
+ The constructed conjunctions of IS NOT NULL predicates are attached
+ to the corresponding tables. They used for range analysis complementary
+ to other sargable range conditions.
+
+ @note
+ Let f be a field of the joined table t. In the context of the upper
+ paragraph field f is called null-rejected if any the following holds:
+
+ - t is a table of a top inner join and a conjunctive formula that rejects
+ rows with null values for f can be extracted from the WHERE condition
+
+ - t is an outer table of a top outer join operation and a conjunctive
+ formula over the outer tables of the outer join that rejects rows with
+ null values for can be extracted from the WHERE condition
+
+ - t is an outer table of a non-top outer join operation and a conjunctive
+ formula over the outer tables of the outer join that rejects rows with
+ null values for f can be extracted from the ON expression of the
+ embedding outer join
+
+ - the joined table is an inner table of a outer join operation and
+ a conjunctive formula over inner tables of the outer join that rejects
+ rows with null values for f can be extracted from the ON expression of
+ the outer join operation.
+
+ It is assumed above that all inner join nests have been eliminated and
+ that all possible conversions of outer joins into inner joins have been
+ already done.
+*/
+
+void JOIN::make_notnull_conds_for_range_scans()
+{
+ DBUG_ENTER("JOIN::make_notnull_conds_for_range_scans");
+
+
+ if (impossible_where ||
+ !optimizer_flag(thd, OPTIMIZER_SWITCH_NOT_NULL_RANGE_SCAN))
+ {
+ /* Complementary range analysis is not needed */
+ DBUG_VOID_RETURN;
+ }
+
+ if (conds && build_notnull_conds_for_range_scans(this, conds,
+ conds->used_tables()))
+ {
+ Item *false_cond= new (thd->mem_root) Item_int(thd, (longlong) 0, 1);
+ if (false_cond)
+ {
+ /*
+ Found a IS NULL conjunctive predicate for a null-rejected field
+ in the WHERE clause
+ */
+ conds= false_cond;
+ cond_equal= 0;
+ impossible_where= true;
+ }
+ DBUG_VOID_RETURN;
+ }
+
+ List_iterator<TABLE_LIST> li(*join_list);
+ TABLE_LIST *tbl;
+ while ((tbl= li++))
+ {
+ if (tbl->on_expr)
+ {
+ if (tbl->nested_join)
+ {
+ build_notnull_conds_for_inner_nest_of_outer_join(this, tbl);
+ }
+ else if (build_notnull_conds_for_range_scans(this, tbl->on_expr,
+ tbl->table->map))
+ {
+ /*
+ Found a IS NULL conjunctive predicate for a null-rejected field
+ of the inner table of an outer join with ON expression tbl->on_expr
+ */
+ Item *false_cond= new (thd->mem_root) Item_int(thd, (longlong) 0, 1);
+ if (false_cond)
+ tbl->on_expr= false_cond;
+ }
+ }
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ @brief
+ Build not null conditions for range scans of given join tables
+
+ @param join the join for whose tables not null conditions are to be built
+ @param cond the condition from which not null predicates are to be inferred
+ @param allowed the bit map of join tables to be taken into account
+
+ @details
+ For each join table t from the 'allowed' set of tables the function finds
+ all fields whose null-rejectedness can be inferred from null-rejectedness
+ of the condition cond. For each found field f from table t such that it
+ participates at least in one index on table t a NOT NULL predicate is
+ constructed and a conjunction of all such predicates is attached to t.
+ If when looking for null-rejecting fields of t it is discovered one of its
+ fields has to be null-rejected and there is IS NULL conjunctive top level
+ predicate for this field then the function immediately returns true.
+ The function uses the bitmap TABLE::tmp_set to mark found null-rejected
+ fields of table t.
+
+ @note
+ Currently only top level conjuncts without disjunctive sub-formulas are
+ are taken into account when looking for null-rejected fields.
+
+ @retval
+ true if a contradiction is inferred
+ false otherwise
+*/
+
+static
+bool build_notnull_conds_for_range_scans(JOIN *join, Item *cond,
+ table_map allowed)
+{
+ THD *thd= join->thd;
+
+ DBUG_ENTER("build_notnull_conds_for_range_scans");
+
+ for (JOIN_TAB *s= join->join_tab + join->const_tables ;
+ s < join->join_tab + join->table_count ; s++)
+ {
+ /* Clear all needed bitmaps to mark found fields */
+ if (allowed & s->table->map)
+ bitmap_clear_all(&s->table->tmp_set);
+ }
+
+ /*
+ Find all null-rejected fields assuming that cond is null-rejected and
+ only formulas over tables from 'allowed' are to be taken into account
+ */
+ if (cond->find_not_null_fields(allowed))
+ DBUG_RETURN(true);
+
+ /*
+ For each table t from 'allowed' build a conjunction of NOT NULL predicates
+ constructed for all found fields if they are included in some indexes.
+ If the construction of the conjunction succeeds attach the formula to
+ t->table->notnull_cond. The condition will be used to look for complementary
+ range scans.
+ */
+ for (JOIN_TAB *s= join->join_tab + join->const_tables ;
+ s < join->join_tab + join->table_count ; s++)
+ {
+ TABLE *tab= s->table;
+ List<Item> notnull_list;
+ Item *notnull_cond= 0;
+
+ if (!(allowed & tab->map))
+ continue;
+
+ for (Field** field_ptr= tab->field; *field_ptr; field_ptr++)
+ {
+ Field *field= *field_ptr;
+ if (field->part_of_key.is_clear_all())
+ continue;
+ if (!bitmap_is_set(&tab->tmp_set, field->field_index))
+ continue;
+ Item_field *field_item= new (thd->mem_root) Item_field(thd, field);
+ if (!field_item)
+ continue;
+ Item *isnotnull_item=
+ new (thd->mem_root) Item_func_isnotnull(thd, field_item);
+ if (!isnotnull_item)
+ continue;
+ if (notnull_list.push_back(isnotnull_item, thd->mem_root))
+ continue;
+ s->const_keys.merge(field->part_of_key);
+ }
+
+ switch (notnull_list.elements) {
+ case 0:
+ break;
+ case 1:
+ notnull_cond= notnull_list.head();
+ break;
+ default:
+ notnull_cond=
+ new (thd->mem_root) Item_cond_and(thd, notnull_list);
+ }
+ if (notnull_cond && !notnull_cond->fix_fields(thd, 0))
+ {
+ tab->notnull_cond= notnull_cond;
+ }
+ }
+ DBUG_RETURN(false);
+}
+
+
+/**
+ @brief
+ Build not null conditions for inner nest tables of an outer join
+
+ @param join the join for whose table nest not null conditions are to be built
+ @param nest_tbl the nest of the inner tables of an outer join
+
+ @details
+ The function assumes that nest_tbl is the nest of the inner tables of an
+ outer join and so an ON expression for this outer join is attached to
+ nest_tbl.
+ The function selects the tables of the nest_tbl that are not inner tables of
+ embedded outer joins and then it calls build_notnull_conds_for_range_scans()
+ for nest_tbl->on_expr and the bitmap for the selected tables. This call
+ finds all fields belonging to the selected tables whose null-rejectedness
+ can be inferred from the null-rejectedness of nest_tbl->on_expr. After this
+ the function recursively finds all null_rejected fields for the remaining
+ tables from the nest of nest_tbl.
+*/
+
+static
+void build_notnull_conds_for_inner_nest_of_outer_join(JOIN *join,
+ TABLE_LIST *nest_tbl)
+{
+ TABLE_LIST *tbl;
+ table_map used_tables= 0;
+ THD *thd= join->thd;
+ List_iterator<TABLE_LIST> li(nest_tbl->nested_join->join_list);
+
+ while ((tbl= li++))
+ {
+ if (!tbl->on_expr)
+ used_tables|= tbl->table->map;
+ }
+ if (used_tables &&
+ build_notnull_conds_for_range_scans(join, nest_tbl->on_expr, used_tables))
+ {
+ Item *false_cond= new (thd->mem_root) Item_int(thd, (longlong) 0, 1);
+ if (false_cond)
+ nest_tbl->on_expr= false_cond;
+ }
+
+ li.rewind();
+ while ((tbl= li++))
+ {
+ if (tbl->on_expr)
+ {
+ if (tbl->nested_join)
+ {
+ build_notnull_conds_for_inner_nest_of_outer_join(join, tbl);
+ }
+ else if (build_notnull_conds_for_range_scans(join, tbl->on_expr,
+ tbl->table->map))
+ {
+ Item *false_cond= new (thd->mem_root) Item_int(thd, (longlong) 0, 1);
+ if (false_cond)
+ tbl->on_expr= false_cond;
+ }
+ }
+ }
+}
+
+
/**
@} (end of group Query_Optimizer)
*/
diff --git a/sql/sql_select.h b/sql/sql_select.h
index dd823a7..2b40a41 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -1749,6 +1749,7 @@ class JOIN :public Sql_alloc
void add_keyuses_for_splitting();
bool inject_best_splitting_cond(table_map remaining_tables);
bool fix_all_splittings_in_plan();
+ void make_notnull_conds_for_range_scans();
bool transform_in_predicates_into_in_subq(THD *thd);
private:
@@ -2343,7 +2344,7 @@ Item_equal *find_item_equal(COND_EQUAL *cond_equal, Field *field,
extern bool test_if_ref(Item *,
Item_field *left_item,Item *right_item);
-inline bool optimizer_flag(THD *thd, uint flag)
+inline bool optimizer_flag(THD *thd, ulonglong flag)
{
return (thd->variables.optimizer_switch & flag);
}
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index b50f697..58b6da5 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -2544,6 +2544,7 @@ export const char *optimizer_switch_names[]=
"orderby_uses_equalities",
"condition_pushdown_for_derived",
"split_materialized",
+ "not_null_range_scan",
"default",
NullS
};
diff --git a/sql/table.cc b/sql/table.cc
index 4805017..34fb6d5 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -4658,6 +4658,8 @@ void TABLE::init(THD *thd, TABLE_LIST *tl)
(*f_ptr)->cond_selectivity= 1.0;
}
+ notnull_cond= 0;
+
DBUG_ASSERT(!file->keyread_enabled());
restore_record(this, s->default_values);
diff --git a/sql/table.h b/sql/table.h
index fa6cb70..47096aa 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -1344,6 +1344,13 @@ struct TABLE
SplM_opt_info *spl_opt_info;
key_map keys_usable_for_splitting;
+ /*
+ Conjunction of the predicates of the form IS NOT NULL(f) where f refers to
+ a column of this TABLE such that they can be inferred from the condition
+ of the WHERE clause or from some ON expression of the processed select
+ and can be useful for range optimizer.
+ */
+ Item *notnull_cond;
inline void reset() { bzero((void*)this, sizeof(*this)); }
void init(THD *thd, TABLE_LIST *tl);
diff --git a/storage/tokudb/mysql-test/tokudb/r/ext_key_1_innodb.result b/storage/tokudb/mysql-test/tokudb/r/ext_key_1_innodb.result
index a80e166..5d471d2 100644
--- a/storage/tokudb/mysql-test/tokudb/r/ext_key_1_innodb.result
+++ b/storage/tokudb/mysql-test/tokudb/r/ext_key_1_innodb.result
@@ -1,7 +1,7 @@
drop table if exists t;
select @@optimizer_switch;
@@optimizer_switch
-index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
+index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,not_null_range_scan=off
create table t (id int not null, x int not null, y int not null, primary key(id), key(x)) engine=innodb;
insert into t values (0,0,0),(1,1,1),(2,2,2),(3,2,3),(4,2,4);
explain select x,id from t force index (x) where x=0 and id=0;
diff --git a/storage/tokudb/mysql-test/tokudb/r/ext_key_1_tokudb.result b/storage/tokudb/mysql-test/tokudb/r/ext_key_1_tokudb.result
index 96d6814..a3c518a 100644
--- a/storage/tokudb/mysql-test/tokudb/r/ext_key_1_tokudb.result
+++ b/storage/tokudb/mysql-test/tokudb/r/ext_key_1_tokudb.result
@@ -1,7 +1,7 @@
drop table if exists t;
select @@optimizer_switch;
@@optimizer_switch
-index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
+index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,not_null_range_scan=off
create table t (id int not null, x int not null, y int not null, primary key(id), key(x)) engine=tokudb;
insert into t values (0,0,0),(1,1,1),(2,2,2),(3,2,3),(4,2,4);
explain select x,id from t force index (x) where x=0 and id=0;
diff --git a/storage/tokudb/mysql-test/tokudb/r/ext_key_2_innodb.result b/storage/tokudb/mysql-test/tokudb/r/ext_key_2_innodb.result
index 43737c7..21dadb8 100644
--- a/storage/tokudb/mysql-test/tokudb/r/ext_key_2_innodb.result
+++ b/storage/tokudb/mysql-test/tokudb/r/ext_key_2_innodb.result
@@ -1,7 +1,7 @@
drop table if exists t;
select @@optimizer_switch;
@@optimizer_switch
-index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
+index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,not_null_range_scan=off
create table t (a int not null, b int not null, c int not null, d int not null, primary key(a,b), key(c,a)) engine=innodb;
insert into t values (0,0,0,0),(0,1,0,1);
explain select c,a,b from t where c=0 and a=0 and b=1;
diff --git a/storage/tokudb/mysql-test/tokudb/r/ext_key_2_tokudb.result b/storage/tokudb/mysql-test/tokudb/r/ext_key_2_tokudb.result
index 1dcb1ee..41c3f2b 100644
--- a/storage/tokudb/mysql-test/tokudb/r/ext_key_2_tokudb.result
+++ b/storage/tokudb/mysql-test/tokudb/r/ext_key_2_tokudb.result
@@ -1,7 +1,7 @@
drop table if exists t;
select @@optimizer_switch;
@@optimizer_switch
-index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on
+index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=off,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,not_null_range_scan=off
create table t (a int not null, b int not null, c int not null, d int not null, primary key(a,b), key(c,a)) engine=tokudb;
insert into t values (0,0,0,0),(0,1,0,1);
explain select c,a,b from t where c=0 and a=0 and b=1;
[View Less]
1
0

[Commits] c9fe6fb: Merge branch 'mdev-18844' of https://github.com/waynexia/server into mdev-18844
by IgorBabaev 01 Sep '19
by IgorBabaev 01 Sep '19
01 Sep '19
revision-id: c9fe6fbb61428e2d40f1de085ebdae505935b362 (mariadb-10.4.4-289-gc9fe6fb)
parent(s): 2707af2dec65ffd4195b9d79a233b1f298fe1756
author: Igor Babaev
committer: Igor Babaev
timestamp: 2019-08-31 22:44:58 -0700
message:
Merge branch 'mdev-18844' of https://github.com/waynexia/server into mdev-18844
---
sql/sql_union.cc | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 1abc81b..a7d0d08 100644
--- a/sql/sql_union.cc
+++ b/…
[View More]sql/sql_union.cc
@@ -858,7 +858,7 @@ bool select_unit_ext::send_eof()
}
if (curr_op_type == INTERSECT_ALL)
{
- longlong add_cnt= additional_cnt->val_int();
+ ha_rows add_cnt= (ha_rows)additional_cnt->val_int();
if (dup_cnt > add_cnt && add_cnt > 0)
dup_cnt= (ha_rows)add_cnt;
}
@@ -2171,7 +2171,8 @@ bool st_select_lex_unit::exec()
sl->tvc->exec(sl);
else
sl->join->exec();
- if (sl == union_distinct && !have_except_all_or_intersect_all)
+ if (sl == union_distinct && !have_except_all_or_intersect_all &&
+ !(with_element && with_element->is_recursive))
{
// This is UNION DISTINCT, so there should be a fake_select_lex
DBUG_ASSERT(fake_select_lex != NULL);
[View Less]
1
0

01 Sep '19
revision-id: 2707af2dec65ffd4195b9d79a233b1f298fe1756 (mariadb-10.4.4-288-g2707af2)
parent(s): 95f35bb75d8c3a518ee90ec82eb4e237c3b4e508
author: Ruihang Xia
committer: Igor Babaev
timestamp: 2019-08-31 18:58:01 -0700
message:
(1)mod: counter type from longlong to ha_rows
(2)fix: bug when call create tmp table
---
sql/sql_class.h | 2 +-
sql/sql_union.cc | 21 ++++++++-------------
2 files changed, 9 insertions(+), 14 deletions(-)
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 4820784.…
[View More].54d6541 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -5870,7 +5870,7 @@ class select_unit_ext :public select_unit
};
int send_data(List<Item> &items);
void change_select();
- int unfold_record(longlong cnt);
+ int unfold_record(ha_rows cnt);
bool send_eof();
bool force_enable_index_if_needed()
{
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 862b729..1abc81b 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -330,11 +330,6 @@ select_unit::create_result_table(THD *thd_arg, List<Item> *column_types,
tmp_table_param.bit_fields_as_long= bit_fields_as_long;
tmp_table_param.hidden_field_count= hidden;
- /*
- At least one of `duplicate_cnt` and `intersect_cnt` are used.
- in this case table can keep unique actually.
- */
- if (hidden > 0) is_union_distinct= true;
if (! (table= create_tmp_table(thd_arg, &tmp_table_param, *column_types,
(ORDER*) 0, is_union_distinct, 1,
options, HA_POS_ERROR, alias,
@@ -499,7 +494,7 @@ bool select_unit_ext::disable_index_if_needed(SELECT_LEX *curr_sl)
-1 conversion happened
*/
-int select_unit_ext::unfold_record(longlong cnt)
+int select_unit_ext::unfold_record(ha_rows cnt)
{
DBUG_ASSERT(cnt > 0);
@@ -840,7 +835,7 @@ bool select_unit_ext::send_eof()
else if (need_unfold)
{
/* unfold if is ALL operation */
- longlong dup_cnt;
+ ha_rows dup_cnt;
if (unlikely(table->file->ha_rnd_init_with_error(1)))
return 1;
do
@@ -854,7 +849,7 @@ bool select_unit_ext::send_eof()
}
break;
}
- dup_cnt= duplicate_cnt->val_int();
+ dup_cnt= (ha_rows)duplicate_cnt->val_int();
/* delete record if not exist in the second operand */
if (dup_cnt == 0)
{
@@ -865,7 +860,7 @@ bool select_unit_ext::send_eof()
{
longlong add_cnt= additional_cnt->val_int();
if (dup_cnt > add_cnt && add_cnt > 0)
- dup_cnt= add_cnt;
+ dup_cnt= (ha_rows)add_cnt;
}
if (dup_cnt == 1)
@@ -1576,9 +1571,7 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
if (join_union_item_types(thd, types, union_part_count + 1))
goto err;
if (union_result->create_result_table(thd, &types,
- MY_TEST(union_distinct) ||
- have_except_all_or_intersect_all ||
- have_intersect,
+ MY_TEST(union_distinct),
create_options,
&derived_arg->alias, false,
instantiate_tmp_table, false,
@@ -1698,7 +1691,9 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
}
bool error=
union_result->create_result_table(thd, &types,
- MY_TEST(union_distinct),
+ MY_TEST(union_distinct) ||
+ have_except_all_or_intersect_all ||
+ have_intersect,
create_options, &empty_clex_str, false,
instantiate_tmp_table, false,
hidden);
[View Less]
1
0
revision-id: 95f35bb75d8c3a518ee90ec82eb4e237c3b4e508 (mariadb-10.4.4-287-g95f35bb)
parent(s): a896bebfa6d00b0bb7685956196a7977d9273652
author: Ruihang Xia
committer: Igor Babaev
timestamp: 2019-08-31 18:56:50 -0700
message:
(1) fix type error
(2) remove empty "--error ER_PARSE_ERROR"
(3) change three members in class select_unit to protected.
---
mysql-test/main/except.test | 1 -
mysql-test/main/intersect.test | 1 -
sql/sql_class.h | 4 ++--
sql/sql_union.cc …
[View More] | 2 +-
4 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/mysql-test/main/except.test b/mysql-test/main/except.test
index 702502c..de387cc 100644
--- a/mysql-test/main/except.test
+++ b/mysql-test/main/except.test
@@ -66,7 +66,6 @@ select 1 as a from dual except select 1 from dual;
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
create table t1 (a int, b blob, a1 int, b1 blob) engine=MyISAM;
diff --git a/mysql-test/main/intersect.test b/mysql-test/main/intersect.test
index b420aa2..a99aa92 100644
--- a/mysql-test/main/intersect.test
+++ b/mysql-test/main/intersect.test
@@ -65,7 +65,6 @@ select 1 as a from dual intersect select 1 from dual;
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
diff --git a/sql/sql_class.h b/sql/sql_class.h
index f59afe5..4820784 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -5708,7 +5708,7 @@ class TMP_TABLE_PARAM :public Sql_alloc
class select_unit :public select_result_interceptor
{
-public:
+protected:
uint curr_step, prev_step, curr_sel;
enum sub_select_type step;
public:
@@ -5870,7 +5870,7 @@ class select_unit_ext :public select_unit
};
int send_data(List<Item> &items);
void change_select();
- int unfold_record(int cnt);
+ int unfold_record(longlong cnt);
bool send_eof();
bool force_enable_index_if_needed()
{
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 1bd65f8..862b729 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -499,7 +499,7 @@ bool select_unit_ext::disable_index_if_needed(SELECT_LEX *curr_sl)
-1 conversion happened
*/
-int select_unit_ext::unfold_record(int cnt)
+int select_unit_ext::unfold_record(longlong cnt)
{
DBUG_ASSERT(cnt > 0);
[View Less]
1
0

[Commits] d541c7f: MDEV-18844 Implement EXCEPT ALL and INTERSECT ALL operations
by IgorBabaev 01 Sep '19
by IgorBabaev 01 Sep '19
01 Sep '19
revision-id: d541c7f846621789ffa1fd515568db9192a7c5af (mariadb-10.4.4-286-gd541c7f)
parent(s): afe969ba05faece41fdef1275e9b9c510081805b
author: Ruihang Xia
committer: Igor Babaev
timestamp: 2019-08-31 17:50:58 -0700
message:
MDEV-18844 Implement EXCEPT ALL and INTERSECT ALL operations
---
mysql-test/main/brackets.result | 2 +-
mysql-test/main/except.result | 2 -
mysql-test/main/except.test | 2 -
mysql-test/main/except_all.result …
[View More]| 660 +++++++++++++++
mysql-test/main/except_all.test | 99 +++
mysql-test/main/intersect.result | 44 +-
mysql-test/main/intersect.test | 22 +-
mysql-test/main/intersect_all.result | 888 ++++++++++++++++++++
mysql-test/main/intersect_all.test | 328 ++++++++
mysql-test/main/set_operation.result | 1157 +++++++++++++++++++++++++++
mysql-test/main/set_operation.test | 526 ++++++++++++
mysql-test/main/set_operation_oracle.result | 75 ++
mysql-test/main/set_operation_oracle.test | 65 ++
sql/sql_class.h | 151 +++-
sql/sql_lex.cc | 15 +-
sql/sql_lex.h | 40 +-
sql/sql_tvc.cc | 1 +
sql/sql_union.cc | 947 ++++++++++++++++++----
sql/sql_yacc.yy | 8 +-
storage/heap/hp_write.c | 26 +-
20 files changed, 4807 insertions(+), 251 deletions(-)
diff --git a/mysql-test/main/brackets.result b/mysql-test/main/brackets.result
index e14bef9..8fc54e6 100644
--- a/mysql-test/main/brackets.result
+++ b/mysql-test/main/brackets.result
@@ -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
diff --git a/mysql-test/main/except.result b/mysql-test/main/except.result
index 9c5a3ea..3416ad0 100644
--- a/mysql-test/main/except.result
+++ b/mysql-test/main/except.result
@@ -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");
diff --git a/mysql-test/main/except.test b/mysql-test/main/except.test
index 32aa0b9..de387cc 100644
--- a/mysql-test/main/except.test
+++ b/mysql-test/main/except.test
@@ -66,8 +66,6 @@ select 1 as a from dual except select 1 from dual;
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;
diff --git a/mysql-test/main/except_all.result b/mysql-test/main/except_all.result
new file mode 100644
index 0000000..19ff9f3
--- /dev/null
+++ b/mysql-test/main/except_all.result
@@ -0,0 +1,660 @@
+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;
+a b
+4 4
+select * from t1 except all select * from t2;
+a b
+4 4
+2 2
+4 4
+4 4
+select * from t1 except all select c+1,d+1 from t2;
+a b
+1 1
+4 4
+(select * from t1) except all (select * from t2);
+a b
+4 4
+2 2
+4 4
+4 4
+select * from ((select * from t1) except all (select * from t2)) a;
+a b
+4 4
+2 2
+4 4
+4 4
+select * from ((select a from t1) except all (select c from t2)) a;
+a
+4
+2
+4
+4
+select * from t1 except all select * from t1 union all select * from t1 union all select * from t1 except select * from t2;
+a b
+4 4
+select * from t1 except all select * from t1 union all select * from t1 union all select * from t1 except all select * from t2;
+a b
+4 4
+2 2
+4 4
+4 4
+4 4
+4 4
+4 4
+2 2
+2 2
+select * from (select * from t1 except all select * from t2) q1 except all select * from (select * from t1 except all select * from t2) q2;
+a b
+EXPLAIN select * from t1 except all select * from t2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 7
+2 EXCEPT t2 ALL NULL NULL NULL NULL 7
+NULL EXCEPT RESULT <except1,2> ALL NULL NULL NULL NULL NULL
+EXPLAIN format=json select * from t1 except all select * from t2;
+EXPLAIN
+{
+ "query_block": {
+ "union_result": {
+ "table_name": "<except1,2>",
+ "access_type": "ALL",
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 7,
+ "filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 2,
+ "operation": "EXCEPT",
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 7,
+ "filtered": 100
+ }
+ }
+ }
+ ]
+ }
+ }
+}
+EXPLAIN extended (select * from t1) except all (select * from t2);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 7 100.00
+2 EXCEPT t2 ALL NULL NULL NULL NULL 7 100.00
+NULL EXCEPT RESULT <except1,2> 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`) except all (/* select#2 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2`)
+EXPLAIN extended select * from ((select * from t1) except all (select * from t2)) a;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 7 100.00
+2 DERIVED t1 ALL NULL NULL NULL NULL 7 100.00
+3 EXCEPT t2 ALL NULL NULL NULL NULL 7 100.00
+NULL EXCEPT RESULT <except2,3> ALL NULL NULL NULL NULL NULL NULL
+Warnings:
+Note 1003 /* select#1 */ select `a`.`a` AS `a`,`a`.`b` AS `b` from (/* select#2 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` except all (/* select#3 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2`)) `a`
+ANALYZE format=json select * from ((select a,b from t1) except all (select c,d from t2)) a;
+ANALYZE
+{
+ "query_block": {
+ "select_id": 1,
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 7,
+ "r_rows": 4,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100,
+ "materialized": {
+ "query_block": {
+ "union_result": {
+ "table_name": "<except2,3>",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "r_rows": 4,
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 2,
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 7,
+ "r_rows": 7,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 3,
+ "operation": "EXCEPT",
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 7,
+ "r_rows": 7,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+}
+ANALYZE format=json select * from ((select a from t1) except all (select c from t2)) a;
+ANALYZE
+{
+ "query_block": {
+ "select_id": 1,
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 7,
+ "r_rows": 4,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100,
+ "materialized": {
+ "query_block": {
+ "union_result": {
+ "table_name": "<except2,3>",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "r_rows": 4,
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 2,
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 7,
+ "r_rows": 7,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 3,
+ "operation": "EXCEPT",
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 7,
+ "r_rows": 7,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+}
+select * from ((select a from t1) except all (select c from t2)) a;
+a
+4
+2
+4
+4
+prepare stmt from "(select a,b from t1) except all (select c,d from t2)";
+execute stmt;
+a b
+4 4
+2 2
+4 4
+4 4
+execute stmt;
+a b
+4 4
+2 2
+4 4
+4 4
+prepare stmt from "select * from ((select a,b from t1) except all (select c,d from t2)) a";
+execute stmt;
+a b
+4 4
+2 2
+4 4
+4 4
+execute stmt;
+a b
+4 4
+2 2
+4 4
+4 4
+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);
+a b e f
+1 1 4 4
+2 2 4 4
+1 1 5 5
+2 2 5 5
+1 1 4 4
+2 2 4 4
+2 2 5 5
+select * from ((select a,b,e,f from t1,t3) except all (select c,d,g,h from t2,t4)) t;
+a b e f
+1 1 4 4
+2 2 4 4
+1 1 5 5
+2 2 5 5
+1 1 4 4
+2 2 4 4
+2 2 5 5
+(select * from t1,t3) except all (select * from t2,t4);
+a b e f
+1 1 4 4
+2 2 4 4
+1 1 5 5
+2 2 5 5
+1 1 4 4
+2 2 4 4
+2 2 5 5
+(select a,b,e from t1,t3) except all (select c,d,g from t2,t4);
+a b e
+1 1 4
+2 2 4
+1 1 5
+2 2 5
+1 1 4
+2 2 4
+2 2 5
+EXPLAIN (select a,b,e,f from t1,t3) except all (select c,d,g,h from t2,t4);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3
+1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using join buffer (flat, BNL join)
+2 EXCEPT t2 ALL NULL NULL NULL NULL 2
+2 EXCEPT t4 ALL NULL NULL NULL NULL 3 Using join buffer (flat, BNL join)
+NULL EXCEPT RESULT <except1,2> ALL NULL NULL NULL NULL NULL
+EXPLAIN select * from ((select a,b,e,f from t1,t3) except all (select c,d,g,h from t2,t4)) t;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 9
+2 DERIVED t1 ALL NULL NULL NULL NULL 3
+2 DERIVED t3 ALL NULL NULL NULL NULL 3 Using join buffer (flat, BNL join)
+3 EXCEPT t2 ALL NULL NULL NULL NULL 2
+3 EXCEPT t4 ALL NULL NULL NULL NULL 3 Using join buffer (flat, BNL join)
+NULL EXCEPT RESULT <except2,3> ALL NULL NULL NULL NULL NULL
+EXPLAIN extended select * from ((select a,b,e,f from t1,t3) except all (select c,d,g,h from t2,t4)) t;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 9 100.00
+2 DERIVED t1 ALL NULL NULL NULL NULL 3 100.00
+2 DERIVED t3 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join)
+3 EXCEPT t2 ALL NULL NULL NULL NULL 2 100.00
+3 EXCEPT t4 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join)
+NULL EXCEPT RESULT <except2,3> ALL NULL NULL NULL NULL NULL NULL
+Warnings:
+Note 1003 /* select#1 */ select `t`.`a` AS `a`,`t`.`b` AS `b`,`t`.`e` AS `e`,`t`.`f` AS `f` from (/* select#2 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t1` join `test`.`t3` except all (/* select#3 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d`,`test`.`t4`.`g` AS `g`,`test`.`t4`.`h` AS `h` from `test`.`t2` join `test`.`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;
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ALL",
+ "rows": 9,
+ "filtered": 100,
+ "materialized": {
+ "query_block": {
+ "union_result": {
+ "table_name": "<except2,3>",
+ "access_type": "ALL",
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 2,
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 3,
+ "filtered": 100
+ },
+ "block-nl-join": {
+ "table": {
+ "table_name": "t3",
+ "access_type": "ALL",
+ "rows": 3,
+ "filtered": 100
+ },
+ "buffer_type": "flat",
+ "buffer_size": "119",
+ "join_type": "BNL"
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 3,
+ "operation": "EXCEPT",
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 2,
+ "filtered": 100
+ },
+ "block-nl-join": {
+ "table": {
+ "table_name": "t4",
+ "access_type": "ALL",
+ "rows": 3,
+ "filtered": 100
+ },
+ "buffer_type": "flat",
+ "buffer_size": "119",
+ "join_type": "BNL"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+}
+ANALYZE format=json (select a,b,e,f from t1,t3) except all (select c,d,g,h from t2,t4);
+ANALYZE
+{
+ "query_block": {
+ "union_result": {
+ "table_name": "<except1,2>",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "r_rows": 7,
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 1,
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 3,
+ "r_rows": 3,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ },
+ "block-nl-join": {
+ "table": {
+ "table_name": "t3",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 3,
+ "r_rows": 3,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ },
+ "buffer_type": "flat",
+ "buffer_size": "119",
+ "join_type": "BNL",
+ "r_filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 2,
+ "operation": "EXCEPT",
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 2,
+ "r_rows": 2,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ },
+ "block-nl-join": {
+ "table": {
+ "table_name": "t4",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 3,
+ "r_rows": 3,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ },
+ "buffer_type": "flat",
+ "buffer_size": "119",
+ "join_type": "BNL",
+ "r_filtered": 100
+ }
+ }
+ }
+ ]
+ }
+ }
+}
+ANALYZE format=json select * from ((select a,b,e,f from t1,t3) except all (select c,d,g,h from t2,t4)) t;
+ANALYZE
+{
+ "query_block": {
+ "select_id": 1,
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 9,
+ "r_rows": 7,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100,
+ "materialized": {
+ "query_block": {
+ "union_result": {
+ "table_name": "<except2,3>",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "r_rows": 7,
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 2,
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 3,
+ "r_rows": 3,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ },
+ "block-nl-join": {
+ "table": {
+ "table_name": "t3",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 3,
+ "r_rows": 3,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ },
+ "buffer_type": "flat",
+ "buffer_size": "119",
+ "join_type": "BNL",
+ "r_filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 3,
+ "operation": "EXCEPT",
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 2,
+ "r_rows": 2,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ },
+ "block-nl-join": {
+ "table": {
+ "table_name": "t4",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 3,
+ "r_rows": 3,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ },
+ "buffer_type": "flat",
+ "buffer_size": "119",
+ "join_type": "BNL",
+ "r_filtered": 100
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+}
+prepare stmt from "(select a,b,e,f from t1,t3) except all (select c,d,g,h from t2,t4)";
+execute stmt;
+a b e f
+1 1 4 4
+2 2 4 4
+1 1 5 5
+2 2 5 5
+1 1 4 4
+2 2 4 4
+2 2 5 5
+execute stmt;
+a b e f
+1 1 4 4
+2 2 4 4
+1 1 5 5
+2 2 5 5
+1 1 4 4
+2 2 4 4
+2 2 5 5
+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;
+a b e f
+1 1 4 4
+2 2 4 4
+1 1 5 5
+2 2 5 5
+1 1 4 4
+2 2 4 4
+2 2 5 5
+execute stmt;
+a b e f
+1 1 4 4
+2 2 4 4
+1 1 5 5
+2 2 5 5
+1 1 4 4
+2 2 4 4
+2 2 5 5
+drop tables t1,t2,t3,t4;
+select 1 as a from dual except all select 1 from dual;
+a
+(select 1 from dual) except all (select 1 from dual);
+1
+(select 1 from dual into @v) 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 'into @v) except all (select 1 from dual)' at line 1
+select 1 from dual ORDER BY 1 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 'except all select 1 from dual' at line 1
+select 1 as a from dual union all select 1 from dual;
+a
+1
+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"),(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);
+a b b1
+1 ddd sdfrrwwww
+2 fgh dffggtt
+create table t3 (select a,b,b1 from t1) except all (select c,d,d1 from t2);
+show create table t3;
+Table Create Table
+t3 CREATE TABLE `t3` (
+ `a` int(11) DEFAULT NULL,
+ `b` blob DEFAULT NULL,
+ `b1` blob DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+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 );
+i
+drop table t;
diff --git a/mysql-test/main/except_all.test b/mysql-test/main/except_all.test
new file mode 100644
index 0000000..f873b22
--- /dev/null
+++ b/mysql-test/main/except_all.test
@@ -0,0 +1,99 @@
+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
diff --git a/mysql-test/main/intersect.result b/mysql-test/main/intersect.result
index bd88243..034018d 100644
--- a/mysql-test/main/intersect.result
+++ b/mysql-test/main/intersect.result
@@ -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
diff --git a/mysql-test/main/intersect.test b/mysql-test/main/intersect.test
index 616a833..a99aa92 100644
--- a/mysql-test/main/intersect.test
+++ b/mysql-test/main/intersect.test
@@ -65,8 +65,6 @@ select 1 as a from dual intersect select 1 from dual;
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 +145,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 +152,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 +296,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 +315,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
diff --git a/mysql-test/main/intersect_all.result b/mysql-test/main/intersect_all.result
new file mode 100644
index 0000000..66ee060
--- /dev/null
+++ b/mysql-test/main/intersect_all.result
@@ -0,0 +1,888 @@
+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;
+a b
+2 2
+2 2
+(select a,b from t1) intersect all (select c,d from t2);
+a b
+2 2
+2 2
+select * from ((select a,b from t1) intersect all (select c,d from t2)) t;
+a b
+2 2
+2 2
+select * from ((select a from t1) intersect all (select c from t2)) t;
+a
+2
+2
+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);
+a b
+2 2
+2 2
+EXPLAIN (select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 4
+2 INTERSECT t2 ALL NULL NULL NULL NULL 4
+3 INTERSECT t3 ALL NULL NULL NULL NULL 4
+NULL INTERSECT RESULT <intersect1,2,3> ALL NULL NULL NULL NULL NULL
+EXPLAIN extended (select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 4 100.00
+2 INTERSECT t2 ALL NULL NULL NULL NULL 4 100.00
+3 INTERSECT t3 ALL NULL NULL NULL NULL 4 100.00
+NULL INTERSECT RESULT <intersect1,2,3> 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`) intersect all (/* select#2 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2`) intersect all (/* select#3 */ select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`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;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 4 100.00
+2 DERIVED t1 ALL NULL NULL NULL NULL 4 100.00
+3 INTERSECT t2 ALL NULL NULL NULL NULL 4 100.00
+4 INTERSECT t3 ALL NULL NULL NULL NULL 4 100.00
+NULL INTERSECT RESULT <intersect2,3,4> ALL NULL NULL NULL NULL NULL NULL
+Warnings:
+Note 1003 /* select#1 */ select `a`.`a` AS `a`,`a`.`b` AS `b` from (/* select#2 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` intersect all (/* select#3 */ 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`)) `a`
+EXPLAIN format=json (select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3);
+EXPLAIN
+{
+ "query_block": {
+ "union_result": {
+ "table_name": "<intersect1,2,3>",
+ "access_type": "ALL",
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 4,
+ "filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 2,
+ "operation": "INTERSECT",
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 4,
+ "filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 3,
+ "operation": "INTERSECT",
+ "table": {
+ "table_name": "t3",
+ "access_type": "ALL",
+ "rows": 4,
+ "filtered": 100
+ }
+ }
+ }
+ ]
+ }
+ }
+}
+ANALYZE format=json (select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3);
+ANALYZE
+{
+ "query_block": {
+ "union_result": {
+ "table_name": "<intersect1,2,3>",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "r_rows": 2,
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 1,
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 4,
+ "r_rows": 4,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 2,
+ "operation": "INTERSECT",
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 4,
+ "r_rows": 4,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 3,
+ "operation": "INTERSECT",
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t3",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 4,
+ "r_rows": 4,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ }
+ }
+ }
+ ]
+ }
+ }
+}
+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;
+ANALYZE
+{
+ "query_block": {
+ "select_id": 1,
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 4,
+ "r_rows": 2,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100,
+ "materialized": {
+ "query_block": {
+ "union_result": {
+ "table_name": "<intersect2,3,4>",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "r_rows": 2,
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 2,
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 4,
+ "r_rows": 4,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 3,
+ "operation": "INTERSECT",
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 4,
+ "r_rows": 4,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 4,
+ "operation": "INTERSECT",
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t3",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 4,
+ "r_rows": 4,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+}
+select * from ((select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3)) a;
+a b
+2 2
+2 2
+prepare stmt from "(select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3);";
+execute stmt;
+a b
+2 2
+2 2
+execute stmt;
+a b
+2 2
+2 2
+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;
+a b
+2 2
+2 2
+execute stmt;
+a b
+2 2
+2 2
+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);
+a b
+2 2
+2 2
+(select a,b from t1) intersect (select c,d from t2) intersect all (select e,f from t3);
+a b
+2 2
+insert into t3 values (2,2);
+(select a,b from t1) intersect all (select c,d from t2) intersect (select e,f from t3);
+a b
+2 2
+(select a,b from t1) intersect all (select c,e from t2,t3);
+a b
+2 2
+2 2
+2 2
+EXPLAIN (select a,b from t1) intersect all (select c,e from t2,t3);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6
+2 INTERSECT t3 ALL NULL NULL NULL NULL 5
+2 INTERSECT t2 ALL NULL NULL NULL NULL 7 Using join buffer (flat, BNL join)
+NULL INTERSECT RESULT <intersect1,2> ALL NULL NULL NULL NULL NULL
+EXPLAIN extended (select a,b from t1) intersect all (select c,e from t2,t3);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00
+2 INTERSECT t3 ALL NULL NULL NULL NULL 5 100.00
+2 INTERSECT t2 ALL NULL NULL NULL NULL 7 100.00 Using join buffer (flat, BNL join)
+NULL INTERSECT RESULT <intersect1,2> 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`) intersect all (/* select#2 */ select `test`.`t2`.`c` AS `c`,`test`.`t3`.`e` AS `e` from `test`.`t2` join `test`.`t3`)
+EXPLAIN extended select * from ((select a,b from t1) intersect all (select c,e from t2,t3)) a;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 6 100.00
+2 DERIVED t1 ALL NULL NULL NULL NULL 6 100.00
+3 INTERSECT t3 ALL NULL NULL NULL NULL 5 100.00
+3 INTERSECT t2 ALL NULL NULL NULL NULL 7 100.00 Using join buffer (flat, BNL join)
+NULL INTERSECT RESULT <intersect2,3> ALL NULL NULL NULL NULL NULL NULL
+Warnings:
+Note 1003 /* select#1 */ select `a`.`a` AS `a`,`a`.`b` AS `b` from (/* select#2 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` intersect all (/* select#3 */ select `test`.`t2`.`c` AS `c`,`test`.`t3`.`e` AS `e` from `test`.`t2` join `test`.`t3`)) `a`
+EXPLAIN format=json (select a,b from t1) intersect all (select c,e from t2,t3);
+EXPLAIN
+{
+ "query_block": {
+ "union_result": {
+ "table_name": "<intersect1,2>",
+ "access_type": "ALL",
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 6,
+ "filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 2,
+ "operation": "INTERSECT",
+ "table": {
+ "table_name": "t3",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100
+ },
+ "block-nl-join": {
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 7,
+ "filtered": 100
+ },
+ "buffer_type": "flat",
+ "buffer_size": "65",
+ "join_type": "BNL"
+ }
+ }
+ }
+ ]
+ }
+ }
+}
+ANALYZE format=json (select a,b from t1) intersect all (select c,e from t2,t3);
+ANALYZE
+{
+ "query_block": {
+ "union_result": {
+ "table_name": "<intersect1,2>",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "r_rows": 3,
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 1,
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 6,
+ "r_rows": 6,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 2,
+ "operation": "INTERSECT",
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t3",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 5,
+ "r_rows": 5,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ },
+ "block-nl-join": {
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 7,
+ "r_rows": 7,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ },
+ "buffer_type": "flat",
+ "buffer_size": "65",
+ "join_type": "BNL",
+ "r_filtered": 100
+ }
+ }
+ }
+ ]
+ }
+ }
+}
+ANALYZE format=json select * from ((select a,b from t1) intersect all (select c,e from t2,t3)) a;
+ANALYZE
+{
+ "query_block": {
+ "select_id": 1,
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 6,
+ "r_rows": 3,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100,
+ "materialized": {
+ "query_block": {
+ "union_result": {
+ "table_name": "<intersect2,3>",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "r_rows": 3,
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 2,
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 6,
+ "r_rows": 6,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 3,
+ "operation": "INTERSECT",
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t3",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 5,
+ "r_rows": 5,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ },
+ "block-nl-join": {
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 7,
+ "r_rows": 7,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ },
+ "buffer_type": "flat",
+ "buffer_size": "65",
+ "join_type": "BNL",
+ "r_filtered": 100
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+}
+select * from ((select a,b from t1) intersect all (select c,e from t2,t3)) a;
+a b
+2 2
+2 2
+2 2
+prepare stmt from "(select a,b from t1) intersect all (select c,e from t2,t3);";
+execute stmt;
+a b
+2 2
+2 2
+2 2
+execute stmt;
+a b
+2 2
+2 2
+2 2
+prepare stmt from "select * from ((select a,b from t1) intersect all (select c,e from t2,t3)) a";
+execute stmt;
+a b
+2 2
+2 2
+2 2
+execute stmt;
+a b
+2 2
+2 2
+2 2
+drop tables t1,t2,t3;
+select 1 as a from dual intersect all select 1 from dual;
+a
+1
+(select 1 from dual) intersect all (select 1 from dual);
+1
+1
+(select 1 from dual into @v) 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 'into @v) intersect all (select 1 from dual)' at line 1
+select 1 from dual ORDER BY 1 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 'intersect all select 1 from dual' at line 1
+select 1 as a from dual union all select 1 from dual;
+a
+1
+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"),(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);
+a b b1
+2 fgh dffggtt
+2 fgh dffggtt
+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);
+a b
+2 2
+2 2
+select * from ((select a,b from t1) intersect all (select c,d from t2) intersect (select e,f from t3)) a;
+a b
+2 2
+prepare stmt from "(select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3);";
+execute stmt;
+a b
+2 2
+2 2
+execute stmt;
+a b
+2 2
+2 2
+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;
+a b
+2 2
+2 2
+execute stmt;
+a b
+2 2
+2 2
+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;
+Table Create Table
+t4 CREATE TABLE `t4` (
+ `a` int(11) DEFAULT NULL,
+ `b` blob DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+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);
+a b
+4 4
+2 2
+2 2
+(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);
+a b
+4 4
+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);
+a b
+4 4
+2 2
+2 2
+(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);
+a b
+4 4
+2 2
+drop tables t1,t2,t3;
+#
+# INTERSECT precedence
+#
+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);
+a b
+5 5
+6 6
+3 3
+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);
+a b
+5 5
+6 6
+3 3
+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);
+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
+5 UNION <derived2> ALL NULL NULL NULL NULL 2 100.00
+2 DERIVED t2 ALL NULL NULL NULL NULL 2 100.00
+3 INTERSECT t3 ALL NULL NULL NULL NULL 2 100.00
+NULL INTERSECT RESULT <intersect2,3> ALL NULL NULL NULL NULL NULL NULL
+4 UNION NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 (/* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1`) union all /* 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 all (/* select#3 */ select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3`)) `__5` union all (/* select#4 */ select 4 AS `4`,4 AS `4`)
+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);
+e f
+3 3
+3 3
+5 5
+6 6
+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);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00
+2 INTERSECT t2 ALL NULL NULL NULL NULL 3 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 all (/* select#2 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2`) union all (/* select#3 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1`) union all (/* select#4 */ select 4 AS `4`,4 AS `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`);
+a b
+5 5
+6 6
+3 3
+4 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;
+a b
+5 5
+6 6
+3 3
+3 3
+4 4
+execute stmt;
+a b
+5 5
+6 6
+3 3
+3 3
+4 4
+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;
+b a b+1
+5 5 6
+6 6 7
+3 3 4
+3 3 4
+4 4 5
+select b,a,b+1 from v1 where a > 3;
+b a b+1
+5 5 6
+6 6 7
+4 4 5
+create procedure p1()
+select * from v1;
+call p1();
+a b
+5 5
+6 6
+3 3
+3 3
+4 4
+call p1();
+a b
+5 5
+6 6
+3 3
+3 3
+4 4
+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();
+a b
+5 5
+6 6
+3 3
+3 3
+4 4
+call p1();
+a b
+5 5
+6 6
+3 3
+3 3
+4 4
+drop procedure p1;
+show create view v1;
+View Create View character_set_client collation_connection
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS (select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1`) union all select `__6`.`c` AS `c`,`__6`.`d` AS `d` from (select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` intersect all (select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3`)) `__6` union all (select 4 AS `4`,4 AS `4`) latin1 latin1_swedish_ci
+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 );
+i
+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));
+i
+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;
+count(*)
+14848
+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;
+count(*)
+14848
+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;
+count(*)
+16430
+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;
+count(*)
+15547
+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;
+c1
+1
+3
+2
+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;
+a
+7
+7
+2
+1
+2
+explain extended
+select * from t1 where a > 4
+union all
+select * from t2 where a < 5
+intersect all
+select * from t3 where a < 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 7 100.00 Using where
+4 UNION <derived2> ALL NULL NULL NULL NULL 7 100.00
+2 DERIVED t2 ALL NULL NULL NULL NULL 8 100.00 Using where
+3 INTERSECT t3 ALL NULL NULL NULL NULL 7 100.00 Using where
+NULL INTERSECT RESULT <intersect2,3> ALL NULL NULL NULL NULL NULL NULL
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` > 4 union all /* select#4 */ select `__4`.`a` AS `a` from (/* select#2 */ select `test`.`t2`.`a` AS `a` from `test`.`t2` where `test`.`t2`.`a` < 5 intersect all /* select#3 */ select `test`.`t3`.`a` AS `a` from `test`.`t3` where `test`.`t3`.`a` < 5) `__4`
+drop table t1,t2,t3;
diff --git a/mysql-test/main/intersect_all.test b/mysql-test/main/intersect_all.test
new file mode 100644
index 0000000..5d2b038
--- /dev/null
+++ b/mysql-test/main/intersect_all.test
@@ -0,0 +1,328 @@
+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;
\ No newline at end of file
diff --git a/mysql-test/main/set_operation.result b/mysql-test/main/set_operation.result
new file mode 100644
index 0000000..a021033
--- /dev/null
+++ b/mysql-test/main/set_operation.result
@@ -0,0 +1,1157 @@
+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),(3,3),(2,2),(3,3);
+insert into t2 values (2,2),(3,3),(5,5),(2,2),(2,2),(3,3);
+insert into t3 values (4,4),(2,2),(2,2),(1,1),(3,3);
+insert into t4 values (2,2),(4,4),(1,1);
+create view v0(g, h) as select a,c from t1,t2;
+# test optimization
+select * from t1
+INTERSECT ALL
+select * from t2
+INTERSECT ALL
+select * from t3;
+a b
+2 2
+2 2
+3 3
+EXPLAIN EXTENDED select * from t1
+INTERSECT ALL
+select * from t2
+INTERSECT ALL
+select * from t3;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5 100.00
+2 INTERSECT t2 ALL NULL NULL NULL NULL 6 100.00
+3 INTERSECT t3 ALL NULL NULL NULL NULL 5 100.00
+NULL INTERSECT RESULT <intersect1,2,3> 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` intersect all /* select#2 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` intersect all /* select#3 */ select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3`
+select * from t1
+INTERSECT ALL
+select * from t2
+INTERSECT ALL
+select * from t3
+INTERSECT
+select * from t1;
+a b
+2 2
+3 3
+EXPLAIN EXTENDED select * from t1
+INTERSECT ALL
+select * from t2
+INTERSECT ALL
+select * from t3
+INTERSECT
+select * from t1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5 100.00
+2 INTERSECT t2 ALL NULL NULL NULL NULL 6 100.00
+3 INTERSECT t3 ALL NULL NULL NULL NULL 5 100.00
+4 INTERSECT t1 ALL NULL NULL NULL NULL 5 100.00
+NULL INTERSECT RESULT <intersect1,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` intersect /* 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` intersect /* select#4 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1`
+select * from t1
+INTERSECT ALL
+select * from t2
+INTERSECT ALL
+select * from t3
+EXCEPT ALL
+select * from t4;
+a b
+2 2
+3 3
+EXPLAIN EXTENDED select * from t1
+INTERSECT ALL
+select * from t2
+INTERSECT ALL
+select * from t3
+EXCEPT ALL
+select * from t4;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5 100.00
+2 INTERSECT t2 ALL NULL NULL NULL NULL 6 100.00
+3 INTERSECT t3 ALL NULL NULL NULL NULL 5 100.00
+4 EXCEPT t4 ALL NULL NULL NULL NULL 3 100.00
+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` intersect all /* select#2 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` intersect all /* select#3 */ select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3` except all /* select#4 */ select `test`.`t4`.`g` AS `g`,`test`.`t4`.`h` AS `h` from `test`.`t4`
+select * from t1
+INTERSECT
+select * from t2
+EXCEPT ALL
+select * from t4;
+a b
+3 3
+EXPLAIN EXTENDED select * from t1
+INTERSECT
+select * from t2
+EXCEPT ALL
+select * from t4;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5 100.00
+2 INTERSECT t2 ALL NULL NULL NULL NULL 6 100.00
+3 EXCEPT t4 ALL NULL NULL NULL NULL 3 100.00
+NULL UNIT RESULT <unit1,2,3> 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` intersect /* select#2 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` except /* select#3 */ select `test`.`t4`.`g` AS `g`,`test`.`t4`.`h` AS `h` from `test`.`t4`
+insert into t4 values (1,1),(9,9);
+select * from t1
+UNION ALL
+select * from t2
+UNION ALL
+select * from t3
+EXCEPT
+select * from t4;
+a b
+3 3
+5 5
+EXPLAIN EXTENDED select * from t1
+UNION ALL
+select * from t2
+UNION ALL
+select * from t3
+EXCEPT
+select * from t4;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5 100.00
+2 UNION t2 ALL NULL NULL NULL NULL 6 100.00
+3 UNION t3 ALL NULL NULL NULL NULL 5 100.00
+4 EXCEPT t4 ALL NULL NULL NULL NULL 5 100.00
+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` union /* select#3 */ select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3` except /* select#4 */ select `test`.`t4`.`g` AS `g`,`test`.`t4`.`h` AS `h` from `test`.`t4`
+delete from t4;
+insert into t4 values (3,3),(3,3);
+select * from t1
+INTERSECT ALL
+select * from t2
+UNION ALL
+select * from t3
+EXCEPT ALL
+select * from t1
+UNION
+select * from t4
+EXCEPT
+select * from t3
+UNION ALL
+select * from t1;
+a b
+2 2
+2 2
+1 1
+3 3
+3 3
+EXPLAIN EXTENDED select * from t1
+INTERSECT ALL
+select * from t2
+UNION ALL
+select * from t3
+EXCEPT ALL
+select * from t1
+UNION
+select * from t4
+EXCEPT
+select * from t3
+UNION ALL
+select * from t1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5 100.00
+2 INTERSECT t2 ALL NULL NULL NULL NULL 6 100.00
+3 UNION t3 ALL NULL NULL NULL NULL 5 100.00
+4 EXCEPT t1 ALL NULL NULL NULL NULL 5 100.00
+5 UNION t4 ALL NULL NULL NULL NULL 2 100.00
+6 EXCEPT t3 ALL NULL NULL NULL NULL 5 100.00
+7 UNION t1 ALL NULL NULL NULL NULL 5 100.00
+NULL UNIT RESULT <unit1,2,3,4,5,6,7> 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` intersect all /* select#2 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` union all /* select#3 */ select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3` except all /* select#4 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` union /* select#5 */ select `test`.`t4`.`g` AS `g`,`test`.`t4`.`h` AS `h` from `test`.`t4` except /* select#6 */ select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3` union all /* select#7 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1`
+drop table t4;
+# test optimization with brackets
+(
+(select 1 except select 5 union all select 6)
+union
+(select 2 intersect all select 3 intersect all select 4)
+except
+(select 7 intersect all select 8)
+)
+union all
+(select 9 union all select 10)
+except all
+select 11;
+1
+1
+6
+9
+10
+EXPLAIN EXTENDED (
+(select 1 except select 5 union all select 6)
+union
+(select 2 intersect all select 3 intersect all select 4)
+except
+(select 7 intersect all select 8)
+)
+union all
+(select 9 union all select 10)
+except all
+select 11;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY <derived8> ALL NULL NULL NULL NULL 4 100.00
+8 DERIVED <derived2> ALL NULL NULL NULL NULL 2 100.00
+2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+3 EXCEPT NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+4 UNION NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+NULL UNIT RESULT <unit2,3,4> ALL NULL NULL NULL NULL NULL NULL
+9 UNION <derived5> ALL NULL NULL NULL NULL 2 100.00
+5 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+6 INTERSECT NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+7 INTERSECT NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+NULL INTERSECT RESULT <intersect5,6,7> ALL NULL NULL NULL NULL NULL NULL
+12 EXCEPT <derived10> ALL NULL NULL NULL NULL 2 100.00
+10 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+11 INTERSECT NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+NULL INTERSECT RESULT <intersect10,11> ALL NULL NULL NULL NULL NULL NULL
+NULL UNIT RESULT <unit8,9,12> ALL NULL NULL NULL NULL NULL NULL
+15 UNION <derived13> ALL NULL NULL NULL NULL 2 100.00
+13 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+14 UNION NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+16 EXCEPT NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+NULL UNIT RESULT <unit1,15,16> ALL NULL NULL NULL NULL NULL NULL
+Warnings:
+Note 1003 /* select#1 */ select `__14`.`1` AS `1` from (/* select#8 */ select `__7`.`1` AS `1` from (/* select#2 */ select 1 AS `1` except /* select#3 */ select 5 AS `5` union /* select#4 */ select 6 AS `6`) `__7` union /* select#9 */ select `__8`.`2` AS `2` from (/* select#5 */ select 2 AS `2` intersect /* select#6 */ select 3 AS `3` intersect /* select#7 */ select 4 AS `4`) `__8` except /* select#12 */ select `__11`.`7` AS `7` from (/* select#10 */ select 7 AS `7` intersect /* select#11 */ select 8 AS `8`) `__11`) `__14` union all /* select#15 */ select `__15`.`9` AS `9` from (/* select#13 */ select 9 AS `9` union all /* select#14 */ select 10 AS `10`) `__15` except all /* select#16 */ select 11 AS `11`
+(select 1 union all select 2)
+union
+(select 3 union all select 4);
+1
+1
+2
+3
+4
+EXPLAIN EXTENDED (select 1 union all select 2)
+union
+(select 3 union all select 4);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2 100.00
+2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+3 UNION NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+6 UNION <derived4> ALL NULL NULL NULL NULL 2 100.00
+4 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+5 UNION NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+NULL UNION RESULT <union1,6> ALL NULL NULL NULL NULL NULL NULL
+Warnings:
+Note 1003 /* select#1 */ select `__5`.`1` AS `1` from (/* select#2 */ select 1 AS `1` union /* select#3 */ select 2 AS `2`) `__5` union /* select#6 */ select `__6`.`3` AS `3` from (/* select#4 */ select 3 AS `3` union /* select#5 */ select 4 AS `4`) `__6`
+(select 1 intersect all select 2)
+except
+select 3;
+1
+EXPLAIN EXTENDED (select 1 intersect all select 2)
+except
+select 3;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2 100.00
+2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+3 INTERSECT NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+NULL INTERSECT RESULT <intersect2,3> ALL NULL NULL NULL NULL NULL NULL
+4 EXCEPT NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+NULL EXCEPT RESULT <except1,4> ALL NULL NULL NULL NULL NULL NULL
+Warnings:
+Note 1003 /* select#1 */ select `__4`.`1` AS `1` from (/* select#2 */ select 1 AS `1` intersect /* select#3 */ select 2 AS `2`) `__4` except /* select#4 */ select 3 AS `3`
+(select 1 intersect all select 2 intersect all select 3)
+intersect
+(select 4 intersect all select 5);
+1
+EXPLAIN EXTENDED (select 1 intersect all select 2 intersect all select 3)
+intersect
+(select 4 intersect all select 5);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2 100.00
+2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+3 INTERSECT NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+4 INTERSECT NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+NULL INTERSECT RESULT <intersect2,3,4> ALL NULL NULL NULL NULL NULL NULL
+7 INTERSECT <derived5> ALL NULL NULL NULL NULL 2 100.00
+5 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+6 INTERSECT NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+NULL INTERSECT RESULT <intersect5,6> ALL NULL NULL NULL NULL NULL NULL
+NULL INTERSECT RESULT <intersect1,7> ALL NULL NULL NULL NULL NULL NULL
+Warnings:
+Note 1003 /* select#1 */ select `__6`.`1` AS `1` from (/* select#2 */ select 1 AS `1` intersect /* select#3 */ select 2 AS `2` intersect /* select#4 */ select 3 AS `3`) `__6` intersect /* select#7 */ select `__7`.`4` AS `4` from (/* select#5 */ select 4 AS `4` intersect /* select#6 */ select 5 AS `5`) `__7`
+# test set operations with table value constructor
+(values (1,1),(1,1),(1,1),(2,2),(2,2),(3,3),(9,9))
+INTERSECT ALL
+(values (1,1),(2,2),(2,2),(3,3),(3,3),(3,3),(8,8))
+EXCEPT ALL
+(values (7,7),(1,1));
+1 1
+2 2
+2 2
+3 3
+delete from t1;
+insert into t1 values(1,1),(1,1),(2,2),(4,4),(9,9);
+select * from t1
+UNION ALL
+(values (11,12),(3,3),(2,2),(3,3),(4,4),(8,8))
+INTERSECT
+(values (13,14),(7,7),(2,2),(3,3),(1,1))
+INTERSECT ALL
+(values (15,16),(2,2),(1,1))
+EXCEPT
+(values (17,18),(1,1));
+a b
+2 2
+4 4
+9 9
+# test set operations with derived table
+select * from (
+select * from t1
+UNION ALL
+select * from t2
+)dt1
+INTERSECT ALL
+select * from (
+select * from t2
+EXCEPT ALL
+select * from t3
+)dt2;
+a b
+2 2
+3 3
+5 5
+select * from (
+select * from t1
+UNION ALL
+select * from t3
+)dt1
+EXCEPT ALL
+select * from (
+select * from t2
+INTERSECT ALL
+select * from t2
+)dt2;
+a b
+1 1
+1 1
+4 4
+9 9
+1 1
+4 4
+SELECT * from(
+select * from (
+select * from t1
+UNION ALL
+select * from t2
+)dt1
+INTERSECT ALL
+select * from (
+select * from t2
+EXCEPT ALL
+select * from t3
+)dt2
+)dt3;
+a b
+2 2
+3 3
+5 5
+# integration test
+select * from t1
+UNION ALL
+select * from t2
+INTERSECT ALL
+(values (1,1), (2,2), (2,2), (5,5), (2,2))
+INTERSECT ALL
+select * from (select * from t1 union all select * from t1) sq
+EXCEPT ALL
+select * from t3
+UNION ALL
+select * from t2
+UNION
+select * from t3
+EXCEPT
+select a,c from t1,t2
+UNION ALL
+select * from v0 where g < 4
+UNION ALL
+select * from t3;
+a b
+1 1
+1 2
+3 3
+9 9
+5 5
+4 4
+1 2
+2 2
+1 3
+1 3
+2 3
+1 5
+1 5
+2 5
+1 2
+1 2
+2 2
+1 2
+1 2
+2 2
+1 3
+1 3
+2 3
+4 4
+2 2
+2 2
+1 1
+3 3
+select * from t1
+UNION ALL
+select * from t2
+INTERSECT ALL
+(values (1,1), (2,2), (2,2), (5,5), (2,2))
+INTERSECT ALL
+select * from (select * from t1 union all select * from t1) sq
+EXCEPT ALL
+select * from t3
+UNION ALL
+select * from t2
+UNION
+select * from t3
+EXCEPT
+select a,c from t1,t2
+UNION ALL
+select * from v0 where g < 4
+UNION ALL
+select * from t3
+ORDER BY a;
+a b
+1 1
+1 1
+1 2
+1 2
+1 2
+1 2
+1 2
+1 2
+1 3
+1 3
+1 3
+1 3
+1 5
+1 5
+2 2
+2 2
+2 2
+2 2
+2 2
+2 3
+2 3
+2 5
+3 3
+3 3
+4 4
+4 4
+5 5
+9 9
+select * from (
+select * from t1
+UNION ALL
+select * from t2
+INTERSECT ALL
+(values (1,1), (2,2), (2,2), (5,5), (2,2) )
+INTERSECT ALL
+select * from (select * from t1 union all select * from t1) sq
+EXCEPT ALL
+select * from t3
+UNION ALL
+select * from t2
+UNION
+select * from t3
+EXCEPT
+select a,c from t1,t2
+UNION ALL
+select * from v0 where g < 4
+UNION ALL
+select * from t3
+) dt;
+a b
+1 1
+1 2
+3 3
+9 9
+5 5
+4 4
+1 2
+2 2
+1 3
+1 3
+2 3
+1 5
+1 5
+2 5
+1 2
+1 2
+2 2
+1 2
+1 2
+2 2
+1 3
+1 3
+2 3
+4 4
+2 2
+2 2
+1 1
+3 3
+EXPLAIN
+select * from t1
+UNION ALL
+select * from t2
+INTERSECT ALL
+(values (1,1), (2,2), (2,2), (5,5), (2,2) )
+INTERSECT ALL
+select * from (select * from t1 union all select * from t1) sq
+EXCEPT ALL
+select * from t3
+UNION ALL
+select * from t2
+UNION
+select * from t3
+EXCEPT
+select a,c from t1,t2
+UNION ALL
+select * from v0 where g < 4
+UNION ALL
+select * from t3;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5
+8 UNION <derived2> ALL NULL NULL NULL NULL 5
+2 DERIVED t2 ALL NULL NULL NULL NULL 6
+3 INTERSECT NULL NULL NULL NULL NULL NULL NULL No tables used
+4 INTERSECT <derived5> ALL NULL NULL NULL NULL 10
+5 DERIVED t1 ALL NULL NULL NULL NULL 5
+6 UNION t1 ALL NULL NULL NULL NULL 5
+NULL INTERSECT RESULT <intersect2,3,4> ALL NULL NULL NULL NULL NULL
+7 EXCEPT t3 ALL NULL NULL NULL NULL 5
+9 UNION t2 ALL NULL NULL NULL NULL 6
+10 UNION t3 ALL NULL NULL NULL NULL 5
+11 EXCEPT t1 ALL NULL NULL NULL NULL 5
+11 EXCEPT t2 ALL NULL NULL NULL NULL 6 Using join buffer (flat, BNL join)
+12 UNION t1 ALL NULL NULL NULL NULL 5 Using where
+12 UNION t2 ALL NULL NULL NULL NULL 6 Using join buffer (flat, BNL join)
+13 UNION t3 ALL NULL NULL NULL NULL 5
+NULL UNIT RESULT <unit1,8,7,9,10,11,12,13> ALL NULL NULL NULL NULL NULL
+EXPLAIN format=json
+select * from t1
+UNION ALL
+select * from t2
+INTERSECT ALL
+(values (1,1), (2,2), (2,2), (5,5), (2,2) )
+INTERSECT ALL
+select * from (select * from t1 union all select * from t1) sq
+EXCEPT ALL
+select * from t3
+UNION ALL
+select * from t2
+UNION
+select * from t3
+EXCEPT
+select a,c from t1,t2
+UNION ALL
+select * from v0 where g < 4
+UNION ALL
+select * from t3;
+EXPLAIN
+{
+ "query_block": {
+ "union_result": {
+ "table_name": "<unit1,8,7,9,10,11,12,13>",
+ "access_type": "ALL",
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 8,
+ "operation": "UNION",
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "materialized": {
+ "query_block": {
+ "union_result": {
+ "table_name": "<intersect2,3,4>",
+ "access_type": "ALL",
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 2,
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 6,
+ "filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 3,
+ "operation": "INTERSECT",
+ "table": {
+ "message": "No tables used"
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 4,
+ "operation": "INTERSECT",
+ "table": {
+ "table_name": "<derived5>",
+ "access_type": "ALL",
+ "rows": 10,
+ "filtered": 100,
+ "materialized": {
+ "query_block": {
+ "union_result": {
+ "table_name": "<union5,6>",
+ "access_type": "ALL",
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 5,
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 6,
+ "operation": "UNION",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 7,
+ "operation": "EXCEPT",
+ "table": {
+ "table_name": "t3",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 9,
+ "operation": "UNION",
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 6,
+ "filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 10,
+ "operation": "UNION",
+ "table": {
+ "table_name": "t3",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 11,
+ "operation": "EXCEPT",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100
+ },
+ "block-nl-join": {
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 6,
+ "filtered": 100
+ },
+ "buffer_type": "flat",
+ "buffer_size": "65",
+ "join_type": "BNL"
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 12,
+ "operation": "UNION",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a < 4"
+ },
+ "block-nl-join": {
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 6,
+ "filtered": 100
+ },
+ "buffer_type": "flat",
+ "buffer_size": "65",
+ "join_type": "BNL"
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 13,
+ "operation": "UNION",
+ "table": {
+ "table_name": "t3",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100
+ }
+ }
+ }
+ ]
+ }
+ }
+}
+EXPLAIN EXTENDED
+select * from t1
+UNION ALL
+select * from t2
+INTERSECT ALL
+(values (1,1), (2,2), (2,2), (5,5), (2,2) )
+INTERSECT ALL
+select * from (select * from t1 union all select * from t1) sq
+EXCEPT ALL
+select * from t3
+UNION ALL
+select * from t2
+UNION
+select * from t3
+EXCEPT
+select a,c from t1,t2
+UNION ALL
+select * from v0 where g < 4
+UNION ALL
+select * from t3;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5 100.00
+8 UNION <derived2> ALL NULL NULL NULL NULL 5 100.00
+2 DERIVED t2 ALL NULL NULL NULL NULL 6 100.00
+3 INTERSECT NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+4 INTERSECT <derived5> ALL NULL NULL NULL NULL 10 100.00
+5 DERIVED t1 ALL NULL NULL NULL NULL 5 100.00
+6 UNION t1 ALL NULL NULL NULL NULL 5 100.00
+NULL INTERSECT RESULT <intersect2,3,4> ALL NULL NULL NULL NULL NULL NULL
+7 EXCEPT t3 ALL NULL NULL NULL NULL 5 100.00
+9 UNION t2 ALL NULL NULL NULL NULL 6 100.00
+10 UNION t3 ALL NULL NULL NULL NULL 5 100.00
+11 EXCEPT t1 ALL NULL NULL NULL NULL 5 100.00
+11 EXCEPT t2 ALL NULL NULL NULL NULL 6 100.00 Using join buffer (flat, BNL join)
+12 UNION t1 ALL NULL NULL NULL NULL 5 100.00 Using where
+12 UNION t2 ALL NULL NULL NULL NULL 6 100.00 Using join buffer (flat, BNL join)
+13 UNION t3 ALL NULL NULL NULL NULL 5 100.00
+NULL UNIT RESULT <unit1,8,7,9,10,11,12,13> 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 all /* select#8 */ select `__8`.`c` AS `c`,`__8`.`d` AS `d` from (/* select#2 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` intersect all (values (1,1),(2,2),(2,2),(5,5),(2,2)) intersect all /* select#4 */ select `sq`.`a` AS `a`,`sq`.`b` AS `b` from (/* select#5 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` union all /* select#6 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1`) `sq`) `__8` except all /* select#7 */ select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3` union /* select#9 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` union /* select#10 */ select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3` except /* select#11 */ select `test`.`t1`.`a` AS `a`,`test`.`t2`.`c` AS `c` from `test`.`t1` join `test`.`t2` union all /* select#12 */ se
lect `te
st`.`t1`.`a` AS `g`,`test`.`t2`.`c` AS `h` from `test`.`t1` join `test`.`t2` where `test`.`t1`.`a` < 4 union all /* select#13 */ select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3`
+PREPARE stmt from"
+ select * from t1
+ UNION ALL
+ select * from t2
+ INTERSECT ALL
+ (values (1,1), (2,2), (2,2), (5,5), (2,2) )
+ INTERSECT ALL
+ select * from (select * from t1 union all select * from t1) sq
+ EXCEPT ALL
+ select * from t3
+ UNION ALL
+ select * from t2
+ UNION
+ select * from t3
+ EXCEPT
+ select a,c from t1,t2
+ UNION ALL
+ select * from v0 where g < 4
+ UNION ALL
+ select * from t3
+";
+EXECUTE stmt;
+a b
+1 1
+1 2
+3 3
+9 9
+5 5
+4 4
+1 2
+2 2
+1 3
+1 3
+2 3
+1 5
+1 5
+2 5
+1 2
+1 2
+2 2
+1 2
+1 2
+2 2
+1 3
+1 3
+2 3
+4 4
+2 2
+2 2
+1 1
+3 3
+EXECUTE stmt;
+a b
+1 1
+1 2
+3 3
+9 9
+5 5
+4 4
+1 2
+2 2
+1 3
+1 3
+2 3
+1 5
+1 5
+2 5
+1 2
+1 2
+2 2
+1 2
+1 2
+2 2
+1 3
+1 3
+2 3
+4 4
+2 2
+2 2
+1 1
+3 3
+deallocate prepare stmt;
+create view v1(i1, i2) as
+select * from t1
+UNION ALL
+select * from t2
+INTERSECT ALL
+(values (1,1), (2,2), (2,2), (5,5), (2,2) )
+INTERSECT ALL
+select * from (select * from t1 union all select * from t1) sq
+EXCEPT ALL
+select * from t3
+UNION ALL
+select * from t2
+UNION
+select * from t3
+EXCEPT
+select a,c from t1,t2
+UNION ALL
+select * from v0 where g < 4
+UNION ALL
+select * from t3;
+show create view v1;
+View Create View character_set_client collation_connection
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `test`.`t1`.`a` AS `i1`,`test`.`t1`.`b` AS `i2` from `test`.`t1` union all select `__9`.`c` AS `c`,`__9`.`d` AS `d` from (select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` intersect all (values (1,1),(2,2),(2,2),(5,5),(2,2)) intersect all select `sq`.`a` AS `a`,`sq`.`b` AS `b` from (select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` union all select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1`) `sq`) `__9` except all select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3` union all select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` union select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3` except select `test`.`t1`.`a` AS `a`,`test`.`t2`.`c` AS `c` from (`test`.`t1` join `test`.`t2`) union all select `v0`.`g` AS `g`,`v0`.`h` AS `h` from `test`.`v0` where `v0`.`g` < 4 union
all sele
ct `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3` latin1 latin1_swedish_ci
+select * from v1 limit 14;
+i1 i2
+1 1
+1 2
+3 3
+9 9
+5 5
+4 4
+1 2
+2 2
+1 3
+1 3
+2 3
+1 5
+1 5
+2 5
+select * from v1 order by i1 limit 14;
+i1 i2
+1 1
+1 1
+1 2
+1 2
+1 2
+1 2
+1 2
+1 2
+1 3
+1 3
+1 3
+1 3
+1 5
+1 5
+drop table t1,t2,t3;
+drop view v0,v1;
+# compare result
+create table t1 (a int, b int);
+create table t2 (c int, d int);
+create table t3 (e int, f int);
+create table t4 (g int, h int);
+insert into t1 values (1,1),(1,1),(2,2);
+insert into t2 values (1,1),(1,1),(2,2),(3,3);
+insert into t3 values (1,1);
+insert into t4 values (4,4);
+select * from t1 intersect all select * from t2 except select * from t3 union select * from t4;
+a b
+4 4
+2 2
+select * from t1 intersect all select * from t2 except ALL select * from t3 union select * from t4;
+a b
+1 1
+2 2
+4 4
+select * from t1 intersect DISTINCT select * from t2 except select * from t3 union select * from t4;
+a b
+4 4
+2 2
+select * from t1 intersect DISTINCT select * from t2 except ALL select * from t3 union select * from t4;
+a b
+4 4
+2 2
+delete from t1;
+delete from t2;
+delete from t3;
+delete from t4;
+insert into t1 values (1,1),(1,1),(1,1),(2,2),(2,2),(4,4),(5,5);
+insert into t2 values (1,1),(1,1),(1,1),(2,2),(2,2),(3,3);
+insert into t3 values (1,1),(2,2),(2,2);
+select * from t1 intersect all select * from t2 intersect all select * from t3;
+a b
+1 1
+2 2
+2 2
+select * from t1 intersect all select * from t2 intersect select * from t3;
+a b
+1 1
+2 2
+select * from t1 intersect all select * from t1 intersect all select * from t2 intersect select * from t3;
+a b
+1 1
+2 2
+delete from t1;
+delete from t2;
+delete from t3;
+insert into t1 values (1,1),(1,1),(2,2);
+insert into t2 values (1,1),(1,1),(2,2),(3,3);
+insert into t3 values (1,1),(5,5);
+insert into t4 values (4,4),(4,4),(4,4);
+select * from t1 intersect all select * from t2 union all select * from t3 union select * from t4;
+a b
+1 1
+2 2
+5 5
+4 4
+select * from t1 intersect DISTINCT select * from t2 union DISTINCT select * from t3 union select * from t4;
+a b
+1 1
+2 2
+5 5
+4 4
+select * from t1 intersect all select * from t2 intersect all select * from t3 union select * from t4;
+a b
+1 1
+4 4
+select * from t1 intersect all select * from t2 intersect DISTINCT select * from t3 union select * from t4;
+a b
+1 1
+4 4
+select * from t1 intersect DISTINCT select * from t2 intersect DISTINCT select * from t3 union select * from t4;
+a b
+1 1
+4 4
+select * from t1 intersect all select * from t2 EXCEPT select * from t3 union select * from t4;
+a b
+4 4
+2 2
+select * from t1 intersect DISTINCT select * from t2 EXCEPT select * from t3 union select * from t4;
+a b
+4 4
+2 2
+select * from t1 intersect all select * from t2 EXCEPT ALL select * from t3 union select * from t4;
+a b
+1 1
+2 2
+4 4
+select * from t1 EXCEPT select * from t2 union all select * from t3 union select * from t4;
+a b
+5 5
+1 1
+4 4
+select * from t1 EXCEPT select * from t2 union DISTINCT select * from t3 union select * from t4;
+a b
+5 5
+1 1
+4 4
+delete from t1;
+delete from t2;
+delete from t3;
+delete from t4;
+insert into t1 values (1,1),(2,2);
+insert into t2 values (1,1),(2,2);
+insert into t3 values (1,1),(3,3);
+select * from t1 union all select * from t2 except all select * from t3;
+a b
+1 1
+2 2
+2 2
+select * from t1 union all select * from t2 except DISTINCT select * from t3;
+a b
+2 2
+select * from t1 union DISTINCT select * from t2 except all select * from t3;
+a b
+2 2
+select * from t1 union DISTINCT select * from t2 except DISTINCT select * from t3;
+a b
+2 2
+drop table t1;
+drop table t2;
+drop table t3;
+drop table t4;
+select 1 intersect all select 2 intersect all select 3 intersect select 4 union select 5;
+1
+5
+select 1 intersect all select 2 intersect all select 3 union select 4 except select 5;
+1
+4
+select 1 union select 2 except all select 3 union select 4;
+1
+1
+2
+4
+select 1 union all select 2 union all select 3 union select 4;
+1
+1
+2
+3
+4
+# test with limited resource
+set @@max_heap_table_size= 1024;
+Warnings:
+Warning 1292 Truncated incorrect max_heap_table_size value: '1024'
+set @@tmp_table_size= 1024;
+create table t1 (a int, b int);
+insert into t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(0,0);
+insert into t1 select * from t1;
+insert into t1 select * from t1;
+insert into t1 select * from t1;
+insert into t1 select a+100, b+100 from t1;
+create table t2 (a int, b int);
+insert into t2 values (10,10),(11,11),(12,12),(13,13),(14,14),(5,5),(6,6),(7,7),(8,8),(9,9);
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select a+100, b+100 from t2;
+select count(*) from
+(
+select * from t1
+INTERSECT ALL
+select * from t2
+) c;
+count(*)
+80
+select count(*) from
+(
+select * from t1
+EXCEPT ALL
+select * from t2
+) c;
+count(*)
+80
+select count(*) from
+(
+select * from t1
+INTERSECT ALL
+select * from t2
+UNION ALL
+select * from t1
+EXCEPT ALL
+select * from t2
+) c;
+count(*)
+160
+delete from t1;
+delete from t2;
+insert into t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(0,0);
+insert into t1 select a+10, b+10 from t1;
+insert into t1 select a+20, b+20 from t1;
+insert into t1 select a+40, b+40 from t1;
+insert into t1 select a+80, b+80 from t1;
+insert into t2 values (1110,1110),(1111,1111),(1112,1112),(1113,1113),(1114,1114),(1105,1105),(1106,1106),(1107,1107),(1108,1108),(1109,1109);
+insert into t2 select a+10, b+10 from t2;
+insert into t2 select a+20, b+20 from t2;
+insert into t2 select a+40, b+40 from t2;
+insert into t2 select a+80, b+80 from t2;
+select count(*) from
+(
+select * from t1
+UNION ALL
+select * from t2
+EXCEPT ALL
+values (1,1)
+) c;
+count(*)
+319
+drop table t1;
+drop table t2;
diff --git a/mysql-test/main/set_operation.test b/mysql-test/main/set_operation.test
new file mode 100644
index 0000000..c43725c
--- /dev/null
+++ b/mysql-test/main/set_operation.test
@@ -0,0 +1,526 @@
+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),(3,3),(2,2),(3,3);
+insert into t2 values (2,2),(3,3),(5,5),(2,2),(2,2),(3,3);
+insert into t3 values (4,4),(2,2),(2,2),(1,1),(3,3);
+insert into t4 values (2,2),(4,4),(1,1);
+create view v0(g, h) as select a,c from t1,t2;
+
+--echo # test optimization
+
+let $q=
+ select * from t1
+ INTERSECT ALL
+ select * from t2
+ INTERSECT ALL
+ select * from t3;
+eval $q;
+eval EXPLAIN EXTENDED $q;
+
+let $q=
+ select * from t1
+ INTERSECT ALL
+ select * from t2
+ INTERSECT ALL
+ select * from t3
+ INTERSECT
+ select * from t1;
+eval $q;
+eval EXPLAIN EXTENDED $q;
+
+let $q=
+ select * from t1
+ INTERSECT ALL
+ select * from t2
+ INTERSECT ALL
+ select * from t3
+ EXCEPT ALL
+ select * from t4;
+eval $q;
+eval EXPLAIN EXTENDED $q;
+
+let $q=
+ select * from t1
+ INTERSECT
+ select * from t2
+ EXCEPT ALL
+ select * from t4;
+eval $q;
+eval EXPLAIN EXTENDED $q;
+
+insert into t4 values (1,1),(9,9);
+let $q=
+ select * from t1
+ UNION ALL
+ select * from t2
+ UNION ALL
+ select * from t3
+ EXCEPT
+ select * from t4;
+eval $q;
+eval EXPLAIN EXTENDED $q;
+
+delete from t4;
+insert into t4 values (3,3),(3,3);
+let $q=
+ select * from t1
+ INTERSECT ALL
+ select * from t2
+ UNION ALL
+ select * from t3
+ EXCEPT ALL
+ select * from t1
+ UNION
+ select * from t4
+ EXCEPT
+ select * from t3
+ UNION ALL
+ select * from t1;
+
+eval $q;
+eval EXPLAIN EXTENDED $q;
+drop table t4;
+
+--echo # test optimization with brackets
+
+let $q=
+(
+ (select 1 except select 5 union all select 6)
+ union
+ (select 2 intersect all select 3 intersect all select 4)
+ except
+ (select 7 intersect all select 8)
+)
+ union all
+(select 9 union all select 10)
+ except all
+select 11;
+eval $q;
+eval EXPLAIN EXTENDED $q;
+
+let $q=
+(select 1 union all select 2)
+ union
+(select 3 union all select 4);
+eval $q;
+eval EXPLAIN EXTENDED $q;
+
+let $q=
+(select 1 intersect all select 2)
+ except
+select 3;
+eval $q;
+eval EXPLAIN EXTENDED $q;
+
+let $q=
+(select 1 intersect all select 2 intersect all select 3)
+ intersect
+(select 4 intersect all select 5);
+eval $q;
+eval EXPLAIN EXTENDED $q;
+
+
+--echo # test set operations with table value constructor
+
+(values (1,1),(1,1),(1,1),(2,2),(2,2),(3,3),(9,9))
+INTERSECT ALL
+(values (1,1),(2,2),(2,2),(3,3),(3,3),(3,3),(8,8))
+EXCEPT ALL
+(values (7,7),(1,1));
+
+delete from t1;
+insert into t1 values(1,1),(1,1),(2,2),(4,4),(9,9);
+
+select * from t1
+UNION ALL
+(values (11,12),(3,3),(2,2),(3,3),(4,4),(8,8))
+INTERSECT
+(values (13,14),(7,7),(2,2),(3,3),(1,1))
+INTERSECT ALL
+(values (15,16),(2,2),(1,1))
+EXCEPT
+(values (17,18),(1,1));
+
+--echo # test set operations with derived table
+
+select * from (
+ select * from t1
+ UNION ALL
+ select * from t2
+)dt1
+INTERSECT ALL
+select * from (
+ select * from t2
+ EXCEPT ALL
+ select * from t3
+)dt2;
+
+select * from (
+ select * from t1
+ UNION ALL
+ select * from t3
+)dt1
+EXCEPT ALL
+select * from (
+ select * from t2
+ INTERSECT ALL
+ select * from t2
+)dt2;
+
+SELECT * from(
+ select * from (
+ select * from t1
+ UNION ALL
+ select * from t2
+ )dt1
+ INTERSECT ALL
+ select * from (
+ select * from t2
+ EXCEPT ALL
+ select * from t3
+ )dt2
+)dt3;
+
+--echo # integration test
+
+
+select * from t1
+UNION ALL
+select * from t2
+INTERSECT ALL
+(values (1,1), (2,2), (2,2), (5,5), (2,2))
+INTERSECT ALL
+select * from (select * from t1 union all select * from t1) sq
+EXCEPT ALL
+select * from t3
+UNION ALL
+select * from t2
+UNION
+select * from t3
+EXCEPT
+select a,c from t1,t2
+UNION ALL
+select * from v0 where g < 4
+UNION ALL
+select * from t3;
+
+--sorted_result
+select * from t1
+UNION ALL
+select * from t2
+INTERSECT ALL
+(values (1,1), (2,2), (2,2), (5,5), (2,2))
+INTERSECT ALL
+select * from (select * from t1 union all select * from t1) sq
+EXCEPT ALL
+select * from t3
+UNION ALL
+select * from t2
+UNION
+select * from t3
+EXCEPT
+select a,c from t1,t2
+UNION ALL
+select * from v0 where g < 4
+UNION ALL
+select * from t3
+ORDER BY a;
+
+
+select * from (
+ select * from t1
+ UNION ALL
+ select * from t2
+ INTERSECT ALL
+ (values (1,1), (2,2), (2,2), (5,5), (2,2) )
+ INTERSECT ALL
+ select * from (select * from t1 union all select * from t1) sq
+ EXCEPT ALL
+ select * from t3
+ UNION ALL
+ select * from t2
+ UNION
+ select * from t3
+ EXCEPT
+ select a,c from t1,t2
+ UNION ALL
+ select * from v0 where g < 4
+ UNION ALL
+ select * from t3
+) dt;
+
+EXPLAIN
+select * from t1
+UNION ALL
+select * from t2
+INTERSECT ALL
+(values (1,1), (2,2), (2,2), (5,5), (2,2) )
+INTERSECT ALL
+select * from (select * from t1 union all select * from t1) sq
+EXCEPT ALL
+select * from t3
+UNION ALL
+select * from t2
+UNION
+select * from t3
+EXCEPT
+select a,c from t1,t2
+UNION ALL
+select * from v0 where g < 4
+UNION ALL
+select * from t3;
+
+EXPLAIN format=json
+select * from t1
+UNION ALL
+select * from t2
+INTERSECT ALL
+(values (1,1), (2,2), (2,2), (5,5), (2,2) )
+INTERSECT ALL
+select * from (select * from t1 union all select * from t1) sq
+EXCEPT ALL
+select * from t3
+UNION ALL
+select * from t2
+UNION
+select * from t3
+EXCEPT
+select a,c from t1,t2
+UNION ALL
+select * from v0 where g < 4
+UNION ALL
+select * from t3;
+
+EXPLAIN EXTENDED
+select * from t1
+UNION ALL
+select * from t2
+INTERSECT ALL
+(values (1,1), (2,2), (2,2), (5,5), (2,2) )
+INTERSECT ALL
+select * from (select * from t1 union all select * from t1) sq
+EXCEPT ALL
+select * from t3
+UNION ALL
+select * from t2
+UNION
+select * from t3
+EXCEPT
+select a,c from t1,t2
+UNION ALL
+select * from v0 where g < 4
+UNION ALL
+select * from t3;
+
+PREPARE stmt from"
+ select * from t1
+ UNION ALL
+ select * from t2
+ INTERSECT ALL
+ (values (1,1), (2,2), (2,2), (5,5), (2,2) )
+ INTERSECT ALL
+ select * from (select * from t1 union all select * from t1) sq
+ EXCEPT ALL
+ select * from t3
+ UNION ALL
+ select * from t2
+ UNION
+ select * from t3
+ EXCEPT
+ select a,c from t1,t2
+ UNION ALL
+ select * from v0 where g < 4
+ UNION ALL
+ select * from t3
+";
+
+
+EXECUTE stmt;
+
+EXECUTE stmt;
+deallocate prepare stmt;
+
+create view v1(i1, i2) as
+ select * from t1
+ UNION ALL
+ select * from t2
+ INTERSECT ALL
+ (values (1,1), (2,2), (2,2), (5,5), (2,2) )
+ INTERSECT ALL
+ select * from (select * from t1 union all select * from t1) sq
+ EXCEPT ALL
+ select * from t3
+ UNION ALL
+ select * from t2
+ UNION
+ select * from t3
+ EXCEPT
+ select a,c from t1,t2
+ UNION ALL
+ select * from v0 where g < 4
+ UNION ALL
+ select * from t3;
+
+show create view v1;
+
+select * from v1 limit 14;
+--sorted_result
+select * from v1 order by i1 limit 14;
+
+drop table t1,t2,t3;
+drop view v0,v1;
+
+--echo # compare result
+
+create table t1 (a int, b int);
+create table t2 (c int, d int);
+create table t3 (e int, f int);
+create table t4 (g int, h int);
+
+
+insert into t1 values (1,1),(1,1),(2,2);
+insert into t2 values (1,1),(1,1),(2,2),(3,3);
+insert into t3 values (1,1);
+insert into t4 values (4,4);
+
+select * from t1 intersect all select * from t2 except select * from t3 union select * from t4;
+select * from t1 intersect all select * from t2 except ALL select * from t3 union select * from t4;
+
+select * from t1 intersect DISTINCT select * from t2 except select * from t3 union select * from t4;
+select * from t1 intersect DISTINCT select * from t2 except ALL select * from t3 union select * from t4;
+
+delete from t1;
+delete from t2;
+delete from t3;
+delete from t4;
+
+
+insert into t1 values (1,1),(1,1),(1,1),(2,2),(2,2),(4,4),(5,5);
+insert into t2 values (1,1),(1,1),(1,1),(2,2),(2,2),(3,3);
+insert into t3 values (1,1),(2,2),(2,2);
+
+select * from t1 intersect all select * from t2 intersect all select * from t3;
+select * from t1 intersect all select * from t2 intersect select * from t3;
+select * from t1 intersect all select * from t1 intersect all select * from t2 intersect select * from t3;
+
+delete from t1;
+delete from t2;
+delete from t3;
+
+
+insert into t1 values (1,1),(1,1),(2,2);
+insert into t2 values (1,1),(1,1),(2,2),(3,3);
+insert into t3 values (1,1),(5,5);
+insert into t4 values (4,4),(4,4),(4,4);
+
+select * from t1 intersect all select * from t2 union all select * from t3 union select * from t4;
+select * from t1 intersect DISTINCT select * from t2 union DISTINCT select * from t3 union select * from t4;
+
+select * from t1 intersect all select * from t2 intersect all select * from t3 union select * from t4;
+select * from t1 intersect all select * from t2 intersect DISTINCT select * from t3 union select * from t4;
+select * from t1 intersect DISTINCT select * from t2 intersect DISTINCT select * from t3 union select * from t4;
+
+select * from t1 intersect all select * from t2 EXCEPT select * from t3 union select * from t4;
+select * from t1 intersect DISTINCT select * from t2 EXCEPT select * from t3 union select * from t4;
+select * from t1 intersect all select * from t2 EXCEPT ALL select * from t3 union select * from t4;
+
+select * from t1 EXCEPT select * from t2 union all select * from t3 union select * from t4;
+select * from t1 EXCEPT select * from t2 union DISTINCT select * from t3 union select * from t4;
+
+delete from t1;
+delete from t2;
+delete from t3;
+delete from t4;
+
+
+insert into t1 values (1,1),(2,2);
+insert into t2 values (1,1),(2,2);
+insert into t3 values (1,1),(3,3);
+
+select * from t1 union all select * from t2 except all select * from t3;
+select * from t1 union all select * from t2 except DISTINCT select * from t3;
+select * from t1 union DISTINCT select * from t2 except all select * from t3;
+select * from t1 union DISTINCT select * from t2 except DISTINCT select * from t3;
+
+drop table t1;
+drop table t2;
+drop table t3;
+drop table t4;
+
+
+select 1 intersect all select 2 intersect all select 3 intersect select 4 union select 5;
+select 1 intersect all select 2 intersect all select 3 union select 4 except select 5;
+select 1 union select 2 except all select 3 union select 4;
+select 1 union all select 2 union all select 3 union select 4;
+
+--echo # test with limited resource
+
+set @@max_heap_table_size= 1024;
+set @@tmp_table_size= 1024;
+
+create table t1 (a int, b int);
+insert into t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(0,0);
+insert into t1 select * from t1;
+insert into t1 select * from t1;
+insert into t1 select * from t1;
+insert into t1 select a+100, b+100 from t1;
+create table t2 (a int, b int);
+insert into t2 values (10,10),(11,11),(12,12),(13,13),(14,14),(5,5),(6,6),(7,7),(8,8),(9,9);
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select a+100, b+100 from t2;
+
+
+select count(*) from
+(
+ select * from t1
+ INTERSECT ALL
+ select * from t2
+) c;
+
+select count(*) from
+(
+ select * from t1
+ EXCEPT ALL
+ select * from t2
+) c;
+
+select count(*) from
+(
+ select * from t1
+ INTERSECT ALL
+ select * from t2
+ UNION ALL
+ select * from t1
+ EXCEPT ALL
+ select * from t2
+) c;
+
+delete from t1;
+delete from t2;
+
+insert into t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(0,0);
+insert into t1 select a+10, b+10 from t1;
+insert into t1 select a+20, b+20 from t1;
+insert into t1 select a+40, b+40 from t1;
+insert into t1 select a+80, b+80 from t1;
+insert into t2 values (1110,1110),(1111,1111),(1112,1112),(1113,1113),(1114,1114),(1105,1105),(1106,1106),(1107,1107),(1108,1108),(1109,1109);
+insert into t2 select a+10, b+10 from t2;
+insert into t2 select a+20, b+20 from t2;
+insert into t2 select a+40, b+40 from t2;
+insert into t2 select a+80, b+80 from t2;
+
+select count(*) from
+(
+ select * from t1
+ UNION ALL
+ select * from t2
+ EXCEPT ALL
+ values (1,1)
+) c;
+
+drop table t1;
+drop table t2;
diff --git a/mysql-test/main/set_operation_oracle.result b/mysql-test/main/set_operation_oracle.result
new file mode 100644
index 0000000..28f6e31
--- /dev/null
+++ b/mysql-test/main/set_operation_oracle.result
@@ -0,0 +1,75 @@
+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;
diff --git a/mysql-test/main/set_operation_oracle.test b/mysql-test/main/set_operation_oracle.test
new file mode 100644
index 0000000..bd2a4d5
--- /dev/null
+++ b/mysql-test/main/set_operation_oracle.test
@@ -0,0 +1,65 @@
+# 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
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 152bf06..54d6541 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -5708,17 +5708,18 @@ class TMP_TABLE_PARAM :public Sql_alloc
class select_unit :public select_result_interceptor
{
+protected:
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(ha_rows 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
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 8f6e86f..e77f173 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -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 (...) */
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index b916d07..cd6c068 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -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;
@@ -868,11 +878,6 @@ class st_select_lex_unit: public st_select_lex_node {
*/
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:
VALUES (v1) ... (vn) => SELECT * FROM (VALUES (v1) ... (vn)) as tvc
@@ -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;
diff --git a/sql/sql_tvc.cc b/sql/sql_tvc.cc
index 9eefd03..47f50ae 100644
--- a/sql/sql_tvc.cc
+++ b/sql/sql_tvc.cc
@@ -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;
}
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 41f4234..1abc81b 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -72,7 +72,7 @@ void select_unit::change_select()
switch (step)
{
case INTERSECT_TYPE:
- intersect_mark->value= prev_step= curr_step;
+ prev_step= curr_step;
curr_step= current_select_number;
break;
case EXCEPT_TYPE:
@@ -83,6 +83,7 @@ void select_unit::change_select()
}
DBUG_VOID_RETURN;
}
+
/**
Fill temporary tables for UNION/EXCEPT/INTERSECT
@@ -93,7 +94,7 @@ void select_unit::change_select()
EXCEPT:
looks for the record in the table (with 'counter' field first if
INTERSECT present in the sequence) and delete it if found
-INTESECT:
+INTERSECT:
looks for the same record with 'counter' field of previous operation,
put as a 'counter' number of the current SELECT.
We scan the table and remove all records which marked with not last
@@ -108,7 +109,7 @@ void select_unit::change_select()
*/
int select_unit::send_data(List<Item> &values)
{
- int rc;
+ int rc= 0;
int not_reported_error= 0;
if (unit->offset_limit_cnt)
{ // using limit offset,count
@@ -119,17 +120,24 @@ int select_unit::send_data(List<Item> &values)
return 0;
if (table->no_rows_with_nulls)
table->null_catch_flags= CHECK_ROW_FOR_NULLS_TO_REJECT;
- if (intersect_mark)
+
+ fill_record(thd, table, table->field + addon_cnt, values, true, false);
+ /* set up initial values for records to be written */
+ if (addon_cnt && step == UNION_TYPE)
{
- fill_record(thd, table, table->field + 1, values, TRUE, FALSE);
- table->field[0]->store((ulonglong) curr_step, 1);
+ DBUG_ASSERT(addon_cnt == 1);
+ table->field[0]->store((longlong) curr_step, 1);
}
- else
- fill_record(thd, table, table->field, values, TRUE, FALSE);
+
if (unlikely(thd->is_error()))
{
rc= 1;
- goto end;
+ if (unlikely(not_reported_error))
+ {
+ DBUG_ASSERT(rc);
+ table->file->print_error(not_reported_error, MYF(0));
+ }
+ return rc;
}
if (table->no_rows_with_nulls)
{
@@ -137,105 +145,58 @@ int select_unit::send_data(List<Item> &values)
if (table->null_catch_flags)
{
rc= 0;
- goto end;
+ if (unlikely(not_reported_error))
+ {
+ DBUG_ASSERT(rc);
+ table->file->print_error(not_reported_error, MYF(0));
+ }
+ return rc;
}
}
- // select_unit::change_select() change step & Co correctly for each SELECT
+ /* select_unit::change_select() change step & Co correctly for each SELECT */
+ int find_res;
switch (step)
{
- case UNION_TYPE:
- {
- if (unlikely((write_err=
- table->file->ha_write_tmp_row(table->record[0]))))
- {
- if (write_err == HA_ERR_FOUND_DUPP_KEY)
- {
- /*
- Inform upper level that we found a duplicate key, that should not
- be counted as part of limit
- */
- rc= -1;
- goto end;
- }
- bool is_duplicate= FALSE;
- /* create_internal_tmp_table_from_heap will generate error if needed */
- if (table->file->is_fatal_error(write_err, HA_CHECK_DUP) &&
- create_internal_tmp_table_from_heap(thd, table,
- tmp_table_param.start_recinfo,
- &tmp_table_param.recinfo,
- write_err, 1, &is_duplicate))
- {
- rc= 1;
- goto end;
- }
+ case UNION_TYPE:
+ rc= write_record();
+ /* no reaction with conversion */
+ if (rc == -2)
+ rc= 0;
+ break;
- if (is_duplicate)
- {
- rc= -1;
- goto end;
- }
- }
- break;
- }
- case EXCEPT_TYPE:
- {
- int find_res;
- /*
- The temporary table uses very first index or constrain for
- checking unique constrain.
- */
- if (!(find_res= table->file->find_unique_row(table->record[0], 0)))
- {
- DBUG_ASSERT(!table->triggers);
- table->status|= STATUS_DELETED;
- not_reported_error= table->file->ha_delete_tmp_row(table->record[0]);
- rc= MY_TEST(not_reported_error);
- goto end;
- }
- else
- {
- if ((rc= not_reported_error= (find_res != 1)))
- goto end;
- }
- break;
- }
- case INTERSECT_TYPE:
+ case EXCEPT_TYPE:
+ /*
+ The temporary table uses very first index or constrain for
+ checking unique constrain.
+ */
+ if (!(find_res= table->file->find_unique_row(table->record[0], 0)))
+ rc= delete_record();
+ else
+ rc= not_reported_error= (find_res != 1);
+ break;
+ case INTERSECT_TYPE:
+ /*
+ The temporary table uses very first index or constrain for
+ checking unique constrain.
+ */
+ if (!(find_res= table->file->find_unique_row(table->record[0], 0)))
{
- int find_res;
- /*
- The temporary table uses very first index or constrain for
- checking unique constrain.
- */
- if (!(find_res= table->file->find_unique_row(table->record[0], 0)))
+ DBUG_ASSERT(!table->triggers);
+ if (table->field[0]->val_int() == prev_step)
{
- DBUG_ASSERT(!table->triggers);
- if (table->field[0]->val_int() != prev_step)
- {
- rc= 0;
- goto end;
- }
- store_record(table, record[1]);
- table->field[0]->store(curr_step, 0);
- not_reported_error= table->file->ha_update_tmp_row(table->record[1],
- table->record[0]);
+ not_reported_error= update_counter(table->field[0], curr_step);
rc= MY_TEST(not_reported_error);
DBUG_ASSERT(rc != HA_ERR_RECORD_IS_THE_SAME);
- goto end;
}
- else
- {
- if ((rc= not_reported_error= (find_res != 1)))
- goto end;
- }
- break;
}
- default:
- DBUG_ASSERT(0);
+ else
+ rc= not_reported_error= (find_res != 1);
+ break;
+ default:
+ DBUG_ASSERT(0);
}
- rc= 0;
-end:
if (unlikely(not_reported_error))
{
DBUG_ASSERT(rc);
@@ -251,7 +212,7 @@ bool select_unit::send_eof()
thd->lex->current_select->next_select()->get_linkage() == INTERSECT_TYPE))
{
/*
- it is not INTESECT or next SELECT in the sequence is INTERSECT so no
+ it is not INTERSECT or next SELECT in the sequence is INTERSECT so no
need filtering (the last INTERSECT in this sequence of intersects will
filter).
*/
@@ -265,15 +226,14 @@ bool select_unit::send_eof()
TODO: as optimization for simple case this could be moved to
'fake_select' WHERE condition
*/
- handler *file= table->file;
int error;
- if (unlikely(file->ha_rnd_init_with_error(1)))
+ if (table->file->ha_rnd_init_with_error(1))
return 1;
-
do
{
- if (unlikely(error= file->ha_rnd_next(table->record[0])))
+ error= table->file->ha_rnd_next(table->record[0]);
+ if (unlikely(error))
{
if (error == HA_ERR_END_OF_FILE)
{
@@ -283,9 +243,9 @@ bool select_unit::send_eof()
break;
}
if (table->field[0]->val_int() != curr_step)
- error= file->ha_delete_tmp_row(table->record[0]);
- } while (likely(!error));
- file->ha_rnd_end();
+ error= delete_record();
+ } while (!error);
+ table->file->ha_rnd_end();
if (unlikely(error))
table->file->print_error(error, MYF(0));
@@ -345,6 +305,7 @@ bool select_unit::flush()
create_table whether to physically create result table
keep_row_order keep rows in order as they were inserted
hidden number of hidden fields (for INTERSECT)
+ plus one for `ALL`
DESCRIPTION
Create a temporary table that is used to store the result of a UNION,
@@ -433,6 +394,143 @@ select_union_recursive::create_result_table(THD *thd_arg,
}
+/*
+ @brief
+ Write a record
+
+ @retval
+ -2 conversion happened
+ -1 found a duplicate key
+ 0 no error
+ 1 if an error is reported
+*/
+
+int select_unit::write_record()
+{
+ if (unlikely((write_err= table->file->ha_write_tmp_row(table->record[0]))))
+ {
+ if (write_err == HA_ERR_FOUND_DUPP_KEY)
+ {
+ /*
+ Inform upper level that we found a duplicate key, that should not
+ be counted as part of limit
+ */
+ return -1;
+ }
+ bool is_duplicate= false;
+ /* create_internal_tmp_table_from_heap will generate error if needed */
+ if (table->file->is_fatal_error(write_err, HA_CHECK_DUP))
+ {
+ if (!create_internal_tmp_table_from_heap(thd, table,
+ tmp_table_param.start_recinfo,
+ &tmp_table_param.recinfo,
+ write_err, 1, &is_duplicate))
+ {
+ return -2;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ if (is_duplicate)
+ {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
+/*
+ @brief
+ Update counter for a record
+
+ @retval
+ 0 no error
+ -1 error occurred
+*/
+
+int select_unit::update_counter(Field* counter, longlong value)
+{
+ store_record(table, record[1]);
+ counter->store(value, 0);
+ int error= table->file->ha_update_tmp_row(table->record[1],
+ table->record[0]);
+ return error;
+}
+
+
+/*
+ @brief
+ Try to disable index
+
+ @retval
+ true index is disabled this time
+ false this time did not disable the index
+*/
+
+bool select_unit_ext::disable_index_if_needed(SELECT_LEX *curr_sl)
+{
+ if (is_index_enabled &&
+ (curr_sl == curr_sl->master_unit()->union_distinct ||
+ !curr_sl->next_select()) )
+ {
+ is_index_enabled= false;
+ if (table->file->ha_disable_indexes(HA_KEY_SWITCH_ALL))
+ return false;
+ table->no_keyread=1;
+ return true;
+ }
+ return false;
+}
+
+/*
+ @brief
+ Unfold a record
+
+ @retval
+ 0 no error
+ -1 conversion happened
+*/
+
+int select_unit_ext::unfold_record(ha_rows cnt)
+{
+
+ DBUG_ASSERT(cnt > 0);
+ int error= 0;
+ bool is_convertion_happened= false;
+ while (--cnt)
+ {
+ error= write_record();
+ if (error == -2)
+ {
+ is_convertion_happened= true;
+ error= -1;
+ }
+ }
+ if (is_convertion_happened)
+ return -1;
+ return error;
+}
+
+/*
+ @brief
+ Delete a record
+
+ @retval
+ 0 no error
+ 1 if an error is reported
+*/
+
+int select_unit::delete_record()
+{
+ DBUG_ASSERT(!table->triggers);
+ table->status|= STATUS_DELETED;
+ int not_reported_error= table->file->ha_delete_tmp_row(table->record[0]);
+ return MY_TEST(not_reported_error);
+}
+
/**
Reset and empty the temporary table that stores the materialized query
result.
@@ -448,6 +546,357 @@ void select_unit::cleanup()
}
+/*
+ @brief
+ Set up value needed by send_data() and send_eof()
+
+ @detail
+ - For EXCEPT we will decrease the counter by one
+ and INTERSECT / UNION we increase the counter.
+
+ - For INTERSECT we will modify the second extra field (intersect counter)
+ and for EXCEPT / UNION we modify the first (duplicate counter)
+*/
+
+void select_unit_ext::change_select()
+{
+ select_unit::change_select();
+ switch(step){
+ case UNION_TYPE:
+ increment= 1;
+ curr_op_type= UNION_DISTINCT;
+ break;
+ case EXCEPT_TYPE:
+ increment= -1;
+ curr_op_type= EXCEPT_DISTINCT;
+ break;
+ case INTERSECT_TYPE:
+ increment= 1;
+ curr_op_type= INTERSECT_DISTINCT;
+ break;
+ default: DBUG_ASSERT(0);
+ }
+ if (!thd->lex->current_select->distinct)
+ /* change type from DISTINCT to ALL */
+ curr_op_type= (set_op_type)(curr_op_type + 1);
+
+ duplicate_cnt= table->field[addon_cnt - 1];
+ if (addon_cnt == 2)
+ additional_cnt= table->field[addon_cnt - 2];
+ else
+ additional_cnt= NULL;
+}
+
+
+/*
+ @brief
+ Fill temporary tables for operations need extra fields
+
+ @detail
+ - If this operation is not distinct, we try to find it and increase the
+ counter by "increment" setted in select_unit_ext::change_select().
+
+ - If it is distinct, for UNION we write this record; for INTERSECT we
+ try to find it and increase the intersect counter if found; for EXCEPT
+ we try to find it and delete that record if found.
+
+*/
+
+int select_unit_ext::send_data(List<Item> &values)
+{
+ int rc= 0;
+ int not_reported_error= 0;
+ int find_res;
+ if (unit->offset_limit_cnt)
+ {
+ /* using limit offset,count */
+ unit->offset_limit_cnt--;
+ return 0;
+ }
+ if (thd->killed == ABORT_QUERY)
+ return 0;
+ if (table->no_rows_with_nulls)
+ table->null_catch_flags= CHECK_ROW_FOR_NULLS_TO_REJECT;
+
+ fill_record(thd, table, table->field + addon_cnt, values, true, false);
+ /* set up initial values for records to be written */
+ if ( step == UNION_TYPE )
+ {
+ /* set duplicate counter to 1 */
+ duplicate_cnt->store((longlong) 1, 1);
+ /* set the other counter to 0 */
+ if (curr_op_type == INTERSECT_ALL)
+ additional_cnt->store((longlong) 0, 1);
+ }
+
+ if (unlikely(thd->is_error()))
+ {
+ rc= 1;
+ if (unlikely(not_reported_error))
+ {
+ DBUG_ASSERT(rc);
+ table->file->print_error(not_reported_error, MYF(0));
+ }
+ return rc;
+ }
+ if (table->no_rows_with_nulls)
+ {
+ table->null_catch_flags&= ~CHECK_ROW_FOR_NULLS_TO_REJECT;
+ if (table->null_catch_flags)
+ {
+ if (unlikely(not_reported_error))
+ {
+ DBUG_ASSERT(rc);
+ table->file->print_error(not_reported_error, MYF(0));
+ }
+ return rc;
+ }
+ }
+
+ switch(curr_op_type)
+ {
+ case UNION_ALL:
+ if (!is_index_enabled ||
+ (find_res= table->file->find_unique_row(table->record[0], 0)))
+ {
+ rc= write_record();
+ /* no reaction with conversion */
+ if (rc == -2)
+ rc= 0;
+ }
+ else
+ {
+ longlong cnt= duplicate_cnt->val_int() + increment;
+ not_reported_error= update_counter(duplicate_cnt, cnt);
+ DBUG_ASSERT(!table->triggers);
+ rc= MY_TEST(not_reported_error);
+ }
+ break;
+
+ case EXCEPT_ALL:
+ if (!(find_res= table->file->find_unique_row(table->record[0], 0)))
+ {
+ longlong cnt= duplicate_cnt->val_int() + increment;
+ if (cnt == 0)
+ rc= delete_record();
+ else
+ {
+ not_reported_error= update_counter(duplicate_cnt, cnt);
+ DBUG_ASSERT(!table->triggers);
+ rc= MY_TEST(not_reported_error);
+ }
+ }
+ break;
+
+ case INTERSECT_ALL:
+ if (!(find_res= table->file->find_unique_row(table->record[0], 0)))
+ {
+ longlong cnt= duplicate_cnt->val_int() + increment;
+ if (cnt <= additional_cnt->val_int())
+ {
+ not_reported_error= update_counter(duplicate_cnt, cnt);
+ DBUG_ASSERT(!table->triggers);
+ rc= MY_TEST(not_reported_error);
+ }
+ }
+ break;
+
+ case UNION_DISTINCT:
+ rc= write_record();
+ /* no reaction with conversion */
+ if (rc == -2)
+ rc= 0;
+ break;
+
+ case EXCEPT_DISTINCT:
+ if (!(find_res= table->file->find_unique_row(table->record[0], 0)))
+ rc= delete_record();
+ else
+ rc= not_reported_error= (find_res != 1);
+ break;
+
+ case INTERSECT_DISTINCT:
+ if (!(find_res= table->file->find_unique_row(table->record[0], 0)))
+ {
+ if (additional_cnt->val_int() == prev_step)
+ {
+ not_reported_error= update_counter(additional_cnt, curr_step);
+ rc= MY_TEST(not_reported_error);
+ DBUG_ASSERT(rc != HA_ERR_RECORD_IS_THE_SAME);
+ }
+ else if (additional_cnt->val_int() != curr_step)
+ rc= delete_record();
+ }
+ else
+ rc= not_reported_error= (find_res != 1);
+ break;
+
+ default:
+ DBUG_ASSERT(0);
+ }
+
+ if (unlikely(not_reported_error))
+ {
+ DBUG_ASSERT(rc);
+ table->file->print_error(not_reported_error, MYF(0));
+ }
+ return rc;
+}
+
+
+/*
+ @brief
+ Do post-operation after a operator
+
+ @detail
+ We need to scan in these cases:
+ - If this operation is DISTINCT and next is ALL,
+ duplicate counter needs to be set to 1.
+ - If this operation is INTERSECT ALL and counter needs to be updated.
+ - If next operation is INTERSECT ALL,
+ set up the second extra field (called "intersect_counter") to 0.
+ this extra field counts records in the second operand.
+
+ If this operation is equal to "union_distinct" or is the last operation,
+ we'll disable index. Then if this operation is ALL we'll unfold records.
+*/
+
+bool select_unit_ext::send_eof()
+{
+ int error= 0;
+ SELECT_LEX *curr_sl= thd->lex->current_select;
+ SELECT_LEX *next_sl= curr_sl->next_select();
+ bool is_next_distinct= next_sl && next_sl->distinct;
+ bool is_next_intersect_all=
+ next_sl &&
+ next_sl->get_linkage() == INTERSECT_TYPE &&
+ !next_sl->distinct;
+ bool need_unfold= (disable_index_if_needed(curr_sl) &&
+ !curr_sl->distinct);
+
+ if (((curr_sl->distinct && !is_next_distinct) ||
+ curr_op_type == INTERSECT_ALL ||
+ is_next_intersect_all) &&
+ !need_unfold)
+ {
+ if (!next_sl)
+ DBUG_ASSERT(curr_op_type != INTERSECT_ALL);
+ bool need_update_row;
+ if (unlikely(table->file->ha_rnd_init_with_error(1)))
+ return 1;
+ do
+ {
+ need_update_row= false;
+ if (unlikely(error= table->file->ha_rnd_next(table->record[0])))
+ {
+ if (error == HA_ERR_END_OF_FILE)
+ {
+ error= 0;
+ break;
+ }
+ break;
+ }
+ store_record(table, record[1]);
+
+ if (curr_sl->distinct && !is_next_distinct)
+ {
+ /* set duplicate counter to 1 if next operation is ALL */
+ duplicate_cnt->store(1, 0);
+ need_update_row= true;
+ }
+
+ if (is_next_intersect_all)
+ {
+ longlong d_cnt_val= duplicate_cnt->val_int();
+ if (d_cnt_val == 0)
+ error= delete_record();
+ else
+ {
+ if (curr_op_type == INTERSECT_ALL)
+ {
+ longlong a_cnt_val= additional_cnt->val_int();
+ if (a_cnt_val < d_cnt_val)
+ d_cnt_val= a_cnt_val;
+ }
+ additional_cnt->store(d_cnt_val, 0);
+ duplicate_cnt->store((longlong)0, 0);
+ need_update_row= true;
+ }
+ }
+
+ if (need_update_row)
+ error= table->file->ha_update_tmp_row(table->record[1],
+ table->record[0]);
+ } while (likely(!error));
+ table->file->ha_rnd_end();
+ }
+
+ /* unfold */
+ else if (need_unfold)
+ {
+ /* unfold if is ALL operation */
+ ha_rows dup_cnt;
+ if (unlikely(table->file->ha_rnd_init_with_error(1)))
+ return 1;
+ do
+ {
+ if (unlikely(error= table->file->ha_rnd_next(table->record[0])))
+ {
+ if (error == HA_ERR_END_OF_FILE)
+ {
+ error= 0;
+ break;
+ }
+ break;
+ }
+ dup_cnt= (ha_rows)duplicate_cnt->val_int();
+ /* delete record if not exist in the second operand */
+ if (dup_cnt == 0)
+ {
+ error= delete_record();
+ continue;
+ }
+ if (curr_op_type == INTERSECT_ALL)
+ {
+ longlong add_cnt= additional_cnt->val_int();
+ if (dup_cnt > add_cnt && add_cnt > 0)
+ dup_cnt= (ha_rows)add_cnt;
+ }
+
+ if (dup_cnt == 1)
+ continue;
+
+ duplicate_cnt->store((longlong)1, 0);
+ if (additional_cnt)
+ additional_cnt->store((longlong)0, 0);
+ error= table->file->ha_update_tmp_row(table->record[1],
+ table->record[0]);
+ if (unlikely(error))
+ break;
+
+ if (unfold_record(dup_cnt) == -1)
+ {
+ /* restart the scan */
+ if (unlikely(table->file->ha_rnd_init_with_error(1)))
+ return 1;
+
+ duplicate_cnt= table->field[addon_cnt - 1];
+ if (addon_cnt == 2)
+ additional_cnt= table->field[addon_cnt - 2];
+ else
+ additional_cnt= NULL;
+ continue;
+ }
+ } while (likely(!error));
+ table->file->ha_rnd_end();
+ }
+
+ if (unlikely(error))
+ table->file->print_error(error, MYF(0));
+
+ return (MY_TEST(error));
+}
+
void select_union_recursive::cleanup()
{
if (table)
@@ -818,6 +1267,29 @@ bool st_select_lex_unit::join_union_item_types(THD *thd_arg,
}
+bool init_item_int(THD* thd, Item_int* &item)
+{
+ if (!item)
+ {
+ Query_arena *arena, backup_arena;
+ arena= thd->activate_stmt_arena_if_needed(&backup_arena);
+
+ item= new (thd->mem_root) Item_int(thd, 0);
+
+ if (arena)
+ thd->restore_active_arena(arena, &backup_arena);
+
+ if (!item)
+ return false;
+ }
+ else
+ {
+ item->value= 0;
+ }
+ return true;
+}
+
+
bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
select_result *sel_result,
ulong additional_options)
@@ -829,7 +1301,8 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
uint union_part_count= 0;
select_result *tmp_result;
bool is_union_select;
- bool have_except= FALSE, have_intersect= FALSE;
+ bool have_except= false, have_intersect= false,
+ have_except_all_or_intersect_all= false;
bool instantiate_tmp_table= false;
bool single_tvc= !first_sl->next_select() && first_sl->tvc &&
!fake_select_lex;
@@ -867,7 +1340,7 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
max/min subquery (ALL/ANY optimization)
*/
result= sel_result;
-
+
if (prepared)
{
if (describe)
@@ -906,15 +1379,27 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
found_rows_for_union= first_sl->options & OPTION_FOUND_ROWS;
is_union_select= is_unit_op() || fake_select_lex || single_tvc;
+ /* will only optimize once */
+ if (!bag_set_op_optimized && !is_recursive)
+ {
+ optimize_bag_operation(false);
+ }
+
for (SELECT_LEX *s= first_sl; s; s= s->next_select())
{
switch (s->linkage)
{
case INTERSECT_TYPE:
have_intersect= TRUE;
+ if (!s->distinct){
+ have_except_all_or_intersect_all= true;
+ }
break;
case EXCEPT_TYPE:
have_except= TRUE;
+ if (!s->distinct){
+ have_except_all_or_intersect_all= TRUE;
+ }
break;
default:
break;
@@ -940,7 +1425,19 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
else
{
if (!is_recursive)
- union_result= new (thd->mem_root) select_unit(thd);
+ /*
+ class "select_unit_ext" handles query contains EXCEPT ALL and / or
+ INTERSECT ALL. Others are handled by class "select_unit"
+ If have EXCEPT ALL or INTERSECT ALL in the query. First operand
+ should be UNION ALL
+ */
+ if (have_except_all_or_intersect_all)
+ {
+ union_result= new (thd->mem_root) select_unit_ext(thd);
+ first_sl->distinct= false;
+ }
+ else
+ union_result= new (thd->mem_root) select_unit(thd);
else
{
with_element->rec_result=
@@ -1080,6 +1577,10 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
instantiate_tmp_table, false,
0))
goto err;
+ if (have_except_all_or_intersect_all)
+ {
+ union_result->init();
+ }
if (!derived_arg->table)
{
derived_arg->table= with_element->rec_result->rec_tables.head();
@@ -1091,6 +1592,7 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
}
}
}
+
// In case of a non-recursive UNION, join data types for all UNION parts.
if (!is_recursive && join_union_item_types(thd, types, union_part_count))
goto err;
@@ -1166,48 +1668,42 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
if (global_parameters()->ftfunc_list->elements)
create_options= create_options | TMP_TABLE_FORCE_MYISAM;
+ /* extra field counter */
+ uint hidden= 0;
+ Item_int *addon_fields[2]= {0};
if (!is_recursive)
{
- uint hidden= 0;
- if (have_intersect)
+ if (have_except_all_or_intersect_all)
{
- hidden= 1;
- if (!intersect_mark)
- {
- /*
- For intersect we add a hidden column first that contains
- the current select number of the time when the row was
- added to the temporary table
- */
-
- Query_arena *arena, backup_arena;
- arena= thd->activate_stmt_arena_if_needed(&backup_arena);
-
- intersect_mark= new (thd->mem_root) Item_int(thd, 0);
-
- if (arena)
- thd->restore_active_arena(arena, &backup_arena);
+ /* add duplicate_count */
+ ++hidden;
+ }
+ /* add intersect_count */
+ if (have_intersect)
+ ++hidden;
- if (!intersect_mark)
- goto err;
- }
- else
- intersect_mark->value= 0; //reset
- types.push_front(union_result->intersect_mark= intersect_mark);
- union_result->intersect_mark->name.str= "___";
- union_result->intersect_mark->name.length= 3;
+ for(uint i= 0; i< hidden; i++)
+ {
+ init_item_int(thd, addon_fields[i]);
+ types.push_front(addon_fields[i]);
+ addon_fields[i]->name.str= i ? "__CNT_1" : "__CNT_2";
+ addon_fields[i]->name.length= 7;
}
bool error=
union_result->create_result_table(thd, &types,
- MY_TEST(union_distinct),
+ MY_TEST(union_distinct) ||
+ have_except_all_or_intersect_all ||
+ have_intersect,
create_options, &empty_clex_str, false,
instantiate_tmp_table, false,
hidden);
- if (intersect_mark)
+ union_result->addon_cnt= hidden;
+ for (uint i= 0; i < hidden; i++)
types.pop();
if (unlikely(error))
goto err;
}
+
if (fake_select_lex && !fake_select_lex->first_cond_optimization)
{
save_tablenr= result_table_list.tablenr_exec;
@@ -1235,9 +1731,8 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
arena= thd->activate_stmt_arena_if_needed(&backup_arena);
saved_error= table->fill_item_list(&item_list);
- // Item_list is inherited from 'types', so there could be the counter
- if (intersect_mark)
- item_list.pop(); // remove intersect counter
+ for (uint i= 0; i < hidden; i++)
+ item_list.pop();
if (arena)
thd->restore_active_arena(arena, &backup_arena);
@@ -1282,7 +1777,7 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
We're in execution of a prepared statement or stored procedure:
reset field items to point at fields from the created temporary table.
*/
- table->reset_item_list(&item_list, intersect_mark ? 1 : 0);
+ table->reset_item_list(&item_list, hidden);
}
if (fake_select_lex != NULL &&
(thd->stmt_arena->is_stmt_prepare() ||
@@ -1316,9 +1811,170 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
/**
+ @brief
+ Optimize a sequence of set operations
+
+ @param first_sl first select of the level now under processing
+
+ @details
+ The method optimizes with the following rules:
+ - (1)If a subsequence of INTERSECT contains at least one INTERSECT DISTINCT
+ or this subsequence is followed by UNION/EXCEPT DISTINCT then all
+ elements in the subsequence can changed for INTERSECT DISTINCT
+ - (2)If previous set operation is DISTINCT then EXCEPT ALL can be replaced
+ for EXCEPT DISTINCT
+ - (3)If UNION DISTINCT / EXCEPT DISTINCT follows a subsequence of UNION ALL
+ then all set operations of this subsequence can be replaced for
+ UNION DISTINCT
+
+ For derived table it will look up outer select, and do optimize based on
+ outer select.
+
+ Variable "union_distinct" will be updated in the end.
+ Not compatible with Oracle Mode.
+*/
+
+void st_select_lex_unit::optimize_bag_operation(bool is_outer_distinct)
+{
+ /*
+ skip run optimize for:
+ ORACLE MODE
+ CREATE VIEW
+ PREPARE ... FROM
+ recursive
+ */
+ if ((thd->variables.sql_mode & MODE_ORACLE) ||
+ (thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW) ||
+ (fake_select_lex != NULL && thd->stmt_arena->is_stmt_prepare()) ||
+ (with_element && with_element->is_recursive ))
+ return;
+ DBUG_ASSERT(!bag_set_op_optimized);
+
+ SELECT_LEX *sl;
+ /* INTERSECT subsequence can occur only at the very beginning */
+ /* The first select with linkage == INTERSECT_TYPE */
+ SELECT_LEX *intersect_start= NULL;
+ /* The first select after the INTERSECT subsequence */
+ SELECT_LEX *intersect_end= NULL;
+ /*
+ Will point to the last node before UNION ALL subsequence.
+ Index can be disable there.
+ */
+ SELECT_LEX *disable_index= NULL;
+ /*
+ True if there is a select with:
+ linkage == INTERSECT_TYPE && distinct==true
+ */
+ bool any_intersect_distinct= false;
+ SELECT_LEX *prev_sl= first_select();
+
+ /* process INTERSECT subsequence in the begining */
+ for (sl= prev_sl->next_select(); sl; prev_sl= sl, sl= sl->next_select())
+ {
+ if (sl->linkage != INTERSECT_TYPE)
+ {
+ intersect_end= sl;
+ break;
+ }
+ else
+ {
+ if (!intersect_start)
+ intersect_start= sl;
+ if (sl->distinct)
+ {
+ any_intersect_distinct= true;
+ disable_index= sl;
+ }
+ }
+ }
+
+ /* if subquery only contains INTERSECT and outer is UNION DISTINCT*/
+ if (!sl && is_outer_distinct)
+ any_intersect_distinct= true;
+
+ /* The first select of the current UNION ALL subsequence */
+ SELECT_LEX *union_all_start= NULL;
+ for ( ; sl; prev_sl= sl, sl= sl->next_select())
+ {
+ DBUG_ASSERT (sl->linkage != INTERSECT_TYPE);
+ if (!sl->distinct)
+ {
+ if (sl->linkage == UNION_TYPE)
+ {
+ if (!union_all_start)
+ {
+ union_all_start= sl;
+ }
+ }
+ else
+ {
+ DBUG_ASSERT (sl->linkage == EXCEPT_TYPE);
+ union_all_start= NULL;
+ if (prev_sl->distinct && prev_sl->is_set_op())
+ {
+ sl->distinct= true;
+ disable_index= sl;
+ }
+ }
+ }
+ else
+ { /* sl->distinct == true */
+ for (SELECT_LEX *si= union_all_start; si && si != sl; si= si->next_select())
+ {
+ si->distinct= true;
+ }
+ union_all_start= NULL;
+ disable_index= sl;
+ }
+ }
+
+ if (is_outer_distinct)
+ {
+ for (SELECT_LEX *si= union_all_start; si && si != sl; si= si->next_select())
+ {
+ si->distinct= true;
+ }
+ union_all_start= NULL;
+ }
+
+ if (any_intersect_distinct ||
+ (intersect_end != NULL && intersect_end->distinct))
+ {
+ for (sl= intersect_start; sl && sl != intersect_end; sl= sl->next_select())
+ {
+ sl->distinct= true;
+ if (disable_index && disable_index->linkage == INTERSECT_TYPE)
+ disable_index= sl;
+ }
+ }
+ /*
+ if disable_index points to a INTERSECT, based on rule 1 we can set it
+ to the last INTERSECT node.
+ */
+ if (disable_index && disable_index->linkage == INTERSECT_TYPE &&
+ intersect_end && intersect_end->distinct)
+ disable_index= intersect_end;
+ /* union_distinct controls when to disable index */
+ union_distinct= disable_index;
+
+ /* recursive call this function for whole lex tree */
+ for(sl= first_select(); sl; sl= sl->next_select())
+ {
+ if (sl->is_unit_nest() &&
+ sl->first_inner_unit() &&
+ !sl->first_inner_unit()->bag_set_op_optimized)
+ sl->first_inner_unit()->optimize_bag_operation(sl->distinct);
+ }
+
+ /* mark as optimized */
+ bag_set_op_optimized= true;
+}
+
+
+/**
Run optimization phase.
- @return FALSE unit successfully passed optimization phase.
+ @return false unit successfully passed optimization phase.
@return TRUE an error occur.
*/
bool st_select_lex_unit::optimize()
@@ -1328,10 +1984,10 @@ bool st_select_lex_unit::optimize()
DBUG_ENTER("st_select_lex_unit::optimize");
if (optimized && !uncacheable && !describe)
- DBUG_RETURN(FALSE);
+ DBUG_RETURN(false);
if (with_element && with_element->is_recursive && optimize_started)
- DBUG_RETURN(FALSE);
+ DBUG_RETURN(false);
optimize_started= true;
if (uncacheable || !item || !item->assigned() || describe)
@@ -1351,9 +2007,12 @@ bool st_select_lex_unit::optimize()
table->file->info(HA_STATUS_VARIABLE);
}
/* re-enabling indexes for next subselect iteration */
- if (union_distinct && table->file->ha_enable_indexes(HA_KEY_SWITCH_ALL))
+ if ((union_result->force_enable_index_if_needed() || union_distinct))
{
- DBUG_ASSERT(0);
+ if(table->file->ha_enable_indexes(HA_KEY_SWITCH_ALL))
+ DBUG_ASSERT(0);
+ else
+ table->no_keyread= 0;
}
}
for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
@@ -1499,7 +2158,7 @@ bool st_select_lex_unit::exec()
}
else
{
- sl->join->select_options=
+ sl->join->select_options=
(select_limit_cnt == HA_POS_ERROR || sl->braces) ?
sl->options & ~OPTION_FOUND_ROWS : sl->options | found_rows_for_union;
saved_error= sl->join->optimize();
@@ -1512,7 +2171,7 @@ bool st_select_lex_unit::exec()
sl->tvc->exec(sl);
else
sl->join->exec();
- if (sl == union_distinct && !(with_element && with_element->is_recursive))
+ if (sl == union_distinct && !have_except_all_or_intersect_all)
{
// This is UNION DISTINCT, so there should be a fake_select_lex
DBUG_ASSERT(fake_select_lex != NULL);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index edf6b76..a09af12 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -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; }
;
/*
diff --git a/storage/heap/hp_write.c b/storage/heap/hp_write.c
index 877c1bc..670f628 100644
--- a/storage/heap/hp_write.c
+++ b/storage/heap/hp_write.c
@@ -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;
[View Less]
1
0

[Commits] 7c07d35: MDEV-18844 Implement EXCEPT ALL and INTERSECT ALL operations
by IgorBabaev 01 Sep '19
by IgorBabaev 01 Sep '19
01 Sep '19
revision-id: 7c07d358c4b3b505dde4f9c1fbc204830e0da7aa (mariadb-10.4.4-286-g7c07d35)
parent(s): afe969ba05faece41fdef1275e9b9c510081805b
author: Ruihang Xia
committer: Igor Babaev
timestamp: 2019-08-31 17:49:03 -0700
message:
MDEV-18844 Implement EXCEPT ALL and INTERSECT ALL operations
---
mysql-test/main/brackets.result | 2 +-
mysql-test/main/except.result | 2 -
mysql-test/main/except.test | 2 -
mysql-test/main/except_all.result …
[View More]| 660 +++++++++++++++
mysql-test/main/except_all.test | 99 +++
mysql-test/main/intersect.result | 44 +-
mysql-test/main/intersect.test | 22 +-
mysql-test/main/intersect_all.result | 888 ++++++++++++++++++++
mysql-test/main/intersect_all.test | 328 ++++++++
mysql-test/main/set_operation.result | 1157 +++++++++++++++++++++++++++
mysql-test/main/set_operation.test | 526 ++++++++++++
mysql-test/main/set_operation_oracle.result | 75 ++
mysql-test/main/set_operation_oracle.test | 65 ++
sql/sql_class.h | 151 +++-
sql/sql_lex.cc | 15 +-
sql/sql_lex.h | 40 +-
sql/sql_tvc.cc | 1 +
sql/sql_union.cc | 947 ++++++++++++++++++----
sql/sql_yacc.yy | 8 +-
storage/heap/hp_write.c | 26 +-
20 files changed, 4807 insertions(+), 251 deletions(-)
diff --git a/mysql-test/main/brackets.result b/mysql-test/main/brackets.result
index e14bef9..8fc54e6 100644
--- a/mysql-test/main/brackets.result
+++ b/mysql-test/main/brackets.result
@@ -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
diff --git a/mysql-test/main/except.result b/mysql-test/main/except.result
index 9c5a3ea..3416ad0 100644
--- a/mysql-test/main/except.result
+++ b/mysql-test/main/except.result
@@ -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");
diff --git a/mysql-test/main/except.test b/mysql-test/main/except.test
index 32aa0b9..de387cc 100644
--- a/mysql-test/main/except.test
+++ b/mysql-test/main/except.test
@@ -66,8 +66,6 @@ select 1 as a from dual except select 1 from dual;
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;
diff --git a/mysql-test/main/except_all.result b/mysql-test/main/except_all.result
new file mode 100644
index 0000000..19ff9f3
--- /dev/null
+++ b/mysql-test/main/except_all.result
@@ -0,0 +1,660 @@
+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;
+a b
+4 4
+select * from t1 except all select * from t2;
+a b
+4 4
+2 2
+4 4
+4 4
+select * from t1 except all select c+1,d+1 from t2;
+a b
+1 1
+4 4
+(select * from t1) except all (select * from t2);
+a b
+4 4
+2 2
+4 4
+4 4
+select * from ((select * from t1) except all (select * from t2)) a;
+a b
+4 4
+2 2
+4 4
+4 4
+select * from ((select a from t1) except all (select c from t2)) a;
+a
+4
+2
+4
+4
+select * from t1 except all select * from t1 union all select * from t1 union all select * from t1 except select * from t2;
+a b
+4 4
+select * from t1 except all select * from t1 union all select * from t1 union all select * from t1 except all select * from t2;
+a b
+4 4
+2 2
+4 4
+4 4
+4 4
+4 4
+4 4
+2 2
+2 2
+select * from (select * from t1 except all select * from t2) q1 except all select * from (select * from t1 except all select * from t2) q2;
+a b
+EXPLAIN select * from t1 except all select * from t2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 7
+2 EXCEPT t2 ALL NULL NULL NULL NULL 7
+NULL EXCEPT RESULT <except1,2> ALL NULL NULL NULL NULL NULL
+EXPLAIN format=json select * from t1 except all select * from t2;
+EXPLAIN
+{
+ "query_block": {
+ "union_result": {
+ "table_name": "<except1,2>",
+ "access_type": "ALL",
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 7,
+ "filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 2,
+ "operation": "EXCEPT",
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 7,
+ "filtered": 100
+ }
+ }
+ }
+ ]
+ }
+ }
+}
+EXPLAIN extended (select * from t1) except all (select * from t2);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 7 100.00
+2 EXCEPT t2 ALL NULL NULL NULL NULL 7 100.00
+NULL EXCEPT RESULT <except1,2> 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`) except all (/* select#2 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2`)
+EXPLAIN extended select * from ((select * from t1) except all (select * from t2)) a;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 7 100.00
+2 DERIVED t1 ALL NULL NULL NULL NULL 7 100.00
+3 EXCEPT t2 ALL NULL NULL NULL NULL 7 100.00
+NULL EXCEPT RESULT <except2,3> ALL NULL NULL NULL NULL NULL NULL
+Warnings:
+Note 1003 /* select#1 */ select `a`.`a` AS `a`,`a`.`b` AS `b` from (/* select#2 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` except all (/* select#3 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2`)) `a`
+ANALYZE format=json select * from ((select a,b from t1) except all (select c,d from t2)) a;
+ANALYZE
+{
+ "query_block": {
+ "select_id": 1,
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 7,
+ "r_rows": 4,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100,
+ "materialized": {
+ "query_block": {
+ "union_result": {
+ "table_name": "<except2,3>",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "r_rows": 4,
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 2,
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 7,
+ "r_rows": 7,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 3,
+ "operation": "EXCEPT",
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 7,
+ "r_rows": 7,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+}
+ANALYZE format=json select * from ((select a from t1) except all (select c from t2)) a;
+ANALYZE
+{
+ "query_block": {
+ "select_id": 1,
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 7,
+ "r_rows": 4,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100,
+ "materialized": {
+ "query_block": {
+ "union_result": {
+ "table_name": "<except2,3>",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "r_rows": 4,
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 2,
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 7,
+ "r_rows": 7,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 3,
+ "operation": "EXCEPT",
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 7,
+ "r_rows": 7,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+}
+select * from ((select a from t1) except all (select c from t2)) a;
+a
+4
+2
+4
+4
+prepare stmt from "(select a,b from t1) except all (select c,d from t2)";
+execute stmt;
+a b
+4 4
+2 2
+4 4
+4 4
+execute stmt;
+a b
+4 4
+2 2
+4 4
+4 4
+prepare stmt from "select * from ((select a,b from t1) except all (select c,d from t2)) a";
+execute stmt;
+a b
+4 4
+2 2
+4 4
+4 4
+execute stmt;
+a b
+4 4
+2 2
+4 4
+4 4
+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);
+a b e f
+1 1 4 4
+2 2 4 4
+1 1 5 5
+2 2 5 5
+1 1 4 4
+2 2 4 4
+2 2 5 5
+select * from ((select a,b,e,f from t1,t3) except all (select c,d,g,h from t2,t4)) t;
+a b e f
+1 1 4 4
+2 2 4 4
+1 1 5 5
+2 2 5 5
+1 1 4 4
+2 2 4 4
+2 2 5 5
+(select * from t1,t3) except all (select * from t2,t4);
+a b e f
+1 1 4 4
+2 2 4 4
+1 1 5 5
+2 2 5 5
+1 1 4 4
+2 2 4 4
+2 2 5 5
+(select a,b,e from t1,t3) except all (select c,d,g from t2,t4);
+a b e
+1 1 4
+2 2 4
+1 1 5
+2 2 5
+1 1 4
+2 2 4
+2 2 5
+EXPLAIN (select a,b,e,f from t1,t3) except all (select c,d,g,h from t2,t4);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3
+1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using join buffer (flat, BNL join)
+2 EXCEPT t2 ALL NULL NULL NULL NULL 2
+2 EXCEPT t4 ALL NULL NULL NULL NULL 3 Using join buffer (flat, BNL join)
+NULL EXCEPT RESULT <except1,2> ALL NULL NULL NULL NULL NULL
+EXPLAIN select * from ((select a,b,e,f from t1,t3) except all (select c,d,g,h from t2,t4)) t;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 9
+2 DERIVED t1 ALL NULL NULL NULL NULL 3
+2 DERIVED t3 ALL NULL NULL NULL NULL 3 Using join buffer (flat, BNL join)
+3 EXCEPT t2 ALL NULL NULL NULL NULL 2
+3 EXCEPT t4 ALL NULL NULL NULL NULL 3 Using join buffer (flat, BNL join)
+NULL EXCEPT RESULT <except2,3> ALL NULL NULL NULL NULL NULL
+EXPLAIN extended select * from ((select a,b,e,f from t1,t3) except all (select c,d,g,h from t2,t4)) t;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 9 100.00
+2 DERIVED t1 ALL NULL NULL NULL NULL 3 100.00
+2 DERIVED t3 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join)
+3 EXCEPT t2 ALL NULL NULL NULL NULL 2 100.00
+3 EXCEPT t4 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join)
+NULL EXCEPT RESULT <except2,3> ALL NULL NULL NULL NULL NULL NULL
+Warnings:
+Note 1003 /* select#1 */ select `t`.`a` AS `a`,`t`.`b` AS `b`,`t`.`e` AS `e`,`t`.`f` AS `f` from (/* select#2 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t1` join `test`.`t3` except all (/* select#3 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d`,`test`.`t4`.`g` AS `g`,`test`.`t4`.`h` AS `h` from `test`.`t2` join `test`.`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;
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ALL",
+ "rows": 9,
+ "filtered": 100,
+ "materialized": {
+ "query_block": {
+ "union_result": {
+ "table_name": "<except2,3>",
+ "access_type": "ALL",
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 2,
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 3,
+ "filtered": 100
+ },
+ "block-nl-join": {
+ "table": {
+ "table_name": "t3",
+ "access_type": "ALL",
+ "rows": 3,
+ "filtered": 100
+ },
+ "buffer_type": "flat",
+ "buffer_size": "119",
+ "join_type": "BNL"
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 3,
+ "operation": "EXCEPT",
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 2,
+ "filtered": 100
+ },
+ "block-nl-join": {
+ "table": {
+ "table_name": "t4",
+ "access_type": "ALL",
+ "rows": 3,
+ "filtered": 100
+ },
+ "buffer_type": "flat",
+ "buffer_size": "119",
+ "join_type": "BNL"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+}
+ANALYZE format=json (select a,b,e,f from t1,t3) except all (select c,d,g,h from t2,t4);
+ANALYZE
+{
+ "query_block": {
+ "union_result": {
+ "table_name": "<except1,2>",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "r_rows": 7,
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 1,
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 3,
+ "r_rows": 3,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ },
+ "block-nl-join": {
+ "table": {
+ "table_name": "t3",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 3,
+ "r_rows": 3,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ },
+ "buffer_type": "flat",
+ "buffer_size": "119",
+ "join_type": "BNL",
+ "r_filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 2,
+ "operation": "EXCEPT",
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 2,
+ "r_rows": 2,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ },
+ "block-nl-join": {
+ "table": {
+ "table_name": "t4",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 3,
+ "r_rows": 3,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ },
+ "buffer_type": "flat",
+ "buffer_size": "119",
+ "join_type": "BNL",
+ "r_filtered": 100
+ }
+ }
+ }
+ ]
+ }
+ }
+}
+ANALYZE format=json select * from ((select a,b,e,f from t1,t3) except all (select c,d,g,h from t2,t4)) t;
+ANALYZE
+{
+ "query_block": {
+ "select_id": 1,
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 9,
+ "r_rows": 7,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100,
+ "materialized": {
+ "query_block": {
+ "union_result": {
+ "table_name": "<except2,3>",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "r_rows": 7,
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 2,
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 3,
+ "r_rows": 3,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ },
+ "block-nl-join": {
+ "table": {
+ "table_name": "t3",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 3,
+ "r_rows": 3,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ },
+ "buffer_type": "flat",
+ "buffer_size": "119",
+ "join_type": "BNL",
+ "r_filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 3,
+ "operation": "EXCEPT",
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 2,
+ "r_rows": 2,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ },
+ "block-nl-join": {
+ "table": {
+ "table_name": "t4",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 3,
+ "r_rows": 3,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ },
+ "buffer_type": "flat",
+ "buffer_size": "119",
+ "join_type": "BNL",
+ "r_filtered": 100
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+}
+prepare stmt from "(select a,b,e,f from t1,t3) except all (select c,d,g,h from t2,t4)";
+execute stmt;
+a b e f
+1 1 4 4
+2 2 4 4
+1 1 5 5
+2 2 5 5
+1 1 4 4
+2 2 4 4
+2 2 5 5
+execute stmt;
+a b e f
+1 1 4 4
+2 2 4 4
+1 1 5 5
+2 2 5 5
+1 1 4 4
+2 2 4 4
+2 2 5 5
+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;
+a b e f
+1 1 4 4
+2 2 4 4
+1 1 5 5
+2 2 5 5
+1 1 4 4
+2 2 4 4
+2 2 5 5
+execute stmt;
+a b e f
+1 1 4 4
+2 2 4 4
+1 1 5 5
+2 2 5 5
+1 1 4 4
+2 2 4 4
+2 2 5 5
+drop tables t1,t2,t3,t4;
+select 1 as a from dual except all select 1 from dual;
+a
+(select 1 from dual) except all (select 1 from dual);
+1
+(select 1 from dual into @v) 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 'into @v) except all (select 1 from dual)' at line 1
+select 1 from dual ORDER BY 1 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 'except all select 1 from dual' at line 1
+select 1 as a from dual union all select 1 from dual;
+a
+1
+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"),(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);
+a b b1
+1 ddd sdfrrwwww
+2 fgh dffggtt
+create table t3 (select a,b,b1 from t1) except all (select c,d,d1 from t2);
+show create table t3;
+Table Create Table
+t3 CREATE TABLE `t3` (
+ `a` int(11) DEFAULT NULL,
+ `b` blob DEFAULT NULL,
+ `b1` blob DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+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 );
+i
+drop table t;
diff --git a/mysql-test/main/except_all.test b/mysql-test/main/except_all.test
new file mode 100644
index 0000000..f873b22
--- /dev/null
+++ b/mysql-test/main/except_all.test
@@ -0,0 +1,99 @@
+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
diff --git a/mysql-test/main/intersect.result b/mysql-test/main/intersect.result
index bd88243..034018d 100644
--- a/mysql-test/main/intersect.result
+++ b/mysql-test/main/intersect.result
@@ -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
diff --git a/mysql-test/main/intersect.test b/mysql-test/main/intersect.test
index 616a833..a99aa92 100644
--- a/mysql-test/main/intersect.test
+++ b/mysql-test/main/intersect.test
@@ -65,8 +65,6 @@ select 1 as a from dual intersect select 1 from dual;
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 +145,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 +152,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 +296,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 +315,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
diff --git a/mysql-test/main/intersect_all.result b/mysql-test/main/intersect_all.result
new file mode 100644
index 0000000..66ee060
--- /dev/null
+++ b/mysql-test/main/intersect_all.result
@@ -0,0 +1,888 @@
+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;
+a b
+2 2
+2 2
+(select a,b from t1) intersect all (select c,d from t2);
+a b
+2 2
+2 2
+select * from ((select a,b from t1) intersect all (select c,d from t2)) t;
+a b
+2 2
+2 2
+select * from ((select a from t1) intersect all (select c from t2)) t;
+a
+2
+2
+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);
+a b
+2 2
+2 2
+EXPLAIN (select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 4
+2 INTERSECT t2 ALL NULL NULL NULL NULL 4
+3 INTERSECT t3 ALL NULL NULL NULL NULL 4
+NULL INTERSECT RESULT <intersect1,2,3> ALL NULL NULL NULL NULL NULL
+EXPLAIN extended (select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 4 100.00
+2 INTERSECT t2 ALL NULL NULL NULL NULL 4 100.00
+3 INTERSECT t3 ALL NULL NULL NULL NULL 4 100.00
+NULL INTERSECT RESULT <intersect1,2,3> 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`) intersect all (/* select#2 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2`) intersect all (/* select#3 */ select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`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;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 4 100.00
+2 DERIVED t1 ALL NULL NULL NULL NULL 4 100.00
+3 INTERSECT t2 ALL NULL NULL NULL NULL 4 100.00
+4 INTERSECT t3 ALL NULL NULL NULL NULL 4 100.00
+NULL INTERSECT RESULT <intersect2,3,4> ALL NULL NULL NULL NULL NULL NULL
+Warnings:
+Note 1003 /* select#1 */ select `a`.`a` AS `a`,`a`.`b` AS `b` from (/* select#2 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` intersect all (/* select#3 */ 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`)) `a`
+EXPLAIN format=json (select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3);
+EXPLAIN
+{
+ "query_block": {
+ "union_result": {
+ "table_name": "<intersect1,2,3>",
+ "access_type": "ALL",
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 4,
+ "filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 2,
+ "operation": "INTERSECT",
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 4,
+ "filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 3,
+ "operation": "INTERSECT",
+ "table": {
+ "table_name": "t3",
+ "access_type": "ALL",
+ "rows": 4,
+ "filtered": 100
+ }
+ }
+ }
+ ]
+ }
+ }
+}
+ANALYZE format=json (select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3);
+ANALYZE
+{
+ "query_block": {
+ "union_result": {
+ "table_name": "<intersect1,2,3>",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "r_rows": 2,
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 1,
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 4,
+ "r_rows": 4,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 2,
+ "operation": "INTERSECT",
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 4,
+ "r_rows": 4,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 3,
+ "operation": "INTERSECT",
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t3",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 4,
+ "r_rows": 4,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ }
+ }
+ }
+ ]
+ }
+ }
+}
+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;
+ANALYZE
+{
+ "query_block": {
+ "select_id": 1,
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 4,
+ "r_rows": 2,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100,
+ "materialized": {
+ "query_block": {
+ "union_result": {
+ "table_name": "<intersect2,3,4>",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "r_rows": 2,
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 2,
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 4,
+ "r_rows": 4,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 3,
+ "operation": "INTERSECT",
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 4,
+ "r_rows": 4,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 4,
+ "operation": "INTERSECT",
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t3",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 4,
+ "r_rows": 4,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+}
+select * from ((select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3)) a;
+a b
+2 2
+2 2
+prepare stmt from "(select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3);";
+execute stmt;
+a b
+2 2
+2 2
+execute stmt;
+a b
+2 2
+2 2
+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;
+a b
+2 2
+2 2
+execute stmt;
+a b
+2 2
+2 2
+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);
+a b
+2 2
+2 2
+(select a,b from t1) intersect (select c,d from t2) intersect all (select e,f from t3);
+a b
+2 2
+insert into t3 values (2,2);
+(select a,b from t1) intersect all (select c,d from t2) intersect (select e,f from t3);
+a b
+2 2
+(select a,b from t1) intersect all (select c,e from t2,t3);
+a b
+2 2
+2 2
+2 2
+EXPLAIN (select a,b from t1) intersect all (select c,e from t2,t3);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6
+2 INTERSECT t3 ALL NULL NULL NULL NULL 5
+2 INTERSECT t2 ALL NULL NULL NULL NULL 7 Using join buffer (flat, BNL join)
+NULL INTERSECT RESULT <intersect1,2> ALL NULL NULL NULL NULL NULL
+EXPLAIN extended (select a,b from t1) intersect all (select c,e from t2,t3);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00
+2 INTERSECT t3 ALL NULL NULL NULL NULL 5 100.00
+2 INTERSECT t2 ALL NULL NULL NULL NULL 7 100.00 Using join buffer (flat, BNL join)
+NULL INTERSECT RESULT <intersect1,2> 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`) intersect all (/* select#2 */ select `test`.`t2`.`c` AS `c`,`test`.`t3`.`e` AS `e` from `test`.`t2` join `test`.`t3`)
+EXPLAIN extended select * from ((select a,b from t1) intersect all (select c,e from t2,t3)) a;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 6 100.00
+2 DERIVED t1 ALL NULL NULL NULL NULL 6 100.00
+3 INTERSECT t3 ALL NULL NULL NULL NULL 5 100.00
+3 INTERSECT t2 ALL NULL NULL NULL NULL 7 100.00 Using join buffer (flat, BNL join)
+NULL INTERSECT RESULT <intersect2,3> ALL NULL NULL NULL NULL NULL NULL
+Warnings:
+Note 1003 /* select#1 */ select `a`.`a` AS `a`,`a`.`b` AS `b` from (/* select#2 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` intersect all (/* select#3 */ select `test`.`t2`.`c` AS `c`,`test`.`t3`.`e` AS `e` from `test`.`t2` join `test`.`t3`)) `a`
+EXPLAIN format=json (select a,b from t1) intersect all (select c,e from t2,t3);
+EXPLAIN
+{
+ "query_block": {
+ "union_result": {
+ "table_name": "<intersect1,2>",
+ "access_type": "ALL",
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 6,
+ "filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 2,
+ "operation": "INTERSECT",
+ "table": {
+ "table_name": "t3",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100
+ },
+ "block-nl-join": {
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 7,
+ "filtered": 100
+ },
+ "buffer_type": "flat",
+ "buffer_size": "65",
+ "join_type": "BNL"
+ }
+ }
+ }
+ ]
+ }
+ }
+}
+ANALYZE format=json (select a,b from t1) intersect all (select c,e from t2,t3);
+ANALYZE
+{
+ "query_block": {
+ "union_result": {
+ "table_name": "<intersect1,2>",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "r_rows": 3,
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 1,
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 6,
+ "r_rows": 6,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 2,
+ "operation": "INTERSECT",
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t3",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 5,
+ "r_rows": 5,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ },
+ "block-nl-join": {
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 7,
+ "r_rows": 7,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ },
+ "buffer_type": "flat",
+ "buffer_size": "65",
+ "join_type": "BNL",
+ "r_filtered": 100
+ }
+ }
+ }
+ ]
+ }
+ }
+}
+ANALYZE format=json select * from ((select a,b from t1) intersect all (select c,e from t2,t3)) a;
+ANALYZE
+{
+ "query_block": {
+ "select_id": 1,
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 6,
+ "r_rows": 3,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100,
+ "materialized": {
+ "query_block": {
+ "union_result": {
+ "table_name": "<intersect2,3>",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "r_rows": 3,
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 2,
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 6,
+ "r_rows": 6,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 3,
+ "operation": "INTERSECT",
+ "r_loops": 1,
+ "r_total_time_ms": "REPLACED",
+ "table": {
+ "table_name": "t3",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 5,
+ "r_rows": 5,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ },
+ "block-nl-join": {
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "r_loops": 1,
+ "rows": 7,
+ "r_rows": 7,
+ "r_total_time_ms": "REPLACED",
+ "filtered": 100,
+ "r_filtered": 100
+ },
+ "buffer_type": "flat",
+ "buffer_size": "65",
+ "join_type": "BNL",
+ "r_filtered": 100
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+}
+select * from ((select a,b from t1) intersect all (select c,e from t2,t3)) a;
+a b
+2 2
+2 2
+2 2
+prepare stmt from "(select a,b from t1) intersect all (select c,e from t2,t3);";
+execute stmt;
+a b
+2 2
+2 2
+2 2
+execute stmt;
+a b
+2 2
+2 2
+2 2
+prepare stmt from "select * from ((select a,b from t1) intersect all (select c,e from t2,t3)) a";
+execute stmt;
+a b
+2 2
+2 2
+2 2
+execute stmt;
+a b
+2 2
+2 2
+2 2
+drop tables t1,t2,t3;
+select 1 as a from dual intersect all select 1 from dual;
+a
+1
+(select 1 from dual) intersect all (select 1 from dual);
+1
+1
+(select 1 from dual into @v) 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 'into @v) intersect all (select 1 from dual)' at line 1
+select 1 from dual ORDER BY 1 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 'intersect all select 1 from dual' at line 1
+select 1 as a from dual union all select 1 from dual;
+a
+1
+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"),(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);
+a b b1
+2 fgh dffggtt
+2 fgh dffggtt
+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);
+a b
+2 2
+2 2
+select * from ((select a,b from t1) intersect all (select c,d from t2) intersect (select e,f from t3)) a;
+a b
+2 2
+prepare stmt from "(select a,b from t1) intersect all (select c,d from t2) intersect all (select e,f from t3);";
+execute stmt;
+a b
+2 2
+2 2
+execute stmt;
+a b
+2 2
+2 2
+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;
+a b
+2 2
+2 2
+execute stmt;
+a b
+2 2
+2 2
+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;
+Table Create Table
+t4 CREATE TABLE `t4` (
+ `a` int(11) DEFAULT NULL,
+ `b` blob DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+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);
+a b
+4 4
+2 2
+2 2
+(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);
+a b
+4 4
+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);
+a b
+4 4
+2 2
+2 2
+(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);
+a b
+4 4
+2 2
+drop tables t1,t2,t3;
+#
+# INTERSECT precedence
+#
+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);
+a b
+5 5
+6 6
+3 3
+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);
+a b
+5 5
+6 6
+3 3
+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);
+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
+5 UNION <derived2> ALL NULL NULL NULL NULL 2 100.00
+2 DERIVED t2 ALL NULL NULL NULL NULL 2 100.00
+3 INTERSECT t3 ALL NULL NULL NULL NULL 2 100.00
+NULL INTERSECT RESULT <intersect2,3> ALL NULL NULL NULL NULL NULL NULL
+4 UNION NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+Warnings:
+Note 1003 (/* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1`) union all /* 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 all (/* select#3 */ select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3`)) `__5` union all (/* select#4 */ select 4 AS `4`,4 AS `4`)
+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);
+e f
+3 3
+3 3
+5 5
+6 6
+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);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00
+2 INTERSECT t2 ALL NULL NULL NULL NULL 3 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 all (/* select#2 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2`) union all (/* select#3 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1`) union all (/* select#4 */ select 4 AS `4`,4 AS `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`);
+a b
+5 5
+6 6
+3 3
+4 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;
+a b
+5 5
+6 6
+3 3
+3 3
+4 4
+execute stmt;
+a b
+5 5
+6 6
+3 3
+3 3
+4 4
+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;
+b a b+1
+5 5 6
+6 6 7
+3 3 4
+3 3 4
+4 4 5
+select b,a,b+1 from v1 where a > 3;
+b a b+1
+5 5 6
+6 6 7
+4 4 5
+create procedure p1()
+select * from v1;
+call p1();
+a b
+5 5
+6 6
+3 3
+3 3
+4 4
+call p1();
+a b
+5 5
+6 6
+3 3
+3 3
+4 4
+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();
+a b
+5 5
+6 6
+3 3
+3 3
+4 4
+call p1();
+a b
+5 5
+6 6
+3 3
+3 3
+4 4
+drop procedure p1;
+show create view v1;
+View Create View character_set_client collation_connection
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS (select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1`) union all select `__6`.`c` AS `c`,`__6`.`d` AS `d` from (select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` intersect all (select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3`)) `__6` union all (select 4 AS `4`,4 AS `4`) latin1 latin1_swedish_ci
+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 );
+i
+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));
+i
+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;
+count(*)
+14848
+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;
+count(*)
+14848
+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;
+count(*)
+16430
+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;
+count(*)
+15547
+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;
+c1
+1
+3
+2
+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;
+a
+7
+7
+2
+1
+2
+explain extended
+select * from t1 where a > 4
+union all
+select * from t2 where a < 5
+intersect all
+select * from t3 where a < 5;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 7 100.00 Using where
+4 UNION <derived2> ALL NULL NULL NULL NULL 7 100.00
+2 DERIVED t2 ALL NULL NULL NULL NULL 8 100.00 Using where
+3 INTERSECT t3 ALL NULL NULL NULL NULL 7 100.00 Using where
+NULL INTERSECT RESULT <intersect2,3> ALL NULL NULL NULL NULL NULL NULL
+Warnings:
+Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` > 4 union all /* select#4 */ select `__4`.`a` AS `a` from (/* select#2 */ select `test`.`t2`.`a` AS `a` from `test`.`t2` where `test`.`t2`.`a` < 5 intersect all /* select#3 */ select `test`.`t3`.`a` AS `a` from `test`.`t3` where `test`.`t3`.`a` < 5) `__4`
+drop table t1,t2,t3;
diff --git a/mysql-test/main/intersect_all.test b/mysql-test/main/intersect_all.test
new file mode 100644
index 0000000..5d2b038
--- /dev/null
+++ b/mysql-test/main/intersect_all.test
@@ -0,0 +1,328 @@
+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;
\ No newline at end of file
diff --git a/mysql-test/main/set_operation.result b/mysql-test/main/set_operation.result
new file mode 100644
index 0000000..a021033
--- /dev/null
+++ b/mysql-test/main/set_operation.result
@@ -0,0 +1,1157 @@
+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),(3,3),(2,2),(3,3);
+insert into t2 values (2,2),(3,3),(5,5),(2,2),(2,2),(3,3);
+insert into t3 values (4,4),(2,2),(2,2),(1,1),(3,3);
+insert into t4 values (2,2),(4,4),(1,1);
+create view v0(g, h) as select a,c from t1,t2;
+# test optimization
+select * from t1
+INTERSECT ALL
+select * from t2
+INTERSECT ALL
+select * from t3;
+a b
+2 2
+2 2
+3 3
+EXPLAIN EXTENDED select * from t1
+INTERSECT ALL
+select * from t2
+INTERSECT ALL
+select * from t3;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5 100.00
+2 INTERSECT t2 ALL NULL NULL NULL NULL 6 100.00
+3 INTERSECT t3 ALL NULL NULL NULL NULL 5 100.00
+NULL INTERSECT RESULT <intersect1,2,3> 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` intersect all /* select#2 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` intersect all /* select#3 */ select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3`
+select * from t1
+INTERSECT ALL
+select * from t2
+INTERSECT ALL
+select * from t3
+INTERSECT
+select * from t1;
+a b
+2 2
+3 3
+EXPLAIN EXTENDED select * from t1
+INTERSECT ALL
+select * from t2
+INTERSECT ALL
+select * from t3
+INTERSECT
+select * from t1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5 100.00
+2 INTERSECT t2 ALL NULL NULL NULL NULL 6 100.00
+3 INTERSECT t3 ALL NULL NULL NULL NULL 5 100.00
+4 INTERSECT t1 ALL NULL NULL NULL NULL 5 100.00
+NULL INTERSECT RESULT <intersect1,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` intersect /* 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` intersect /* select#4 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1`
+select * from t1
+INTERSECT ALL
+select * from t2
+INTERSECT ALL
+select * from t3
+EXCEPT ALL
+select * from t4;
+a b
+2 2
+3 3
+EXPLAIN EXTENDED select * from t1
+INTERSECT ALL
+select * from t2
+INTERSECT ALL
+select * from t3
+EXCEPT ALL
+select * from t4;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5 100.00
+2 INTERSECT t2 ALL NULL NULL NULL NULL 6 100.00
+3 INTERSECT t3 ALL NULL NULL NULL NULL 5 100.00
+4 EXCEPT t4 ALL NULL NULL NULL NULL 3 100.00
+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` intersect all /* select#2 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` intersect all /* select#3 */ select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3` except all /* select#4 */ select `test`.`t4`.`g` AS `g`,`test`.`t4`.`h` AS `h` from `test`.`t4`
+select * from t1
+INTERSECT
+select * from t2
+EXCEPT ALL
+select * from t4;
+a b
+3 3
+EXPLAIN EXTENDED select * from t1
+INTERSECT
+select * from t2
+EXCEPT ALL
+select * from t4;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5 100.00
+2 INTERSECT t2 ALL NULL NULL NULL NULL 6 100.00
+3 EXCEPT t4 ALL NULL NULL NULL NULL 3 100.00
+NULL UNIT RESULT <unit1,2,3> 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` intersect /* select#2 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` except /* select#3 */ select `test`.`t4`.`g` AS `g`,`test`.`t4`.`h` AS `h` from `test`.`t4`
+insert into t4 values (1,1),(9,9);
+select * from t1
+UNION ALL
+select * from t2
+UNION ALL
+select * from t3
+EXCEPT
+select * from t4;
+a b
+3 3
+5 5
+EXPLAIN EXTENDED select * from t1
+UNION ALL
+select * from t2
+UNION ALL
+select * from t3
+EXCEPT
+select * from t4;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5 100.00
+2 UNION t2 ALL NULL NULL NULL NULL 6 100.00
+3 UNION t3 ALL NULL NULL NULL NULL 5 100.00
+4 EXCEPT t4 ALL NULL NULL NULL NULL 5 100.00
+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` union /* select#3 */ select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3` except /* select#4 */ select `test`.`t4`.`g` AS `g`,`test`.`t4`.`h` AS `h` from `test`.`t4`
+delete from t4;
+insert into t4 values (3,3),(3,3);
+select * from t1
+INTERSECT ALL
+select * from t2
+UNION ALL
+select * from t3
+EXCEPT ALL
+select * from t1
+UNION
+select * from t4
+EXCEPT
+select * from t3
+UNION ALL
+select * from t1;
+a b
+2 2
+2 2
+1 1
+3 3
+3 3
+EXPLAIN EXTENDED select * from t1
+INTERSECT ALL
+select * from t2
+UNION ALL
+select * from t3
+EXCEPT ALL
+select * from t1
+UNION
+select * from t4
+EXCEPT
+select * from t3
+UNION ALL
+select * from t1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5 100.00
+2 INTERSECT t2 ALL NULL NULL NULL NULL 6 100.00
+3 UNION t3 ALL NULL NULL NULL NULL 5 100.00
+4 EXCEPT t1 ALL NULL NULL NULL NULL 5 100.00
+5 UNION t4 ALL NULL NULL NULL NULL 2 100.00
+6 EXCEPT t3 ALL NULL NULL NULL NULL 5 100.00
+7 UNION t1 ALL NULL NULL NULL NULL 5 100.00
+NULL UNIT RESULT <unit1,2,3,4,5,6,7> 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` intersect all /* select#2 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` union all /* select#3 */ select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3` except all /* select#4 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` union /* select#5 */ select `test`.`t4`.`g` AS `g`,`test`.`t4`.`h` AS `h` from `test`.`t4` except /* select#6 */ select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3` union all /* select#7 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1`
+drop table t4;
+# test optimization with brackets
+(
+(select 1 except select 5 union all select 6)
+union
+(select 2 intersect all select 3 intersect all select 4)
+except
+(select 7 intersect all select 8)
+)
+union all
+(select 9 union all select 10)
+except all
+select 11;
+1
+1
+6
+9
+10
+EXPLAIN EXTENDED (
+(select 1 except select 5 union all select 6)
+union
+(select 2 intersect all select 3 intersect all select 4)
+except
+(select 7 intersect all select 8)
+)
+union all
+(select 9 union all select 10)
+except all
+select 11;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY <derived8> ALL NULL NULL NULL NULL 4 100.00
+8 DERIVED <derived2> ALL NULL NULL NULL NULL 2 100.00
+2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+3 EXCEPT NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+4 UNION NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+NULL UNIT RESULT <unit2,3,4> ALL NULL NULL NULL NULL NULL NULL
+9 UNION <derived5> ALL NULL NULL NULL NULL 2 100.00
+5 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+6 INTERSECT NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+7 INTERSECT NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+NULL INTERSECT RESULT <intersect5,6,7> ALL NULL NULL NULL NULL NULL NULL
+12 EXCEPT <derived10> ALL NULL NULL NULL NULL 2 100.00
+10 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+11 INTERSECT NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+NULL INTERSECT RESULT <intersect10,11> ALL NULL NULL NULL NULL NULL NULL
+NULL UNIT RESULT <unit8,9,12> ALL NULL NULL NULL NULL NULL NULL
+15 UNION <derived13> ALL NULL NULL NULL NULL 2 100.00
+13 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+14 UNION NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+16 EXCEPT NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+NULL UNIT RESULT <unit1,15,16> ALL NULL NULL NULL NULL NULL NULL
+Warnings:
+Note 1003 /* select#1 */ select `__14`.`1` AS `1` from (/* select#8 */ select `__7`.`1` AS `1` from (/* select#2 */ select 1 AS `1` except /* select#3 */ select 5 AS `5` union /* select#4 */ select 6 AS `6`) `__7` union /* select#9 */ select `__8`.`2` AS `2` from (/* select#5 */ select 2 AS `2` intersect /* select#6 */ select 3 AS `3` intersect /* select#7 */ select 4 AS `4`) `__8` except /* select#12 */ select `__11`.`7` AS `7` from (/* select#10 */ select 7 AS `7` intersect /* select#11 */ select 8 AS `8`) `__11`) `__14` union all /* select#15 */ select `__15`.`9` AS `9` from (/* select#13 */ select 9 AS `9` union all /* select#14 */ select 10 AS `10`) `__15` except all /* select#16 */ select 11 AS `11`
+(select 1 union all select 2)
+union
+(select 3 union all select 4);
+1
+1
+2
+3
+4
+EXPLAIN EXTENDED (select 1 union all select 2)
+union
+(select 3 union all select 4);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2 100.00
+2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+3 UNION NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+6 UNION <derived4> ALL NULL NULL NULL NULL 2 100.00
+4 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+5 UNION NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+NULL UNION RESULT <union1,6> ALL NULL NULL NULL NULL NULL NULL
+Warnings:
+Note 1003 /* select#1 */ select `__5`.`1` AS `1` from (/* select#2 */ select 1 AS `1` union /* select#3 */ select 2 AS `2`) `__5` union /* select#6 */ select `__6`.`3` AS `3` from (/* select#4 */ select 3 AS `3` union /* select#5 */ select 4 AS `4`) `__6`
+(select 1 intersect all select 2)
+except
+select 3;
+1
+EXPLAIN EXTENDED (select 1 intersect all select 2)
+except
+select 3;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2 100.00
+2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+3 INTERSECT NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+NULL INTERSECT RESULT <intersect2,3> ALL NULL NULL NULL NULL NULL NULL
+4 EXCEPT NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+NULL EXCEPT RESULT <except1,4> ALL NULL NULL NULL NULL NULL NULL
+Warnings:
+Note 1003 /* select#1 */ select `__4`.`1` AS `1` from (/* select#2 */ select 1 AS `1` intersect /* select#3 */ select 2 AS `2`) `__4` except /* select#4 */ select 3 AS `3`
+(select 1 intersect all select 2 intersect all select 3)
+intersect
+(select 4 intersect all select 5);
+1
+EXPLAIN EXTENDED (select 1 intersect all select 2 intersect all select 3)
+intersect
+(select 4 intersect all select 5);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2 100.00
+2 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+3 INTERSECT NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+4 INTERSECT NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+NULL INTERSECT RESULT <intersect2,3,4> ALL NULL NULL NULL NULL NULL NULL
+7 INTERSECT <derived5> ALL NULL NULL NULL NULL 2 100.00
+5 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+6 INTERSECT NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+NULL INTERSECT RESULT <intersect5,6> ALL NULL NULL NULL NULL NULL NULL
+NULL INTERSECT RESULT <intersect1,7> ALL NULL NULL NULL NULL NULL NULL
+Warnings:
+Note 1003 /* select#1 */ select `__6`.`1` AS `1` from (/* select#2 */ select 1 AS `1` intersect /* select#3 */ select 2 AS `2` intersect /* select#4 */ select 3 AS `3`) `__6` intersect /* select#7 */ select `__7`.`4` AS `4` from (/* select#5 */ select 4 AS `4` intersect /* select#6 */ select 5 AS `5`) `__7`
+# test set operations with table value constructor
+(values (1,1),(1,1),(1,1),(2,2),(2,2),(3,3),(9,9))
+INTERSECT ALL
+(values (1,1),(2,2),(2,2),(3,3),(3,3),(3,3),(8,8))
+EXCEPT ALL
+(values (7,7),(1,1));
+1 1
+2 2
+2 2
+3 3
+delete from t1;
+insert into t1 values(1,1),(1,1),(2,2),(4,4),(9,9);
+select * from t1
+UNION ALL
+(values (11,12),(3,3),(2,2),(3,3),(4,4),(8,8))
+INTERSECT
+(values (13,14),(7,7),(2,2),(3,3),(1,1))
+INTERSECT ALL
+(values (15,16),(2,2),(1,1))
+EXCEPT
+(values (17,18),(1,1));
+a b
+2 2
+4 4
+9 9
+# test set operations with derived table
+select * from (
+select * from t1
+UNION ALL
+select * from t2
+)dt1
+INTERSECT ALL
+select * from (
+select * from t2
+EXCEPT ALL
+select * from t3
+)dt2;
+a b
+2 2
+3 3
+5 5
+select * from (
+select * from t1
+UNION ALL
+select * from t3
+)dt1
+EXCEPT ALL
+select * from (
+select * from t2
+INTERSECT ALL
+select * from t2
+)dt2;
+a b
+1 1
+1 1
+4 4
+9 9
+1 1
+4 4
+SELECT * from(
+select * from (
+select * from t1
+UNION ALL
+select * from t2
+)dt1
+INTERSECT ALL
+select * from (
+select * from t2
+EXCEPT ALL
+select * from t3
+)dt2
+)dt3;
+a b
+2 2
+3 3
+5 5
+# integration test
+select * from t1
+UNION ALL
+select * from t2
+INTERSECT ALL
+(values (1,1), (2,2), (2,2), (5,5), (2,2))
+INTERSECT ALL
+select * from (select * from t1 union all select * from t1) sq
+EXCEPT ALL
+select * from t3
+UNION ALL
+select * from t2
+UNION
+select * from t3
+EXCEPT
+select a,c from t1,t2
+UNION ALL
+select * from v0 where g < 4
+UNION ALL
+select * from t3;
+a b
+1 1
+1 2
+3 3
+9 9
+5 5
+4 4
+1 2
+2 2
+1 3
+1 3
+2 3
+1 5
+1 5
+2 5
+1 2
+1 2
+2 2
+1 2
+1 2
+2 2
+1 3
+1 3
+2 3
+4 4
+2 2
+2 2
+1 1
+3 3
+select * from t1
+UNION ALL
+select * from t2
+INTERSECT ALL
+(values (1,1), (2,2), (2,2), (5,5), (2,2))
+INTERSECT ALL
+select * from (select * from t1 union all select * from t1) sq
+EXCEPT ALL
+select * from t3
+UNION ALL
+select * from t2
+UNION
+select * from t3
+EXCEPT
+select a,c from t1,t2
+UNION ALL
+select * from v0 where g < 4
+UNION ALL
+select * from t3
+ORDER BY a;
+a b
+1 1
+1 1
+1 2
+1 2
+1 2
+1 2
+1 2
+1 2
+1 3
+1 3
+1 3
+1 3
+1 5
+1 5
+2 2
+2 2
+2 2
+2 2
+2 2
+2 3
+2 3
+2 5
+3 3
+3 3
+4 4
+4 4
+5 5
+9 9
+select * from (
+select * from t1
+UNION ALL
+select * from t2
+INTERSECT ALL
+(values (1,1), (2,2), (2,2), (5,5), (2,2) )
+INTERSECT ALL
+select * from (select * from t1 union all select * from t1) sq
+EXCEPT ALL
+select * from t3
+UNION ALL
+select * from t2
+UNION
+select * from t3
+EXCEPT
+select a,c from t1,t2
+UNION ALL
+select * from v0 where g < 4
+UNION ALL
+select * from t3
+) dt;
+a b
+1 1
+1 2
+3 3
+9 9
+5 5
+4 4
+1 2
+2 2
+1 3
+1 3
+2 3
+1 5
+1 5
+2 5
+1 2
+1 2
+2 2
+1 2
+1 2
+2 2
+1 3
+1 3
+2 3
+4 4
+2 2
+2 2
+1 1
+3 3
+EXPLAIN
+select * from t1
+UNION ALL
+select * from t2
+INTERSECT ALL
+(values (1,1), (2,2), (2,2), (5,5), (2,2) )
+INTERSECT ALL
+select * from (select * from t1 union all select * from t1) sq
+EXCEPT ALL
+select * from t3
+UNION ALL
+select * from t2
+UNION
+select * from t3
+EXCEPT
+select a,c from t1,t2
+UNION ALL
+select * from v0 where g < 4
+UNION ALL
+select * from t3;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5
+8 UNION <derived2> ALL NULL NULL NULL NULL 5
+2 DERIVED t2 ALL NULL NULL NULL NULL 6
+3 INTERSECT NULL NULL NULL NULL NULL NULL NULL No tables used
+4 INTERSECT <derived5> ALL NULL NULL NULL NULL 10
+5 DERIVED t1 ALL NULL NULL NULL NULL 5
+6 UNION t1 ALL NULL NULL NULL NULL 5
+NULL INTERSECT RESULT <intersect2,3,4> ALL NULL NULL NULL NULL NULL
+7 EXCEPT t3 ALL NULL NULL NULL NULL 5
+9 UNION t2 ALL NULL NULL NULL NULL 6
+10 UNION t3 ALL NULL NULL NULL NULL 5
+11 EXCEPT t1 ALL NULL NULL NULL NULL 5
+11 EXCEPT t2 ALL NULL NULL NULL NULL 6 Using join buffer (flat, BNL join)
+12 UNION t1 ALL NULL NULL NULL NULL 5 Using where
+12 UNION t2 ALL NULL NULL NULL NULL 6 Using join buffer (flat, BNL join)
+13 UNION t3 ALL NULL NULL NULL NULL 5
+NULL UNIT RESULT <unit1,8,7,9,10,11,12,13> ALL NULL NULL NULL NULL NULL
+EXPLAIN format=json
+select * from t1
+UNION ALL
+select * from t2
+INTERSECT ALL
+(values (1,1), (2,2), (2,2), (5,5), (2,2) )
+INTERSECT ALL
+select * from (select * from t1 union all select * from t1) sq
+EXCEPT ALL
+select * from t3
+UNION ALL
+select * from t2
+UNION
+select * from t3
+EXCEPT
+select a,c from t1,t2
+UNION ALL
+select * from v0 where g < 4
+UNION ALL
+select * from t3;
+EXPLAIN
+{
+ "query_block": {
+ "union_result": {
+ "table_name": "<unit1,8,7,9,10,11,12,13>",
+ "access_type": "ALL",
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 8,
+ "operation": "UNION",
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "materialized": {
+ "query_block": {
+ "union_result": {
+ "table_name": "<intersect2,3,4>",
+ "access_type": "ALL",
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 2,
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 6,
+ "filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 3,
+ "operation": "INTERSECT",
+ "table": {
+ "message": "No tables used"
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 4,
+ "operation": "INTERSECT",
+ "table": {
+ "table_name": "<derived5>",
+ "access_type": "ALL",
+ "rows": 10,
+ "filtered": 100,
+ "materialized": {
+ "query_block": {
+ "union_result": {
+ "table_name": "<union5,6>",
+ "access_type": "ALL",
+ "query_specifications": [
+ {
+ "query_block": {
+ "select_id": 5,
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 6,
+ "operation": "UNION",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 7,
+ "operation": "EXCEPT",
+ "table": {
+ "table_name": "t3",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 9,
+ "operation": "UNION",
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 6,
+ "filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 10,
+ "operation": "UNION",
+ "table": {
+ "table_name": "t3",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 11,
+ "operation": "EXCEPT",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100
+ },
+ "block-nl-join": {
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 6,
+ "filtered": 100
+ },
+ "buffer_type": "flat",
+ "buffer_size": "65",
+ "join_type": "BNL"
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 12,
+ "operation": "UNION",
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100,
+ "attached_condition": "t1.a < 4"
+ },
+ "block-nl-join": {
+ "table": {
+ "table_name": "t2",
+ "access_type": "ALL",
+ "rows": 6,
+ "filtered": 100
+ },
+ "buffer_type": "flat",
+ "buffer_size": "65",
+ "join_type": "BNL"
+ }
+ }
+ },
+ {
+ "query_block": {
+ "select_id": 13,
+ "operation": "UNION",
+ "table": {
+ "table_name": "t3",
+ "access_type": "ALL",
+ "rows": 5,
+ "filtered": 100
+ }
+ }
+ }
+ ]
+ }
+ }
+}
+EXPLAIN EXTENDED
+select * from t1
+UNION ALL
+select * from t2
+INTERSECT ALL
+(values (1,1), (2,2), (2,2), (5,5), (2,2) )
+INTERSECT ALL
+select * from (select * from t1 union all select * from t1) sq
+EXCEPT ALL
+select * from t3
+UNION ALL
+select * from t2
+UNION
+select * from t3
+EXCEPT
+select a,c from t1,t2
+UNION ALL
+select * from v0 where g < 4
+UNION ALL
+select * from t3;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 5 100.00
+8 UNION <derived2> ALL NULL NULL NULL NULL 5 100.00
+2 DERIVED t2 ALL NULL NULL NULL NULL 6 100.00
+3 INTERSECT NULL NULL NULL NULL NULL NULL NULL NULL No tables used
+4 INTERSECT <derived5> ALL NULL NULL NULL NULL 10 100.00
+5 DERIVED t1 ALL NULL NULL NULL NULL 5 100.00
+6 UNION t1 ALL NULL NULL NULL NULL 5 100.00
+NULL INTERSECT RESULT <intersect2,3,4> ALL NULL NULL NULL NULL NULL NULL
+7 EXCEPT t3 ALL NULL NULL NULL NULL 5 100.00
+9 UNION t2 ALL NULL NULL NULL NULL 6 100.00
+10 UNION t3 ALL NULL NULL NULL NULL 5 100.00
+11 EXCEPT t1 ALL NULL NULL NULL NULL 5 100.00
+11 EXCEPT t2 ALL NULL NULL NULL NULL 6 100.00 Using join buffer (flat, BNL join)
+12 UNION t1 ALL NULL NULL NULL NULL 5 100.00 Using where
+12 UNION t2 ALL NULL NULL NULL NULL 6 100.00 Using join buffer (flat, BNL join)
+13 UNION t3 ALL NULL NULL NULL NULL 5 100.00
+NULL UNIT RESULT <unit1,8,7,9,10,11,12,13> 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 all /* select#8 */ select `__8`.`c` AS `c`,`__8`.`d` AS `d` from (/* select#2 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` intersect all (values (1,1),(2,2),(2,2),(5,5),(2,2)) intersect all /* select#4 */ select `sq`.`a` AS `a`,`sq`.`b` AS `b` from (/* select#5 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` union all /* select#6 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1`) `sq`) `__8` except all /* select#7 */ select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3` union /* select#9 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` union /* select#10 */ select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3` except /* select#11 */ select `test`.`t1`.`a` AS `a`,`test`.`t2`.`c` AS `c` from `test`.`t1` join `test`.`t2` union all /* select#12 */ se
lect `te
st`.`t1`.`a` AS `g`,`test`.`t2`.`c` AS `h` from `test`.`t1` join `test`.`t2` where `test`.`t1`.`a` < 4 union all /* select#13 */ select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3`
+PREPARE stmt from"
+ select * from t1
+ UNION ALL
+ select * from t2
+ INTERSECT ALL
+ (values (1,1), (2,2), (2,2), (5,5), (2,2) )
+ INTERSECT ALL
+ select * from (select * from t1 union all select * from t1) sq
+ EXCEPT ALL
+ select * from t3
+ UNION ALL
+ select * from t2
+ UNION
+ select * from t3
+ EXCEPT
+ select a,c from t1,t2
+ UNION ALL
+ select * from v0 where g < 4
+ UNION ALL
+ select * from t3
+";
+EXECUTE stmt;
+a b
+1 1
+1 2
+3 3
+9 9
+5 5
+4 4
+1 2
+2 2
+1 3
+1 3
+2 3
+1 5
+1 5
+2 5
+1 2
+1 2
+2 2
+1 2
+1 2
+2 2
+1 3
+1 3
+2 3
+4 4
+2 2
+2 2
+1 1
+3 3
+EXECUTE stmt;
+a b
+1 1
+1 2
+3 3
+9 9
+5 5
+4 4
+1 2
+2 2
+1 3
+1 3
+2 3
+1 5
+1 5
+2 5
+1 2
+1 2
+2 2
+1 2
+1 2
+2 2
+1 3
+1 3
+2 3
+4 4
+2 2
+2 2
+1 1
+3 3
+deallocate prepare stmt;
+create view v1(i1, i2) as
+select * from t1
+UNION ALL
+select * from t2
+INTERSECT ALL
+(values (1,1), (2,2), (2,2), (5,5), (2,2) )
+INTERSECT ALL
+select * from (select * from t1 union all select * from t1) sq
+EXCEPT ALL
+select * from t3
+UNION ALL
+select * from t2
+UNION
+select * from t3
+EXCEPT
+select a,c from t1,t2
+UNION ALL
+select * from v0 where g < 4
+UNION ALL
+select * from t3;
+show create view v1;
+View Create View character_set_client collation_connection
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `test`.`t1`.`a` AS `i1`,`test`.`t1`.`b` AS `i2` from `test`.`t1` union all select `__9`.`c` AS `c`,`__9`.`d` AS `d` from (select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` intersect all (values (1,1),(2,2),(2,2),(5,5),(2,2)) intersect all select `sq`.`a` AS `a`,`sq`.`b` AS `b` from (select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` union all select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1`) `sq`) `__9` except all select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3` union all select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` union select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3` except select `test`.`t1`.`a` AS `a`,`test`.`t2`.`c` AS `c` from (`test`.`t1` join `test`.`t2`) union all select `v0`.`g` AS `g`,`v0`.`h` AS `h` from `test`.`v0` where `v0`.`g` < 4 union
all sele
ct `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3` latin1 latin1_swedish_ci
+select * from v1 limit 14;
+i1 i2
+1 1
+1 2
+3 3
+9 9
+5 5
+4 4
+1 2
+2 2
+1 3
+1 3
+2 3
+1 5
+1 5
+2 5
+select * from v1 order by i1 limit 14;
+i1 i2
+1 1
+1 1
+1 2
+1 2
+1 2
+1 2
+1 2
+1 2
+1 3
+1 3
+1 3
+1 3
+1 5
+1 5
+drop table t1,t2,t3;
+drop view v0,v1;
+# compare result
+create table t1 (a int, b int);
+create table t2 (c int, d int);
+create table t3 (e int, f int);
+create table t4 (g int, h int);
+insert into t1 values (1,1),(1,1),(2,2);
+insert into t2 values (1,1),(1,1),(2,2),(3,3);
+insert into t3 values (1,1);
+insert into t4 values (4,4);
+select * from t1 intersect all select * from t2 except select * from t3 union select * from t4;
+a b
+4 4
+2 2
+select * from t1 intersect all select * from t2 except ALL select * from t3 union select * from t4;
+a b
+1 1
+2 2
+4 4
+select * from t1 intersect DISTINCT select * from t2 except select * from t3 union select * from t4;
+a b
+4 4
+2 2
+select * from t1 intersect DISTINCT select * from t2 except ALL select * from t3 union select * from t4;
+a b
+4 4
+2 2
+delete from t1;
+delete from t2;
+delete from t3;
+delete from t4;
+insert into t1 values (1,1),(1,1),(1,1),(2,2),(2,2),(4,4),(5,5);
+insert into t2 values (1,1),(1,1),(1,1),(2,2),(2,2),(3,3);
+insert into t3 values (1,1),(2,2),(2,2);
+select * from t1 intersect all select * from t2 intersect all select * from t3;
+a b
+1 1
+2 2
+2 2
+select * from t1 intersect all select * from t2 intersect select * from t3;
+a b
+1 1
+2 2
+select * from t1 intersect all select * from t1 intersect all select * from t2 intersect select * from t3;
+a b
+1 1
+2 2
+delete from t1;
+delete from t2;
+delete from t3;
+insert into t1 values (1,1),(1,1),(2,2);
+insert into t2 values (1,1),(1,1),(2,2),(3,3);
+insert into t3 values (1,1),(5,5);
+insert into t4 values (4,4),(4,4),(4,4);
+select * from t1 intersect all select * from t2 union all select * from t3 union select * from t4;
+a b
+1 1
+2 2
+5 5
+4 4
+select * from t1 intersect DISTINCT select * from t2 union DISTINCT select * from t3 union select * from t4;
+a b
+1 1
+2 2
+5 5
+4 4
+select * from t1 intersect all select * from t2 intersect all select * from t3 union select * from t4;
+a b
+1 1
+4 4
+select * from t1 intersect all select * from t2 intersect DISTINCT select * from t3 union select * from t4;
+a b
+1 1
+4 4
+select * from t1 intersect DISTINCT select * from t2 intersect DISTINCT select * from t3 union select * from t4;
+a b
+1 1
+4 4
+select * from t1 intersect all select * from t2 EXCEPT select * from t3 union select * from t4;
+a b
+4 4
+2 2
+select * from t1 intersect DISTINCT select * from t2 EXCEPT select * from t3 union select * from t4;
+a b
+4 4
+2 2
+select * from t1 intersect all select * from t2 EXCEPT ALL select * from t3 union select * from t4;
+a b
+1 1
+2 2
+4 4
+select * from t1 EXCEPT select * from t2 union all select * from t3 union select * from t4;
+a b
+5 5
+1 1
+4 4
+select * from t1 EXCEPT select * from t2 union DISTINCT select * from t3 union select * from t4;
+a b
+5 5
+1 1
+4 4
+delete from t1;
+delete from t2;
+delete from t3;
+delete from t4;
+insert into t1 values (1,1),(2,2);
+insert into t2 values (1,1),(2,2);
+insert into t3 values (1,1),(3,3);
+select * from t1 union all select * from t2 except all select * from t3;
+a b
+1 1
+2 2
+2 2
+select * from t1 union all select * from t2 except DISTINCT select * from t3;
+a b
+2 2
+select * from t1 union DISTINCT select * from t2 except all select * from t3;
+a b
+2 2
+select * from t1 union DISTINCT select * from t2 except DISTINCT select * from t3;
+a b
+2 2
+drop table t1;
+drop table t2;
+drop table t3;
+drop table t4;
+select 1 intersect all select 2 intersect all select 3 intersect select 4 union select 5;
+1
+5
+select 1 intersect all select 2 intersect all select 3 union select 4 except select 5;
+1
+4
+select 1 union select 2 except all select 3 union select 4;
+1
+1
+2
+4
+select 1 union all select 2 union all select 3 union select 4;
+1
+1
+2
+3
+4
+# test with limited resource
+set @@max_heap_table_size= 1024;
+Warnings:
+Warning 1292 Truncated incorrect max_heap_table_size value: '1024'
+set @@tmp_table_size= 1024;
+create table t1 (a int, b int);
+insert into t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(0,0);
+insert into t1 select * from t1;
+insert into t1 select * from t1;
+insert into t1 select * from t1;
+insert into t1 select a+100, b+100 from t1;
+create table t2 (a int, b int);
+insert into t2 values (10,10),(11,11),(12,12),(13,13),(14,14),(5,5),(6,6),(7,7),(8,8),(9,9);
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select a+100, b+100 from t2;
+select count(*) from
+(
+select * from t1
+INTERSECT ALL
+select * from t2
+) c;
+count(*)
+80
+select count(*) from
+(
+select * from t1
+EXCEPT ALL
+select * from t2
+) c;
+count(*)
+80
+select count(*) from
+(
+select * from t1
+INTERSECT ALL
+select * from t2
+UNION ALL
+select * from t1
+EXCEPT ALL
+select * from t2
+) c;
+count(*)
+160
+delete from t1;
+delete from t2;
+insert into t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(0,0);
+insert into t1 select a+10, b+10 from t1;
+insert into t1 select a+20, b+20 from t1;
+insert into t1 select a+40, b+40 from t1;
+insert into t1 select a+80, b+80 from t1;
+insert into t2 values (1110,1110),(1111,1111),(1112,1112),(1113,1113),(1114,1114),(1105,1105),(1106,1106),(1107,1107),(1108,1108),(1109,1109);
+insert into t2 select a+10, b+10 from t2;
+insert into t2 select a+20, b+20 from t2;
+insert into t2 select a+40, b+40 from t2;
+insert into t2 select a+80, b+80 from t2;
+select count(*) from
+(
+select * from t1
+UNION ALL
+select * from t2
+EXCEPT ALL
+values (1,1)
+) c;
+count(*)
+319
+drop table t1;
+drop table t2;
diff --git a/mysql-test/main/set_operation.test b/mysql-test/main/set_operation.test
new file mode 100644
index 0000000..c43725c
--- /dev/null
+++ b/mysql-test/main/set_operation.test
@@ -0,0 +1,526 @@
+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),(3,3),(2,2),(3,3);
+insert into t2 values (2,2),(3,3),(5,5),(2,2),(2,2),(3,3);
+insert into t3 values (4,4),(2,2),(2,2),(1,1),(3,3);
+insert into t4 values (2,2),(4,4),(1,1);
+create view v0(g, h) as select a,c from t1,t2;
+
+--echo # test optimization
+
+let $q=
+ select * from t1
+ INTERSECT ALL
+ select * from t2
+ INTERSECT ALL
+ select * from t3;
+eval $q;
+eval EXPLAIN EXTENDED $q;
+
+let $q=
+ select * from t1
+ INTERSECT ALL
+ select * from t2
+ INTERSECT ALL
+ select * from t3
+ INTERSECT
+ select * from t1;
+eval $q;
+eval EXPLAIN EXTENDED $q;
+
+let $q=
+ select * from t1
+ INTERSECT ALL
+ select * from t2
+ INTERSECT ALL
+ select * from t3
+ EXCEPT ALL
+ select * from t4;
+eval $q;
+eval EXPLAIN EXTENDED $q;
+
+let $q=
+ select * from t1
+ INTERSECT
+ select * from t2
+ EXCEPT ALL
+ select * from t4;
+eval $q;
+eval EXPLAIN EXTENDED $q;
+
+insert into t4 values (1,1),(9,9);
+let $q=
+ select * from t1
+ UNION ALL
+ select * from t2
+ UNION ALL
+ select * from t3
+ EXCEPT
+ select * from t4;
+eval $q;
+eval EXPLAIN EXTENDED $q;
+
+delete from t4;
+insert into t4 values (3,3),(3,3);
+let $q=
+ select * from t1
+ INTERSECT ALL
+ select * from t2
+ UNION ALL
+ select * from t3
+ EXCEPT ALL
+ select * from t1
+ UNION
+ select * from t4
+ EXCEPT
+ select * from t3
+ UNION ALL
+ select * from t1;
+
+eval $q;
+eval EXPLAIN EXTENDED $q;
+drop table t4;
+
+--echo # test optimization with brackets
+
+let $q=
+(
+ (select 1 except select 5 union all select 6)
+ union
+ (select 2 intersect all select 3 intersect all select 4)
+ except
+ (select 7 intersect all select 8)
+)
+ union all
+(select 9 union all select 10)
+ except all
+select 11;
+eval $q;
+eval EXPLAIN EXTENDED $q;
+
+let $q=
+(select 1 union all select 2)
+ union
+(select 3 union all select 4);
+eval $q;
+eval EXPLAIN EXTENDED $q;
+
+let $q=
+(select 1 intersect all select 2)
+ except
+select 3;
+eval $q;
+eval EXPLAIN EXTENDED $q;
+
+let $q=
+(select 1 intersect all select 2 intersect all select 3)
+ intersect
+(select 4 intersect all select 5);
+eval $q;
+eval EXPLAIN EXTENDED $q;
+
+
+--echo # test set operations with table value constructor
+
+(values (1,1),(1,1),(1,1),(2,2),(2,2),(3,3),(9,9))
+INTERSECT ALL
+(values (1,1),(2,2),(2,2),(3,3),(3,3),(3,3),(8,8))
+EXCEPT ALL
+(values (7,7),(1,1));
+
+delete from t1;
+insert into t1 values(1,1),(1,1),(2,2),(4,4),(9,9);
+
+select * from t1
+UNION ALL
+(values (11,12),(3,3),(2,2),(3,3),(4,4),(8,8))
+INTERSECT
+(values (13,14),(7,7),(2,2),(3,3),(1,1))
+INTERSECT ALL
+(values (15,16),(2,2),(1,1))
+EXCEPT
+(values (17,18),(1,1));
+
+--echo # test set operations with derived table
+
+select * from (
+ select * from t1
+ UNION ALL
+ select * from t2
+)dt1
+INTERSECT ALL
+select * from (
+ select * from t2
+ EXCEPT ALL
+ select * from t3
+)dt2;
+
+select * from (
+ select * from t1
+ UNION ALL
+ select * from t3
+)dt1
+EXCEPT ALL
+select * from (
+ select * from t2
+ INTERSECT ALL
+ select * from t2
+)dt2;
+
+SELECT * from(
+ select * from (
+ select * from t1
+ UNION ALL
+ select * from t2
+ )dt1
+ INTERSECT ALL
+ select * from (
+ select * from t2
+ EXCEPT ALL
+ select * from t3
+ )dt2
+)dt3;
+
+--echo # integration test
+
+
+select * from t1
+UNION ALL
+select * from t2
+INTERSECT ALL
+(values (1,1), (2,2), (2,2), (5,5), (2,2))
+INTERSECT ALL
+select * from (select * from t1 union all select * from t1) sq
+EXCEPT ALL
+select * from t3
+UNION ALL
+select * from t2
+UNION
+select * from t3
+EXCEPT
+select a,c from t1,t2
+UNION ALL
+select * from v0 where g < 4
+UNION ALL
+select * from t3;
+
+--sorted_result
+select * from t1
+UNION ALL
+select * from t2
+INTERSECT ALL
+(values (1,1), (2,2), (2,2), (5,5), (2,2))
+INTERSECT ALL
+select * from (select * from t1 union all select * from t1) sq
+EXCEPT ALL
+select * from t3
+UNION ALL
+select * from t2
+UNION
+select * from t3
+EXCEPT
+select a,c from t1,t2
+UNION ALL
+select * from v0 where g < 4
+UNION ALL
+select * from t3
+ORDER BY a;
+
+
+select * from (
+ select * from t1
+ UNION ALL
+ select * from t2
+ INTERSECT ALL
+ (values (1,1), (2,2), (2,2), (5,5), (2,2) )
+ INTERSECT ALL
+ select * from (select * from t1 union all select * from t1) sq
+ EXCEPT ALL
+ select * from t3
+ UNION ALL
+ select * from t2
+ UNION
+ select * from t3
+ EXCEPT
+ select a,c from t1,t2
+ UNION ALL
+ select * from v0 where g < 4
+ UNION ALL
+ select * from t3
+) dt;
+
+EXPLAIN
+select * from t1
+UNION ALL
+select * from t2
+INTERSECT ALL
+(values (1,1), (2,2), (2,2), (5,5), (2,2) )
+INTERSECT ALL
+select * from (select * from t1 union all select * from t1) sq
+EXCEPT ALL
+select * from t3
+UNION ALL
+select * from t2
+UNION
+select * from t3
+EXCEPT
+select a,c from t1,t2
+UNION ALL
+select * from v0 where g < 4
+UNION ALL
+select * from t3;
+
+EXPLAIN format=json
+select * from t1
+UNION ALL
+select * from t2
+INTERSECT ALL
+(values (1,1), (2,2), (2,2), (5,5), (2,2) )
+INTERSECT ALL
+select * from (select * from t1 union all select * from t1) sq
+EXCEPT ALL
+select * from t3
+UNION ALL
+select * from t2
+UNION
+select * from t3
+EXCEPT
+select a,c from t1,t2
+UNION ALL
+select * from v0 where g < 4
+UNION ALL
+select * from t3;
+
+EXPLAIN EXTENDED
+select * from t1
+UNION ALL
+select * from t2
+INTERSECT ALL
+(values (1,1), (2,2), (2,2), (5,5), (2,2) )
+INTERSECT ALL
+select * from (select * from t1 union all select * from t1) sq
+EXCEPT ALL
+select * from t3
+UNION ALL
+select * from t2
+UNION
+select * from t3
+EXCEPT
+select a,c from t1,t2
+UNION ALL
+select * from v0 where g < 4
+UNION ALL
+select * from t3;
+
+PREPARE stmt from"
+ select * from t1
+ UNION ALL
+ select * from t2
+ INTERSECT ALL
+ (values (1,1), (2,2), (2,2), (5,5), (2,2) )
+ INTERSECT ALL
+ select * from (select * from t1 union all select * from t1) sq
+ EXCEPT ALL
+ select * from t3
+ UNION ALL
+ select * from t2
+ UNION
+ select * from t3
+ EXCEPT
+ select a,c from t1,t2
+ UNION ALL
+ select * from v0 where g < 4
+ UNION ALL
+ select * from t3
+";
+
+
+EXECUTE stmt;
+
+EXECUTE stmt;
+deallocate prepare stmt;
+
+create view v1(i1, i2) as
+ select * from t1
+ UNION ALL
+ select * from t2
+ INTERSECT ALL
+ (values (1,1), (2,2), (2,2), (5,5), (2,2) )
+ INTERSECT ALL
+ select * from (select * from t1 union all select * from t1) sq
+ EXCEPT ALL
+ select * from t3
+ UNION ALL
+ select * from t2
+ UNION
+ select * from t3
+ EXCEPT
+ select a,c from t1,t2
+ UNION ALL
+ select * from v0 where g < 4
+ UNION ALL
+ select * from t3;
+
+show create view v1;
+
+select * from v1 limit 14;
+--sorted_result
+select * from v1 order by i1 limit 14;
+
+drop table t1,t2,t3;
+drop view v0,v1;
+
+--echo # compare result
+
+create table t1 (a int, b int);
+create table t2 (c int, d int);
+create table t3 (e int, f int);
+create table t4 (g int, h int);
+
+
+insert into t1 values (1,1),(1,1),(2,2);
+insert into t2 values (1,1),(1,1),(2,2),(3,3);
+insert into t3 values (1,1);
+insert into t4 values (4,4);
+
+select * from t1 intersect all select * from t2 except select * from t3 union select * from t4;
+select * from t1 intersect all select * from t2 except ALL select * from t3 union select * from t4;
+
+select * from t1 intersect DISTINCT select * from t2 except select * from t3 union select * from t4;
+select * from t1 intersect DISTINCT select * from t2 except ALL select * from t3 union select * from t4;
+
+delete from t1;
+delete from t2;
+delete from t3;
+delete from t4;
+
+
+insert into t1 values (1,1),(1,1),(1,1),(2,2),(2,2),(4,4),(5,5);
+insert into t2 values (1,1),(1,1),(1,1),(2,2),(2,2),(3,3);
+insert into t3 values (1,1),(2,2),(2,2);
+
+select * from t1 intersect all select * from t2 intersect all select * from t3;
+select * from t1 intersect all select * from t2 intersect select * from t3;
+select * from t1 intersect all select * from t1 intersect all select * from t2 intersect select * from t3;
+
+delete from t1;
+delete from t2;
+delete from t3;
+
+
+insert into t1 values (1,1),(1,1),(2,2);
+insert into t2 values (1,1),(1,1),(2,2),(3,3);
+insert into t3 values (1,1),(5,5);
+insert into t4 values (4,4),(4,4),(4,4);
+
+select * from t1 intersect all select * from t2 union all select * from t3 union select * from t4;
+select * from t1 intersect DISTINCT select * from t2 union DISTINCT select * from t3 union select * from t4;
+
+select * from t1 intersect all select * from t2 intersect all select * from t3 union select * from t4;
+select * from t1 intersect all select * from t2 intersect DISTINCT select * from t3 union select * from t4;
+select * from t1 intersect DISTINCT select * from t2 intersect DISTINCT select * from t3 union select * from t4;
+
+select * from t1 intersect all select * from t2 EXCEPT select * from t3 union select * from t4;
+select * from t1 intersect DISTINCT select * from t2 EXCEPT select * from t3 union select * from t4;
+select * from t1 intersect all select * from t2 EXCEPT ALL select * from t3 union select * from t4;
+
+select * from t1 EXCEPT select * from t2 union all select * from t3 union select * from t4;
+select * from t1 EXCEPT select * from t2 union DISTINCT select * from t3 union select * from t4;
+
+delete from t1;
+delete from t2;
+delete from t3;
+delete from t4;
+
+
+insert into t1 values (1,1),(2,2);
+insert into t2 values (1,1),(2,2);
+insert into t3 values (1,1),(3,3);
+
+select * from t1 union all select * from t2 except all select * from t3;
+select * from t1 union all select * from t2 except DISTINCT select * from t3;
+select * from t1 union DISTINCT select * from t2 except all select * from t3;
+select * from t1 union DISTINCT select * from t2 except DISTINCT select * from t3;
+
+drop table t1;
+drop table t2;
+drop table t3;
+drop table t4;
+
+
+select 1 intersect all select 2 intersect all select 3 intersect select 4 union select 5;
+select 1 intersect all select 2 intersect all select 3 union select 4 except select 5;
+select 1 union select 2 except all select 3 union select 4;
+select 1 union all select 2 union all select 3 union select 4;
+
+--echo # test with limited resource
+
+set @@max_heap_table_size= 1024;
+set @@tmp_table_size= 1024;
+
+create table t1 (a int, b int);
+insert into t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(0,0);
+insert into t1 select * from t1;
+insert into t1 select * from t1;
+insert into t1 select * from t1;
+insert into t1 select a+100, b+100 from t1;
+create table t2 (a int, b int);
+insert into t2 values (10,10),(11,11),(12,12),(13,13),(14,14),(5,5),(6,6),(7,7),(8,8),(9,9);
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select * from t2;
+insert into t2 select a+100, b+100 from t2;
+
+
+select count(*) from
+(
+ select * from t1
+ INTERSECT ALL
+ select * from t2
+) c;
+
+select count(*) from
+(
+ select * from t1
+ EXCEPT ALL
+ select * from t2
+) c;
+
+select count(*) from
+(
+ select * from t1
+ INTERSECT ALL
+ select * from t2
+ UNION ALL
+ select * from t1
+ EXCEPT ALL
+ select * from t2
+) c;
+
+delete from t1;
+delete from t2;
+
+insert into t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(0,0);
+insert into t1 select a+10, b+10 from t1;
+insert into t1 select a+20, b+20 from t1;
+insert into t1 select a+40, b+40 from t1;
+insert into t1 select a+80, b+80 from t1;
+insert into t2 values (1110,1110),(1111,1111),(1112,1112),(1113,1113),(1114,1114),(1105,1105),(1106,1106),(1107,1107),(1108,1108),(1109,1109);
+insert into t2 select a+10, b+10 from t2;
+insert into t2 select a+20, b+20 from t2;
+insert into t2 select a+40, b+40 from t2;
+insert into t2 select a+80, b+80 from t2;
+
+select count(*) from
+(
+ select * from t1
+ UNION ALL
+ select * from t2
+ EXCEPT ALL
+ values (1,1)
+) c;
+
+drop table t1;
+drop table t2;
diff --git a/mysql-test/main/set_operation_oracle.result b/mysql-test/main/set_operation_oracle.result
new file mode 100644
index 0000000..28f6e31
--- /dev/null
+++ b/mysql-test/main/set_operation_oracle.result
@@ -0,0 +1,75 @@
+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;
diff --git a/mysql-test/main/set_operation_oracle.test b/mysql-test/main/set_operation_oracle.test
new file mode 100644
index 0000000..bd2a4d5
--- /dev/null
+++ b/mysql-test/main/set_operation_oracle.test
@@ -0,0 +1,65 @@
+# 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
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 152bf06..54d6541 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -5708,17 +5708,18 @@ class TMP_TABLE_PARAM :public Sql_alloc
class select_unit :public select_result_interceptor
{
+protected:
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(ha_rows 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
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 8f6e86f..e77f173 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -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 (...) */
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index b916d07..cd6c068 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -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;
@@ -868,11 +878,6 @@ class st_select_lex_unit: public st_select_lex_node {
*/
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:
VALUES (v1) ... (vn) => SELECT * FROM (VALUES (v1) ... (vn)) as tvc
@@ -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;
diff --git a/sql/sql_tvc.cc b/sql/sql_tvc.cc
index 9eefd03..47f50ae 100644
--- a/sql/sql_tvc.cc
+++ b/sql/sql_tvc.cc
@@ -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;
}
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 41f4234..1abc81b 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -72,7 +72,7 @@ void select_unit::change_select()
switch (step)
{
case INTERSECT_TYPE:
- intersect_mark->value= prev_step= curr_step;
+ prev_step= curr_step;
curr_step= current_select_number;
break;
case EXCEPT_TYPE:
@@ -83,6 +83,7 @@ void select_unit::change_select()
}
DBUG_VOID_RETURN;
}
+
/**
Fill temporary tables for UNION/EXCEPT/INTERSECT
@@ -93,7 +94,7 @@ void select_unit::change_select()
EXCEPT:
looks for the record in the table (with 'counter' field first if
INTERSECT present in the sequence) and delete it if found
-INTESECT:
+INTERSECT:
looks for the same record with 'counter' field of previous operation,
put as a 'counter' number of the current SELECT.
We scan the table and remove all records which marked with not last
@@ -108,7 +109,7 @@ void select_unit::change_select()
*/
int select_unit::send_data(List<Item> &values)
{
- int rc;
+ int rc= 0;
int not_reported_error= 0;
if (unit->offset_limit_cnt)
{ // using limit offset,count
@@ -119,17 +120,24 @@ int select_unit::send_data(List<Item> &values)
return 0;
if (table->no_rows_with_nulls)
table->null_catch_flags= CHECK_ROW_FOR_NULLS_TO_REJECT;
- if (intersect_mark)
+
+ fill_record(thd, table, table->field + addon_cnt, values, true, false);
+ /* set up initial values for records to be written */
+ if (addon_cnt && step == UNION_TYPE)
{
- fill_record(thd, table, table->field + 1, values, TRUE, FALSE);
- table->field[0]->store((ulonglong) curr_step, 1);
+ DBUG_ASSERT(addon_cnt == 1);
+ table->field[0]->store((longlong) curr_step, 1);
}
- else
- fill_record(thd, table, table->field, values, TRUE, FALSE);
+
if (unlikely(thd->is_error()))
{
rc= 1;
- goto end;
+ if (unlikely(not_reported_error))
+ {
+ DBUG_ASSERT(rc);
+ table->file->print_error(not_reported_error, MYF(0));
+ }
+ return rc;
}
if (table->no_rows_with_nulls)
{
@@ -137,105 +145,58 @@ int select_unit::send_data(List<Item> &values)
if (table->null_catch_flags)
{
rc= 0;
- goto end;
+ if (unlikely(not_reported_error))
+ {
+ DBUG_ASSERT(rc);
+ table->file->print_error(not_reported_error, MYF(0));
+ }
+ return rc;
}
}
- // select_unit::change_select() change step & Co correctly for each SELECT
+ /* select_unit::change_select() change step & Co correctly for each SELECT */
+ int find_res;
switch (step)
{
- case UNION_TYPE:
- {
- if (unlikely((write_err=
- table->file->ha_write_tmp_row(table->record[0]))))
- {
- if (write_err == HA_ERR_FOUND_DUPP_KEY)
- {
- /*
- Inform upper level that we found a duplicate key, that should not
- be counted as part of limit
- */
- rc= -1;
- goto end;
- }
- bool is_duplicate= FALSE;
- /* create_internal_tmp_table_from_heap will generate error if needed */
- if (table->file->is_fatal_error(write_err, HA_CHECK_DUP) &&
- create_internal_tmp_table_from_heap(thd, table,
- tmp_table_param.start_recinfo,
- &tmp_table_param.recinfo,
- write_err, 1, &is_duplicate))
- {
- rc= 1;
- goto end;
- }
+ case UNION_TYPE:
+ rc= write_record();
+ /* no reaction with conversion */
+ if (rc == -2)
+ rc= 0;
+ break;
- if (is_duplicate)
- {
- rc= -1;
- goto end;
- }
- }
- break;
- }
- case EXCEPT_TYPE:
- {
- int find_res;
- /*
- The temporary table uses very first index or constrain for
- checking unique constrain.
- */
- if (!(find_res= table->file->find_unique_row(table->record[0], 0)))
- {
- DBUG_ASSERT(!table->triggers);
- table->status|= STATUS_DELETED;
- not_reported_error= table->file->ha_delete_tmp_row(table->record[0]);
- rc= MY_TEST(not_reported_error);
- goto end;
- }
- else
- {
- if ((rc= not_reported_error= (find_res != 1)))
- goto end;
- }
- break;
- }
- case INTERSECT_TYPE:
+ case EXCEPT_TYPE:
+ /*
+ The temporary table uses very first index or constrain for
+ checking unique constrain.
+ */
+ if (!(find_res= table->file->find_unique_row(table->record[0], 0)))
+ rc= delete_record();
+ else
+ rc= not_reported_error= (find_res != 1);
+ break;
+ case INTERSECT_TYPE:
+ /*
+ The temporary table uses very first index or constrain for
+ checking unique constrain.
+ */
+ if (!(find_res= table->file->find_unique_row(table->record[0], 0)))
{
- int find_res;
- /*
- The temporary table uses very first index or constrain for
- checking unique constrain.
- */
- if (!(find_res= table->file->find_unique_row(table->record[0], 0)))
+ DBUG_ASSERT(!table->triggers);
+ if (table->field[0]->val_int() == prev_step)
{
- DBUG_ASSERT(!table->triggers);
- if (table->field[0]->val_int() != prev_step)
- {
- rc= 0;
- goto end;
- }
- store_record(table, record[1]);
- table->field[0]->store(curr_step, 0);
- not_reported_error= table->file->ha_update_tmp_row(table->record[1],
- table->record[0]);
+ not_reported_error= update_counter(table->field[0], curr_step);
rc= MY_TEST(not_reported_error);
DBUG_ASSERT(rc != HA_ERR_RECORD_IS_THE_SAME);
- goto end;
}
- else
- {
- if ((rc= not_reported_error= (find_res != 1)))
- goto end;
- }
- break;
}
- default:
- DBUG_ASSERT(0);
+ else
+ rc= not_reported_error= (find_res != 1);
+ break;
+ default:
+ DBUG_ASSERT(0);
}
- rc= 0;
-end:
if (unlikely(not_reported_error))
{
DBUG_ASSERT(rc);
@@ -251,7 +212,7 @@ bool select_unit::send_eof()
thd->lex->current_select->next_select()->get_linkage() == INTERSECT_TYPE))
{
/*
- it is not INTESECT or next SELECT in the sequence is INTERSECT so no
+ it is not INTERSECT or next SELECT in the sequence is INTERSECT so no
need filtering (the last INTERSECT in this sequence of intersects will
filter).
*/
@@ -265,15 +226,14 @@ bool select_unit::send_eof()
TODO: as optimization for simple case this could be moved to
'fake_select' WHERE condition
*/
- handler *file= table->file;
int error;
- if (unlikely(file->ha_rnd_init_with_error(1)))
+ if (table->file->ha_rnd_init_with_error(1))
return 1;
-
do
{
- if (unlikely(error= file->ha_rnd_next(table->record[0])))
+ error= table->file->ha_rnd_next(table->record[0]);
+ if (unlikely(error))
{
if (error == HA_ERR_END_OF_FILE)
{
@@ -283,9 +243,9 @@ bool select_unit::send_eof()
break;
}
if (table->field[0]->val_int() != curr_step)
- error= file->ha_delete_tmp_row(table->record[0]);
- } while (likely(!error));
- file->ha_rnd_end();
+ error= delete_record();
+ } while (!error);
+ table->file->ha_rnd_end();
if (unlikely(error))
table->file->print_error(error, MYF(0));
@@ -345,6 +305,7 @@ bool select_unit::flush()
create_table whether to physically create result table
keep_row_order keep rows in order as they were inserted
hidden number of hidden fields (for INTERSECT)
+ plus one for `ALL`
DESCRIPTION
Create a temporary table that is used to store the result of a UNION,
@@ -433,6 +394,143 @@ select_union_recursive::create_result_table(THD *thd_arg,
}
+/*
+ @brief
+ Write a record
+
+ @retval
+ -2 conversion happened
+ -1 found a duplicate key
+ 0 no error
+ 1 if an error is reported
+*/
+
+int select_unit::write_record()
+{
+ if (unlikely((write_err= table->file->ha_write_tmp_row(table->record[0]))))
+ {
+ if (write_err == HA_ERR_FOUND_DUPP_KEY)
+ {
+ /*
+ Inform upper level that we found a duplicate key, that should not
+ be counted as part of limit
+ */
+ return -1;
+ }
+ bool is_duplicate= false;
+ /* create_internal_tmp_table_from_heap will generate error if needed */
+ if (table->file->is_fatal_error(write_err, HA_CHECK_DUP))
+ {
+ if (!create_internal_tmp_table_from_heap(thd, table,
+ tmp_table_param.start_recinfo,
+ &tmp_table_param.recinfo,
+ write_err, 1, &is_duplicate))
+ {
+ return -2;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ if (is_duplicate)
+ {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
+/*
+ @brief
+ Update counter for a record
+
+ @retval
+ 0 no error
+ -1 error occurred
+*/
+
+int select_unit::update_counter(Field* counter, longlong value)
+{
+ store_record(table, record[1]);
+ counter->store(value, 0);
+ int error= table->file->ha_update_tmp_row(table->record[1],
+ table->record[0]);
+ return error;
+}
+
+
+/*
+ @brief
+ Try to disable index
+
+ @retval
+ true index is disabled this time
+ false this time did not disable the index
+*/
+
+bool select_unit_ext::disable_index_if_needed(SELECT_LEX *curr_sl)
+{
+ if (is_index_enabled &&
+ (curr_sl == curr_sl->master_unit()->union_distinct ||
+ !curr_sl->next_select()) )
+ {
+ is_index_enabled= false;
+ if (table->file->ha_disable_indexes(HA_KEY_SWITCH_ALL))
+ return false;
+ table->no_keyread=1;
+ return true;
+ }
+ return false;
+}
+
+/*
+ @brief
+ Unfold a record
+
+ @retval
+ 0 no error
+ -1 conversion happened
+*/
+
+int select_unit_ext::unfold_record(ha_rows cnt)
+{
+
+ DBUG_ASSERT(cnt > 0);
+ int error= 0;
+ bool is_convertion_happened= false;
+ while (--cnt)
+ {
+ error= write_record();
+ if (error == -2)
+ {
+ is_convertion_happened= true;
+ error= -1;
+ }
+ }
+ if (is_convertion_happened)
+ return -1;
+ return error;
+}
+
+/*
+ @brief
+ Delete a record
+
+ @retval
+ 0 no error
+ 1 if an error is reported
+*/
+
+int select_unit::delete_record()
+{
+ DBUG_ASSERT(!table->triggers);
+ table->status|= STATUS_DELETED;
+ int not_reported_error= table->file->ha_delete_tmp_row(table->record[0]);
+ return MY_TEST(not_reported_error);
+}
+
/**
Reset and empty the temporary table that stores the materialized query
result.
@@ -448,6 +546,357 @@ void select_unit::cleanup()
}
+/*
+ @brief
+ Set up value needed by send_data() and send_eof()
+
+ @detail
+ - For EXCEPT we will decrease the counter by one
+ and INTERSECT / UNION we increase the counter.
+
+ - For INTERSECT we will modify the second extra field (intersect counter)
+ and for EXCEPT / UNION we modify the first (duplicate counter)
+*/
+
+void select_unit_ext::change_select()
+{
+ select_unit::change_select();
+ switch(step){
+ case UNION_TYPE:
+ increment= 1;
+ curr_op_type= UNION_DISTINCT;
+ break;
+ case EXCEPT_TYPE:
+ increment= -1;
+ curr_op_type= EXCEPT_DISTINCT;
+ break;
+ case INTERSECT_TYPE:
+ increment= 1;
+ curr_op_type= INTERSECT_DISTINCT;
+ break;
+ default: DBUG_ASSERT(0);
+ }
+ if (!thd->lex->current_select->distinct)
+ /* change type from DISTINCT to ALL */
+ curr_op_type= (set_op_type)(curr_op_type + 1);
+
+ duplicate_cnt= table->field[addon_cnt - 1];
+ if (addon_cnt == 2)
+ additional_cnt= table->field[addon_cnt - 2];
+ else
+ additional_cnt= NULL;
+}
+
+
+/*
+ @brief
+ Fill temporary tables for operations need extra fields
+
+ @detail
+ - If this operation is not distinct, we try to find it and increase the
+ counter by "increment" setted in select_unit_ext::change_select().
+
+ - If it is distinct, for UNION we write this record; for INTERSECT we
+ try to find it and increase the intersect counter if found; for EXCEPT
+ we try to find it and delete that record if found.
+
+*/
+
+int select_unit_ext::send_data(List<Item> &values)
+{
+ int rc= 0;
+ int not_reported_error= 0;
+ int find_res;
+ if (unit->offset_limit_cnt)
+ {
+ /* using limit offset,count */
+ unit->offset_limit_cnt--;
+ return 0;
+ }
+ if (thd->killed == ABORT_QUERY)
+ return 0;
+ if (table->no_rows_with_nulls)
+ table->null_catch_flags= CHECK_ROW_FOR_NULLS_TO_REJECT;
+
+ fill_record(thd, table, table->field + addon_cnt, values, true, false);
+ /* set up initial values for records to be written */
+ if ( step == UNION_TYPE )
+ {
+ /* set duplicate counter to 1 */
+ duplicate_cnt->store((longlong) 1, 1);
+ /* set the other counter to 0 */
+ if (curr_op_type == INTERSECT_ALL)
+ additional_cnt->store((longlong) 0, 1);
+ }
+
+ if (unlikely(thd->is_error()))
+ {
+ rc= 1;
+ if (unlikely(not_reported_error))
+ {
+ DBUG_ASSERT(rc);
+ table->file->print_error(not_reported_error, MYF(0));
+ }
+ return rc;
+ }
+ if (table->no_rows_with_nulls)
+ {
+ table->null_catch_flags&= ~CHECK_ROW_FOR_NULLS_TO_REJECT;
+ if (table->null_catch_flags)
+ {
+ if (unlikely(not_reported_error))
+ {
+ DBUG_ASSERT(rc);
+ table->file->print_error(not_reported_error, MYF(0));
+ }
+ return rc;
+ }
+ }
+
+ switch(curr_op_type)
+ {
+ case UNION_ALL:
+ if (!is_index_enabled ||
+ (find_res= table->file->find_unique_row(table->record[0], 0)))
+ {
+ rc= write_record();
+ /* no reaction with conversion */
+ if (rc == -2)
+ rc= 0;
+ }
+ else
+ {
+ longlong cnt= duplicate_cnt->val_int() + increment;
+ not_reported_error= update_counter(duplicate_cnt, cnt);
+ DBUG_ASSERT(!table->triggers);
+ rc= MY_TEST(not_reported_error);
+ }
+ break;
+
+ case EXCEPT_ALL:
+ if (!(find_res= table->file->find_unique_row(table->record[0], 0)))
+ {
+ longlong cnt= duplicate_cnt->val_int() + increment;
+ if (cnt == 0)
+ rc= delete_record();
+ else
+ {
+ not_reported_error= update_counter(duplicate_cnt, cnt);
+ DBUG_ASSERT(!table->triggers);
+ rc= MY_TEST(not_reported_error);
+ }
+ }
+ break;
+
+ case INTERSECT_ALL:
+ if (!(find_res= table->file->find_unique_row(table->record[0], 0)))
+ {
+ longlong cnt= duplicate_cnt->val_int() + increment;
+ if (cnt <= additional_cnt->val_int())
+ {
+ not_reported_error= update_counter(duplicate_cnt, cnt);
+ DBUG_ASSERT(!table->triggers);
+ rc= MY_TEST(not_reported_error);
+ }
+ }
+ break;
+
+ case UNION_DISTINCT:
+ rc= write_record();
+ /* no reaction with conversion */
+ if (rc == -2)
+ rc= 0;
+ break;
+
+ case EXCEPT_DISTINCT:
+ if (!(find_res= table->file->find_unique_row(table->record[0], 0)))
+ rc= delete_record();
+ else
+ rc= not_reported_error= (find_res != 1);
+ break;
+
+ case INTERSECT_DISTINCT:
+ if (!(find_res= table->file->find_unique_row(table->record[0], 0)))
+ {
+ if (additional_cnt->val_int() == prev_step)
+ {
+ not_reported_error= update_counter(additional_cnt, curr_step);
+ rc= MY_TEST(not_reported_error);
+ DBUG_ASSERT(rc != HA_ERR_RECORD_IS_THE_SAME);
+ }
+ else if (additional_cnt->val_int() != curr_step)
+ rc= delete_record();
+ }
+ else
+ rc= not_reported_error= (find_res != 1);
+ break;
+
+ default:
+ DBUG_ASSERT(0);
+ }
+
+ if (unlikely(not_reported_error))
+ {
+ DBUG_ASSERT(rc);
+ table->file->print_error(not_reported_error, MYF(0));
+ }
+ return rc;
+}
+
+
+/*
+ @brief
+ Do post-operation after a operator
+
+ @detail
+ We need to scan in these cases:
+ - If this operation is DISTINCT and next is ALL,
+ duplicate counter needs to be set to 1.
+ - If this operation is INTERSECT ALL and counter needs to be updated.
+ - If next operation is INTERSECT ALL,
+ set up the second extra field (called "intersect_counter") to 0.
+ this extra field counts records in the second operand.
+
+ If this operation is equal to "union_distinct" or is the last operation,
+ we'll disable index. Then if this operation is ALL we'll unfold records.
+*/
+
+bool select_unit_ext::send_eof()
+{
+ int error= 0;
+ SELECT_LEX *curr_sl= thd->lex->current_select;
+ SELECT_LEX *next_sl= curr_sl->next_select();
+ bool is_next_distinct= next_sl && next_sl->distinct;
+ bool is_next_intersect_all=
+ next_sl &&
+ next_sl->get_linkage() == INTERSECT_TYPE &&
+ !next_sl->distinct;
+ bool need_unfold= (disable_index_if_needed(curr_sl) &&
+ !curr_sl->distinct);
+
+ if (((curr_sl->distinct && !is_next_distinct) ||
+ curr_op_type == INTERSECT_ALL ||
+ is_next_intersect_all) &&
+ !need_unfold)
+ {
+ if (!next_sl)
+ DBUG_ASSERT(curr_op_type != INTERSECT_ALL);
+ bool need_update_row;
+ if (unlikely(table->file->ha_rnd_init_with_error(1)))
+ return 1;
+ do
+ {
+ need_update_row= false;
+ if (unlikely(error= table->file->ha_rnd_next(table->record[0])))
+ {
+ if (error == HA_ERR_END_OF_FILE)
+ {
+ error= 0;
+ break;
+ }
+ break;
+ }
+ store_record(table, record[1]);
+
+ if (curr_sl->distinct && !is_next_distinct)
+ {
+ /* set duplicate counter to 1 if next operation is ALL */
+ duplicate_cnt->store(1, 0);
+ need_update_row= true;
+ }
+
+ if (is_next_intersect_all)
+ {
+ longlong d_cnt_val= duplicate_cnt->val_int();
+ if (d_cnt_val == 0)
+ error= delete_record();
+ else
+ {
+ if (curr_op_type == INTERSECT_ALL)
+ {
+ longlong a_cnt_val= additional_cnt->val_int();
+ if (a_cnt_val < d_cnt_val)
+ d_cnt_val= a_cnt_val;
+ }
+ additional_cnt->store(d_cnt_val, 0);
+ duplicate_cnt->store((longlong)0, 0);
+ need_update_row= true;
+ }
+ }
+
+ if (need_update_row)
+ error= table->file->ha_update_tmp_row(table->record[1],
+ table->record[0]);
+ } while (likely(!error));
+ table->file->ha_rnd_end();
+ }
+
+ /* unfold */
+ else if (need_unfold)
+ {
+ /* unfold if is ALL operation */
+ ha_rows dup_cnt;
+ if (unlikely(table->file->ha_rnd_init_with_error(1)))
+ return 1;
+ do
+ {
+ if (unlikely(error= table->file->ha_rnd_next(table->record[0])))
+ {
+ if (error == HA_ERR_END_OF_FILE)
+ {
+ error= 0;
+ break;
+ }
+ break;
+ }
+ dup_cnt= (ha_rows)duplicate_cnt->val_int();
+ /* delete record if not exist in the second operand */
+ if (dup_cnt == 0)
+ {
+ error= delete_record();
+ continue;
+ }
+ if (curr_op_type == INTERSECT_ALL)
+ {
+ longlong add_cnt= additional_cnt->val_int();
+ if (dup_cnt > add_cnt && add_cnt > 0)
+ dup_cnt= (ha_rows)add_cnt;
+ }
+
+ if (dup_cnt == 1)
+ continue;
+
+ duplicate_cnt->store((longlong)1, 0);
+ if (additional_cnt)
+ additional_cnt->store((longlong)0, 0);
+ error= table->file->ha_update_tmp_row(table->record[1],
+ table->record[0]);
+ if (unlikely(error))
+ break;
+
+ if (unfold_record(dup_cnt) == -1)
+ {
+ /* restart the scan */
+ if (unlikely(table->file->ha_rnd_init_with_error(1)))
+ return 1;
+
+ duplicate_cnt= table->field[addon_cnt - 1];
+ if (addon_cnt == 2)
+ additional_cnt= table->field[addon_cnt - 2];
+ else
+ additional_cnt= NULL;
+ continue;
+ }
+ } while (likely(!error));
+ table->file->ha_rnd_end();
+ }
+
+ if (unlikely(error))
+ table->file->print_error(error, MYF(0));
+
+ return (MY_TEST(error));
+}
+
void select_union_recursive::cleanup()
{
if (table)
@@ -818,6 +1267,29 @@ bool st_select_lex_unit::join_union_item_types(THD *thd_arg,
}
+bool init_item_int(THD* thd, Item_int* &item)
+{
+ if (!item)
+ {
+ Query_arena *arena, backup_arena;
+ arena= thd->activate_stmt_arena_if_needed(&backup_arena);
+
+ item= new (thd->mem_root) Item_int(thd, 0);
+
+ if (arena)
+ thd->restore_active_arena(arena, &backup_arena);
+
+ if (!item)
+ return false;
+ }
+ else
+ {
+ item->value= 0;
+ }
+ return true;
+}
+
+
bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
select_result *sel_result,
ulong additional_options)
@@ -829,7 +1301,8 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
uint union_part_count= 0;
select_result *tmp_result;
bool is_union_select;
- bool have_except= FALSE, have_intersect= FALSE;
+ bool have_except= false, have_intersect= false,
+ have_except_all_or_intersect_all= false;
bool instantiate_tmp_table= false;
bool single_tvc= !first_sl->next_select() && first_sl->tvc &&
!fake_select_lex;
@@ -867,7 +1340,7 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
max/min subquery (ALL/ANY optimization)
*/
result= sel_result;
-
+
if (prepared)
{
if (describe)
@@ -906,15 +1379,27 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
found_rows_for_union= first_sl->options & OPTION_FOUND_ROWS;
is_union_select= is_unit_op() || fake_select_lex || single_tvc;
+ /* will only optimize once */
+ if (!bag_set_op_optimized && !is_recursive)
+ {
+ optimize_bag_operation(false);
+ }
+
for (SELECT_LEX *s= first_sl; s; s= s->next_select())
{
switch (s->linkage)
{
case INTERSECT_TYPE:
have_intersect= TRUE;
+ if (!s->distinct){
+ have_except_all_or_intersect_all= true;
+ }
break;
case EXCEPT_TYPE:
have_except= TRUE;
+ if (!s->distinct){
+ have_except_all_or_intersect_all= TRUE;
+ }
break;
default:
break;
@@ -940,7 +1425,19 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
else
{
if (!is_recursive)
- union_result= new (thd->mem_root) select_unit(thd);
+ /*
+ class "select_unit_ext" handles query contains EXCEPT ALL and / or
+ INTERSECT ALL. Others are handled by class "select_unit"
+ If have EXCEPT ALL or INTERSECT ALL in the query. First operand
+ should be UNION ALL
+ */
+ if (have_except_all_or_intersect_all)
+ {
+ union_result= new (thd->mem_root) select_unit_ext(thd);
+ first_sl->distinct= false;
+ }
+ else
+ union_result= new (thd->mem_root) select_unit(thd);
else
{
with_element->rec_result=
@@ -1080,6 +1577,10 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
instantiate_tmp_table, false,
0))
goto err;
+ if (have_except_all_or_intersect_all)
+ {
+ union_result->init();
+ }
if (!derived_arg->table)
{
derived_arg->table= with_element->rec_result->rec_tables.head();
@@ -1091,6 +1592,7 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
}
}
}
+
// In case of a non-recursive UNION, join data types for all UNION parts.
if (!is_recursive && join_union_item_types(thd, types, union_part_count))
goto err;
@@ -1166,48 +1668,42 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
if (global_parameters()->ftfunc_list->elements)
create_options= create_options | TMP_TABLE_FORCE_MYISAM;
+ /* extra field counter */
+ uint hidden= 0;
+ Item_int *addon_fields[2]= {0};
if (!is_recursive)
{
- uint hidden= 0;
- if (have_intersect)
+ if (have_except_all_or_intersect_all)
{
- hidden= 1;
- if (!intersect_mark)
- {
- /*
- For intersect we add a hidden column first that contains
- the current select number of the time when the row was
- added to the temporary table
- */
-
- Query_arena *arena, backup_arena;
- arena= thd->activate_stmt_arena_if_needed(&backup_arena);
-
- intersect_mark= new (thd->mem_root) Item_int(thd, 0);
-
- if (arena)
- thd->restore_active_arena(arena, &backup_arena);
+ /* add duplicate_count */
+ ++hidden;
+ }
+ /* add intersect_count */
+ if (have_intersect)
+ ++hidden;
- if (!intersect_mark)
- goto err;
- }
- else
- intersect_mark->value= 0; //reset
- types.push_front(union_result->intersect_mark= intersect_mark);
- union_result->intersect_mark->name.str= "___";
- union_result->intersect_mark->name.length= 3;
+ for(uint i= 0; i< hidden; i++)
+ {
+ init_item_int(thd, addon_fields[i]);
+ types.push_front(addon_fields[i]);
+ addon_fields[i]->name.str= i ? "__CNT_1" : "__CNT_2";
+ addon_fields[i]->name.length= 7;
}
bool error=
union_result->create_result_table(thd, &types,
- MY_TEST(union_distinct),
+ MY_TEST(union_distinct) ||
+ have_except_all_or_intersect_all ||
+ have_intersect,
create_options, &empty_clex_str, false,
instantiate_tmp_table, false,
hidden);
- if (intersect_mark)
+ union_result->addon_cnt= hidden;
+ for (uint i= 0; i < hidden; i++)
types.pop();
if (unlikely(error))
goto err;
}
+
if (fake_select_lex && !fake_select_lex->first_cond_optimization)
{
save_tablenr= result_table_list.tablenr_exec;
@@ -1235,9 +1731,8 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
arena= thd->activate_stmt_arena_if_needed(&backup_arena);
saved_error= table->fill_item_list(&item_list);
- // Item_list is inherited from 'types', so there could be the counter
- if (intersect_mark)
- item_list.pop(); // remove intersect counter
+ for (uint i= 0; i < hidden; i++)
+ item_list.pop();
if (arena)
thd->restore_active_arena(arena, &backup_arena);
@@ -1282,7 +1777,7 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
We're in execution of a prepared statement or stored procedure:
reset field items to point at fields from the created temporary table.
*/
- table->reset_item_list(&item_list, intersect_mark ? 1 : 0);
+ table->reset_item_list(&item_list, hidden);
}
if (fake_select_lex != NULL &&
(thd->stmt_arena->is_stmt_prepare() ||
@@ -1316,9 +1811,170 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
/**
+ @brief
+ Optimize a sequence of set operations
+
+ @param first_sl first select of the level now under processing
+
+ @details
+ The method optimizes with the following rules:
+ - (1)If a subsequence of INTERSECT contains at least one INTERSECT DISTINCT
+ or this subsequence is followed by UNION/EXCEPT DISTINCT then all
+ elements in the subsequence can changed for INTERSECT DISTINCT
+ - (2)If previous set operation is DISTINCT then EXCEPT ALL can be replaced
+ for EXCEPT DISTINCT
+ - (3)If UNION DISTINCT / EXCEPT DISTINCT follows a subsequence of UNION ALL
+ then all set operations of this subsequence can be replaced for
+ UNION DISTINCT
+
+ For derived table it will look up outer select, and do optimize based on
+ outer select.
+
+ Variable "union_distinct" will be updated in the end.
+ Not compatible with Oracle Mode.
+*/
+
+void st_select_lex_unit::optimize_bag_operation(bool is_outer_distinct)
+{
+ /*
+ skip run optimize for:
+ ORACLE MODE
+ CREATE VIEW
+ PREPARE ... FROM
+ recursive
+ */
+ if ((thd->variables.sql_mode & MODE_ORACLE) ||
+ (thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW) ||
+ (fake_select_lex != NULL && thd->stmt_arena->is_stmt_prepare()) ||
+ (with_element && with_element->is_recursive ))
+ return;
+ DBUG_ASSERT(!bag_set_op_optimized);
+
+ SELECT_LEX *sl;
+ /* INTERSECT subsequence can occur only at the very beginning */
+ /* The first select with linkage == INTERSECT_TYPE */
+ SELECT_LEX *intersect_start= NULL;
+ /* The first select after the INTERSECT subsequence */
+ SELECT_LEX *intersect_end= NULL;
+ /*
+ Will point to the last node before UNION ALL subsequence.
+ Index can be disable there.
+ */
+ SELECT_LEX *disable_index= NULL;
+ /*
+ True if there is a select with:
+ linkage == INTERSECT_TYPE && distinct==true
+ */
+ bool any_intersect_distinct= false;
+ SELECT_LEX *prev_sl= first_select();
+
+ /* process INTERSECT subsequence in the begining */
+ for (sl= prev_sl->next_select(); sl; prev_sl= sl, sl= sl->next_select())
+ {
+ if (sl->linkage != INTERSECT_TYPE)
+ {
+ intersect_end= sl;
+ break;
+ }
+ else
+ {
+ if (!intersect_start)
+ intersect_start= sl;
+ if (sl->distinct)
+ {
+ any_intersect_distinct= true;
+ disable_index= sl;
+ }
+ }
+ }
+
+ /* if subquery only contains INTERSECT and outer is UNION DISTINCT*/
+ if (!sl && is_outer_distinct)
+ any_intersect_distinct= true;
+
+ /* The first select of the current UNION ALL subsequence */
+ SELECT_LEX *union_all_start= NULL;
+ for ( ; sl; prev_sl= sl, sl= sl->next_select())
+ {
+ DBUG_ASSERT (sl->linkage != INTERSECT_TYPE);
+ if (!sl->distinct)
+ {
+ if (sl->linkage == UNION_TYPE)
+ {
+ if (!union_all_start)
+ {
+ union_all_start= sl;
+ }
+ }
+ else
+ {
+ DBUG_ASSERT (sl->linkage == EXCEPT_TYPE);
+ union_all_start= NULL;
+ if (prev_sl->distinct && prev_sl->is_set_op())
+ {
+ sl->distinct= true;
+ disable_index= sl;
+ }
+ }
+ }
+ else
+ { /* sl->distinct == true */
+ for (SELECT_LEX *si= union_all_start; si && si != sl; si= si->next_select())
+ {
+ si->distinct= true;
+ }
+ union_all_start= NULL;
+ disable_index= sl;
+ }
+ }
+
+ if (is_outer_distinct)
+ {
+ for (SELECT_LEX *si= union_all_start; si && si != sl; si= si->next_select())
+ {
+ si->distinct= true;
+ }
+ union_all_start= NULL;
+ }
+
+ if (any_intersect_distinct ||
+ (intersect_end != NULL && intersect_end->distinct))
+ {
+ for (sl= intersect_start; sl && sl != intersect_end; sl= sl->next_select())
+ {
+ sl->distinct= true;
+ if (disable_index && disable_index->linkage == INTERSECT_TYPE)
+ disable_index= sl;
+ }
+ }
+ /*
+ if disable_index points to a INTERSECT, based on rule 1 we can set it
+ to the last INTERSECT node.
+ */
+ if (disable_index && disable_index->linkage == INTERSECT_TYPE &&
+ intersect_end && intersect_end->distinct)
+ disable_index= intersect_end;
+ /* union_distinct controls when to disable index */
+ union_distinct= disable_index;
+
+ /* recursive call this function for whole lex tree */
+ for(sl= first_select(); sl; sl= sl->next_select())
+ {
+ if (sl->is_unit_nest() &&
+ sl->first_inner_unit() &&
+ !sl->first_inner_unit()->bag_set_op_optimized)
+ sl->first_inner_unit()->optimize_bag_operation(sl->distinct);
+ }
+
+ /* mark as optimized */
+ bag_set_op_optimized= true;
+}
+
+
+/**
Run optimization phase.
- @return FALSE unit successfully passed optimization phase.
+ @return false unit successfully passed optimization phase.
@return TRUE an error occur.
*/
bool st_select_lex_unit::optimize()
@@ -1328,10 +1984,10 @@ bool st_select_lex_unit::optimize()
DBUG_ENTER("st_select_lex_unit::optimize");
if (optimized && !uncacheable && !describe)
- DBUG_RETURN(FALSE);
+ DBUG_RETURN(false);
if (with_element && with_element->is_recursive && optimize_started)
- DBUG_RETURN(FALSE);
+ DBUG_RETURN(false);
optimize_started= true;
if (uncacheable || !item || !item->assigned() || describe)
@@ -1351,9 +2007,12 @@ bool st_select_lex_unit::optimize()
table->file->info(HA_STATUS_VARIABLE);
}
/* re-enabling indexes for next subselect iteration */
- if (union_distinct && table->file->ha_enable_indexes(HA_KEY_SWITCH_ALL))
+ if ((union_result->force_enable_index_if_needed() || union_distinct))
{
- DBUG_ASSERT(0);
+ if(table->file->ha_enable_indexes(HA_KEY_SWITCH_ALL))
+ DBUG_ASSERT(0);
+ else
+ table->no_keyread= 0;
}
}
for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
@@ -1499,7 +2158,7 @@ bool st_select_lex_unit::exec()
}
else
{
- sl->join->select_options=
+ sl->join->select_options=
(select_limit_cnt == HA_POS_ERROR || sl->braces) ?
sl->options & ~OPTION_FOUND_ROWS : sl->options | found_rows_for_union;
saved_error= sl->join->optimize();
@@ -1512,7 +2171,7 @@ bool st_select_lex_unit::exec()
sl->tvc->exec(sl);
else
sl->join->exec();
- if (sl == union_distinct && !(with_element && with_element->is_recursive))
+ if (sl == union_distinct && !have_except_all_or_intersect_all)
{
// This is UNION DISTINCT, so there should be a fake_select_lex
DBUG_ASSERT(fake_select_lex != NULL);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index edf6b76..a09af12 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -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; }
;
/*
diff --git a/storage/heap/hp_write.c b/storage/heap/hp_write.c
index 877c1bc..670f628 100644
--- a/storage/heap/hp_write.c
+++ b/storage/heap/hp_write.c
@@ -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;
[View Less]
1
0