join_nested.test, join_nested.result:
new file Many files: Nested joins added. sql/item_cmpfunc.h: Nested joins added. sql/item_func.h: Nested joins added. sql/sql_base.cc: Nested joins added. sql/sql_lex.cc: Nested joins added. sql/sql_lex.h: Nested joins added. sql/sql_parse.cc: Nested joins added. sql/sql_select.cc: Nested joins added. sql/sql_select.h: Nested joins added. sql/sql_yacc.yy: Nested joins added. sql/table.h: Nested joins added. mysql-test/r/join_outer.result: Nested joins added. mysql-test/r/select.result: Nested joins added.
This commit is contained in:
parent
d4898d174c
commit
cd23d6e37a
1161
mysql-test/r/join_nested.result
Normal file
1161
mysql-test/r/join_nested.result
Normal file
File diff suppressed because it is too large
Load Diff
@ -356,13 +356,7 @@ select t1.name, t2.name, t2.id, t2.owner, t3.id from t1 left join t2 on (t1.id =
|
||||
name name id owner id
|
||||
Antonio Paz El Gato 1 1 1
|
||||
Antonio Paz Perrito 2 1 1
|
||||
Lilliana Angelovska NULL NULL NULL 1
|
||||
Thimble Smith NULL NULL NULL 1
|
||||
Antonio Paz NULL NULL NULL 2
|
||||
Lilliana Angelovska NULL NULL NULL 2
|
||||
Thimble Smith NULL NULL NULL 2
|
||||
Antonio Paz NULL NULL NULL 3
|
||||
Lilliana Angelovska NULL NULL NULL 3
|
||||
NULL NULL NULL NULL 2
|
||||
Thimble Smith Happy 3 3 3
|
||||
drop table t1,t2;
|
||||
create table t1 (id int not null, str char(10), index(str));
|
||||
|
@ -2157,13 +2157,10 @@ a a a
|
||||
3 3 3
|
||||
select * from t1 inner join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1;
|
||||
a a a
|
||||
1 1 NULL
|
||||
2 1 1
|
||||
3 1 1
|
||||
1 2 NULL
|
||||
2 2 2
|
||||
3 2 2
|
||||
1 3 NULL
|
||||
2 3 3
|
||||
3 3 3
|
||||
select * from (t1 as t2 left join t1 as t3 using (a)) inner join t1 using ( a );
|
||||
@ -2174,13 +2171,7 @@ a a a
|
||||
select * from t1 inner join (t1 as t2 left join t1 as t3 using (a)) using ( a );
|
||||
a a a
|
||||
1 1 1
|
||||
2 1 NULL
|
||||
3 1 NULL
|
||||
1 2 NULL
|
||||
2 2 2
|
||||
3 2 NULL
|
||||
1 3 NULL
|
||||
2 3 NULL
|
||||
3 3 3
|
||||
select * from (t1 as t2 left join t1 as t3 using (a)) left outer join t1 on t1.a>1;
|
||||
a a a
|
||||
@ -2192,14 +2183,12 @@ a a a
|
||||
3 3 3
|
||||
select * from t1 left outer join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1;
|
||||
a a a
|
||||
1 1 NULL
|
||||
1 NULL NULL
|
||||
2 1 1
|
||||
3 1 1
|
||||
1 2 NULL
|
||||
2 2 2
|
||||
3 2 2
|
||||
1 3 NULL
|
||||
2 3 3
|
||||
3 1 1
|
||||
3 2 2
|
||||
3 3 3
|
||||
select * from (t1 as t2 left join t1 as t3 using (a)) left join t1 using ( a );
|
||||
a a a
|
||||
@ -2209,13 +2198,7 @@ a a a
|
||||
select * from t1 left join (t1 as t2 left join t1 as t3 using (a)) using ( a );
|
||||
a a a
|
||||
1 1 1
|
||||
2 1 NULL
|
||||
3 1 NULL
|
||||
1 2 NULL
|
||||
2 2 2
|
||||
3 2 NULL
|
||||
1 3 NULL
|
||||
2 3 NULL
|
||||
3 3 3
|
||||
select * from (t1 as t2 left join t1 as t3 using (a)) natural left join t1;
|
||||
a a a
|
||||
@ -2229,9 +2212,7 @@ a a a
|
||||
3 3 3
|
||||
select * from (t1 as t2 left join t1 as t3 using (a)) right join t1 on t1.a>1;
|
||||
a a a
|
||||
1 NULL 1
|
||||
2 NULL 1
|
||||
3 NULL 1
|
||||
NULL NULL 1
|
||||
1 1 2
|
||||
2 2 2
|
||||
3 3 2
|
||||
@ -2249,13 +2230,7 @@ a a a
|
||||
select * from (t1 as t2 left join t1 as t3 using (a)) right outer join t1 using ( a );
|
||||
a a a
|
||||
1 1 1
|
||||
2 NULL 1
|
||||
3 NULL 1
|
||||
1 NULL 2
|
||||
2 2 2
|
||||
3 NULL 2
|
||||
1 NULL 3
|
||||
2 NULL 3
|
||||
3 3 3
|
||||
select * from t1 right outer join (t1 as t2 left join t1 as t3 using (a)) using ( a );
|
||||
a a a
|
||||
@ -2265,13 +2240,7 @@ a a a
|
||||
select * from (t1 as t2 left join t1 as t3 using (a)) natural right join t1;
|
||||
a a a
|
||||
1 1 1
|
||||
2 NULL 1
|
||||
3 NULL 1
|
||||
1 NULL 2
|
||||
2 2 2
|
||||
3 NULL 2
|
||||
1 NULL 3
|
||||
2 NULL 3
|
||||
3 3 3
|
||||
select * from t1 natural right join (t1 as t2 left join t1 as t3 using (a));
|
||||
a a a
|
||||
|
693
mysql-test/t/join_nested.test
Normal file
693
mysql-test/t/join_nested.test
Normal file
@ -0,0 +1,693 @@
|
||||
|
||||
|
||||
DROP TABLE IF EXISTS t0,t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||
|
||||
CREATE TABLE t0 (a int, b int, c int);
|
||||
CREATE TABLE t1 (a int, b int, c int);
|
||||
CREATE TABLE t2 (a int, b int, c int);
|
||||
CREATE TABLE t3 (a int, b int, c int);
|
||||
CREATE TABLE t4 (a int, b int, c int);
|
||||
CREATE TABLE t5 (a int, b int, c int);
|
||||
CREATE TABLE t6 (a int, b int, c int);
|
||||
CREATE TABLE t7 (a int, b int, c int);
|
||||
CREATE TABLE t8 (a int, b int, c int);
|
||||
CREATE TABLE t9 (a int, b int, c int);
|
||||
|
||||
INSERT INTO t0 VALUES (1,1,0), (1,2,0), (2,2,0);
|
||||
INSERT INTO t1 VALUES (1,3,0), (2,2,0), (3,2,0);
|
||||
INSERT INTO t2 VALUES (3,3,0), (4,2,0), (5,3,0);
|
||||
INSERT INTO t3 VALUES (1,2,0), (2,2,0);
|
||||
INSERT INTO t4 VALUES (3,2,0), (4,2,0);
|
||||
INSERT INTO t5 VALUES (3,1,0), (2,2,0), (3,3,0);
|
||||
INSERT INTO t6 VALUES (3,2,0), (6,2,0), (6,1,0);
|
||||
INSERT INTO t7 VALUES (1,1,0), (2,2,0);
|
||||
INSERT INTO t8 VALUES (0,2,0), (1,2,0);
|
||||
INSERT INTO t9 VALUES (1,1,0), (1,2,0), (3,3,0);
|
||||
|
||||
|
||||
SELECT t2.a,t2.b
|
||||
FROM t2;
|
||||
|
||||
SELECT t3.a,t3.b
|
||||
FROM t3;
|
||||
|
||||
SELECT t4.a,t4.b
|
||||
FROM t4;
|
||||
|
||||
SELECT t3.a,t3.b,t4.a,t4.b
|
||||
FROM t3,t4;
|
||||
|
||||
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
|
||||
FROM t2
|
||||
LEFT JOIN
|
||||
(t3, t4)
|
||||
ON t2.b=t4.b;
|
||||
|
||||
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
|
||||
FROM t2
|
||||
LEFT JOIN
|
||||
(t3, t4)
|
||||
ON t3.a=1 AND t2.b=t4.b;
|
||||
|
||||
EXPLAIN
|
||||
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
|
||||
FROM t2
|
||||
LEFT JOIN
|
||||
(t3, t4)
|
||||
ON t2.b=t4.b
|
||||
WHERE t3.a=1 OR t3.c IS NULL;
|
||||
|
||||
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
|
||||
FROM t2
|
||||
LEFT JOIN
|
||||
(t3, t4)
|
||||
ON t2.b=t4.b
|
||||
WHERE t3.a=1 OR t3.c IS NULL;
|
||||
|
||||
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
|
||||
FROM t2
|
||||
LEFT JOIN
|
||||
(t3, t4)
|
||||
ON t2.b=t4.b
|
||||
WHERE t3.a>1 OR t3.c IS NULL;
|
||||
|
||||
SELECT t5.a,t5.b
|
||||
FROM t5;
|
||||
|
||||
SELECT t3.a,t3.b,t4.a,t4.b,t5.a,t5.b
|
||||
FROM t3,t4,t5;
|
||||
|
||||
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b
|
||||
FROM t2
|
||||
LEFT JOIN
|
||||
(t3, t4, t5)
|
||||
ON t2.b=t4.b;
|
||||
|
||||
EXPLAIN
|
||||
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b
|
||||
FROM t2
|
||||
LEFT JOIN
|
||||
(t3, t4, t5)
|
||||
ON t2.b=t4.b
|
||||
WHERE t3.a>1 OR t3.c IS NULL;
|
||||
|
||||
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b
|
||||
FROM t2
|
||||
LEFT JOIN
|
||||
(t3, t4, t5)
|
||||
ON t2.b=t4.b
|
||||
WHERE t3.a>1 OR t3.c IS NULL;
|
||||
|
||||
EXPLAIN
|
||||
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b
|
||||
FROM t2
|
||||
LEFT JOIN
|
||||
(t3, t4, t5)
|
||||
ON t2.b=t4.b
|
||||
WHERE (t3.a>1 OR t3.c IS NULL) AND
|
||||
(t5.a<3 OR t5.c IS NULL);
|
||||
|
||||
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b
|
||||
FROM t2
|
||||
LEFT JOIN
|
||||
(t3, t4, t5)
|
||||
ON t2.b=t4.b
|
||||
WHERE (t3.a>1 OR t3.c IS NULL) AND
|
||||
(t5.a<3 OR t5.c IS NULL);
|
||||
|
||||
SELECT t6.a,t6.b
|
||||
FROM t6;
|
||||
|
||||
SELECT t7.a,t7.b
|
||||
FROM t7;
|
||||
|
||||
SELECT t6.a,t6.b,t7.a,t7.b
|
||||
FROM t6,t7;
|
||||
|
||||
SELECT t8.a,t8.b
|
||||
FROM t8;
|
||||
|
||||
EXPLAIN
|
||||
SELECT t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
|
||||
FROM t6,
|
||||
t7
|
||||
LEFT JOIN
|
||||
t8
|
||||
ON t7.b=t8.b AND t6.b < 10;
|
||||
|
||||
SELECT t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
|
||||
FROM t6,
|
||||
t7
|
||||
LEFT JOIN
|
||||
t8
|
||||
ON t7.b=t8.b AND t6.b < 10;
|
||||
|
||||
SELECT t5.a,t5.b
|
||||
FROM t5;
|
||||
|
||||
SELECT t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
|
||||
FROM t5
|
||||
LEFT JOIN
|
||||
(
|
||||
t6,
|
||||
t7
|
||||
LEFT JOIN
|
||||
t8
|
||||
ON t7.b=t8.b AND t6.b < 10
|
||||
)
|
||||
ON t6.b >= 2 AND t5.b=t7.b;
|
||||
|
||||
SELECT t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
|
||||
FROM t5
|
||||
LEFT JOIN
|
||||
(
|
||||
t6,
|
||||
t7
|
||||
LEFT JOIN
|
||||
t8
|
||||
ON t7.b=t8.b AND t6.b < 10
|
||||
)
|
||||
ON t6.b >= 2 AND t5.b=t7.b AND
|
||||
(t8.a < 1 OR t8.c IS NULL);
|
||||
|
||||
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
|
||||
FROM t2
|
||||
LEFT JOIN
|
||||
(t3, t4)
|
||||
ON t3.a=1 AND t2.b=t4.b;
|
||||
|
||||
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
|
||||
t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
|
||||
FROM t2
|
||||
LEFT JOIN
|
||||
(t3, t4)
|
||||
ON t3.a=1 AND t2.b=t4.b,
|
||||
t5
|
||||
LEFT JOIN
|
||||
(
|
||||
t6,
|
||||
t7
|
||||
LEFT JOIN
|
||||
t8
|
||||
ON t7.b=t8.b AND t6.b < 10
|
||||
)
|
||||
ON t6.b >= 2 AND t5.b=t7.b;
|
||||
|
||||
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
|
||||
t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
|
||||
FROM t2
|
||||
LEFT JOIN
|
||||
(t3, t4)
|
||||
ON t3.a=1 AND t2.b=t4.b,
|
||||
t5
|
||||
LEFT JOIN
|
||||
(
|
||||
t6,
|
||||
t7
|
||||
LEFT JOIN
|
||||
t8
|
||||
ON t7.b=t8.b AND t6.b < 10
|
||||
)
|
||||
ON t6.b >= 2 AND t5.b=t7.b
|
||||
WHERE t2.a > 3 AND
|
||||
(t6.a < 6 OR t6.c IS NULL);
|
||||
|
||||
SELECT t1.a,t1.b
|
||||
FROM t1;
|
||||
|
||||
SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
|
||||
t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
|
||||
FROM t1
|
||||
LEFT JOIN
|
||||
(
|
||||
t2
|
||||
LEFT JOIN
|
||||
(t3, t4)
|
||||
ON t3.a=1 AND t2.b=t4.b,
|
||||
t5
|
||||
LEFT JOIN
|
||||
(
|
||||
t6,
|
||||
t7
|
||||
LEFT JOIN
|
||||
t8
|
||||
ON t7.b=t8.b AND t6.b < 10
|
||||
)
|
||||
ON t6.b >= 2 AND t5.b=t7.b
|
||||
)
|
||||
ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
|
||||
(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
|
||||
(t1.a != 2);
|
||||
|
||||
SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
|
||||
t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
|
||||
FROM t1
|
||||
LEFT JOIN
|
||||
(
|
||||
t2
|
||||
LEFT JOIN
|
||||
(t3, t4)
|
||||
ON t3.a=1 AND t2.b=t4.b,
|
||||
t5
|
||||
LEFT JOIN
|
||||
(
|
||||
t6,
|
||||
t7
|
||||
LEFT JOIN
|
||||
t8
|
||||
ON t7.b=t8.b AND t6.b < 10
|
||||
)
|
||||
ON t6.b >= 2 AND t5.b=t7.b
|
||||
)
|
||||
ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
|
||||
(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
|
||||
(t1.a != 2)
|
||||
WHERE (t2.a >= 4 OR t2.c IS NULL);
|
||||
|
||||
SELECT t0.a,t0.b
|
||||
FROM t0;
|
||||
|
||||
EXPLAIN
|
||||
SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
|
||||
t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
|
||||
FROM t0,t1
|
||||
LEFT JOIN
|
||||
(
|
||||
t2
|
||||
LEFT JOIN
|
||||
(t3, t4)
|
||||
ON t3.a=1 AND t2.b=t4.b,
|
||||
t5
|
||||
LEFT JOIN
|
||||
(
|
||||
t6,
|
||||
t7
|
||||
LEFT JOIN
|
||||
t8
|
||||
ON t7.b=t8.b AND t6.b < 10
|
||||
)
|
||||
ON t6.b >= 2 AND t5.b=t7.b
|
||||
)
|
||||
ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
|
||||
(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
|
||||
(t1.a != 2)
|
||||
WHERE t0.a=1 AND
|
||||
t0.b=t1.b AND
|
||||
(t2.a >= 4 OR t2.c IS NULL);
|
||||
|
||||
SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
|
||||
t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
|
||||
FROM t0,t1
|
||||
LEFT JOIN
|
||||
(
|
||||
t2
|
||||
LEFT JOIN
|
||||
(t3, t4)
|
||||
ON t3.a=1 AND t2.b=t4.b,
|
||||
t5
|
||||
LEFT JOIN
|
||||
(
|
||||
t6,
|
||||
t7
|
||||
LEFT JOIN
|
||||
t8
|
||||
ON t7.b=t8.b AND t6.b < 10
|
||||
)
|
||||
ON t6.b >= 2 AND t5.b=t7.b
|
||||
)
|
||||
ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
|
||||
(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
|
||||
(t1.a != 2)
|
||||
WHERE t0.a=1 AND
|
||||
t0.b=t1.b AND
|
||||
(t2.a >= 4 OR t2.c IS NULL);
|
||||
|
||||
EXPLAIN
|
||||
SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
|
||||
t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
|
||||
FROM t0,t1
|
||||
LEFT JOIN
|
||||
(
|
||||
t2
|
||||
LEFT JOIN
|
||||
(t3, t4)
|
||||
ON t3.a=1 AND t2.b=t4.b,
|
||||
t5
|
||||
LEFT JOIN
|
||||
(
|
||||
t6,
|
||||
t7
|
||||
LEFT JOIN
|
||||
t8
|
||||
ON t7.b=t8.b AND t6.b < 10
|
||||
)
|
||||
ON t6.b >= 2 AND t5.b=t7.b
|
||||
)
|
||||
ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
|
||||
(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
|
||||
(t1.a != 2),
|
||||
t9
|
||||
WHERE t0.a=1 AND
|
||||
t0.b=t1.b AND
|
||||
(t2.a >= 4 OR t2.c IS NULL) AND
|
||||
(t3.a < 5 OR t3.c IS NULL) AND
|
||||
(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
|
||||
(t5.a >=2 OR t5.c IS NULL) AND
|
||||
(t6.a >=4 OR t6.c IS NULL) AND
|
||||
(t7.a <= 2 OR t7.c IS NULL) AND
|
||||
(t8.a < 1 OR t8.c IS NULL) AND
|
||||
(t8.b=t9.b OR t8.c IS NULL) AND
|
||||
(t9.a=1);
|
||||
|
||||
SELECT t9.a,t9.b
|
||||
FROM t9;
|
||||
|
||||
SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
|
||||
t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
|
||||
FROM t0,t1
|
||||
LEFT JOIN
|
||||
(
|
||||
t2
|
||||
LEFT JOIN
|
||||
(t3, t4)
|
||||
ON t3.a=1 AND t2.b=t4.b,
|
||||
t5
|
||||
LEFT JOIN
|
||||
(
|
||||
t6,
|
||||
t7
|
||||
LEFT JOIN
|
||||
t8
|
||||
ON t7.b=t8.b AND t6.b < 10
|
||||
)
|
||||
ON t6.b >= 2 AND t5.b=t7.b
|
||||
)
|
||||
ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
|
||||
(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
|
||||
(t1.a != 2),
|
||||
t9
|
||||
WHERE t0.a=1 AND
|
||||
t0.b=t1.b AND
|
||||
(t2.a >= 4 OR t2.c IS NULL) AND
|
||||
(t3.a < 5 OR t3.c IS NULL) AND
|
||||
(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
|
||||
(t5.a >=2 OR t5.c IS NULL) AND
|
||||
(t6.a >=4 OR t6.c IS NULL) AND
|
||||
(t7.a <= 2 OR t7.c IS NULL) AND
|
||||
(t8.a < 1 OR t8.c IS NULL) AND
|
||||
(t8.b=t9.b OR t8.c IS NULL) AND
|
||||
(t9.a=1);
|
||||
|
||||
SELECT t1.a,t1.b
|
||||
FROM t1;
|
||||
|
||||
SELECT t2.a,t2.b
|
||||
FROM t2;
|
||||
|
||||
SELECT t3.a,t3.b
|
||||
FROM t3;
|
||||
|
||||
SELECT t2.a,t2.b,t3.a,t3.b
|
||||
FROM t2
|
||||
LEFT JOIN
|
||||
t3
|
||||
ON t2.b=t3.b;
|
||||
|
||||
SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b
|
||||
FROM t1, t2
|
||||
LEFT JOIN
|
||||
t3
|
||||
ON t2.b=t3.b
|
||||
WHERE t1.a <= 2;
|
||||
|
||||
SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b
|
||||
FROM t1, t3
|
||||
RIGHT JOIN
|
||||
t2
|
||||
ON t2.b=t3.b
|
||||
WHERE t1.a <= 2;
|
||||
|
||||
SELECT t3.a,t3.b,t4.a,t4.b
|
||||
FROM t3,t4;
|
||||
|
||||
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
|
||||
FROM t2
|
||||
LEFT JOIN
|
||||
(t3, t4)
|
||||
ON t3.a=1 AND t2.b=t4.b;
|
||||
|
||||
SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
|
||||
FROM t1, t2
|
||||
LEFT JOIN
|
||||
(t3, t4)
|
||||
ON t3.a=1 AND t2.b=t4.b
|
||||
WHERE t1.a <= 2;
|
||||
|
||||
SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
|
||||
FROM t1, (t3, t4)
|
||||
RIGHT JOIN
|
||||
t2
|
||||
ON t3.a=1 AND t2.b=t4.b
|
||||
WHERE t1.a <= 2;
|
||||
|
||||
SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
|
||||
FROM t1, t3, t4
|
||||
RIGHT JOIN
|
||||
t2
|
||||
ON t3.a=1 AND t2.b=t4.b
|
||||
WHERE t1.a <= 2;
|
||||
|
||||
CREATE INDEX idx_b ON t2(b);
|
||||
|
||||
EXPLAIN
|
||||
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
|
||||
FROM t3,t4
|
||||
LEFT JOIN
|
||||
(t1,t2)
|
||||
ON t3.a=1 AND t3.b=t2.b AND t2.b=t4.b;
|
||||
|
||||
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
|
||||
FROM t3,t4
|
||||
LEFT JOIN
|
||||
(t1,t2)
|
||||
ON t3.a=1 AND t3.b=t2.b AND t2.b=t4.b;
|
||||
|
||||
EXPLAIN
|
||||
SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
|
||||
t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
|
||||
FROM t0,t1
|
||||
LEFT JOIN
|
||||
(
|
||||
t2
|
||||
LEFT JOIN
|
||||
(t3, t4)
|
||||
ON t3.a=1 AND t2.b=t4.b,
|
||||
t5
|
||||
LEFT JOIN
|
||||
(
|
||||
t6,
|
||||
t7
|
||||
LEFT JOIN
|
||||
t8
|
||||
ON t7.b=t8.b AND t6.b < 10
|
||||
)
|
||||
ON t6.b >= 2 AND t5.b=t7.b
|
||||
)
|
||||
ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
|
||||
(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
|
||||
(t1.a != 2),
|
||||
t9
|
||||
WHERE t0.a=1 AND
|
||||
t0.b=t1.b AND
|
||||
(t2.a >= 4 OR t2.c IS NULL) AND
|
||||
(t3.a < 5 OR t3.c IS NULL) AND
|
||||
(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
|
||||
(t5.a >=2 OR t5.c IS NULL) AND
|
||||
(t6.a >=4 OR t6.c IS NULL) AND
|
||||
(t7.a <= 2 OR t7.c IS NULL) AND
|
||||
(t8.a < 1 OR t8.c IS NULL) AND
|
||||
(t8.b=t9.b OR t8.c IS NULL) AND
|
||||
(t9.a=1);
|
||||
|
||||
CREATE INDEX idx_b ON t4(b);
|
||||
CREATE INDEX idx_b ON t5(b);
|
||||
|
||||
EXPLAIN
|
||||
SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
|
||||
t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
|
||||
FROM t0,t1
|
||||
LEFT JOIN
|
||||
(
|
||||
t2
|
||||
LEFT JOIN
|
||||
(t3, t4)
|
||||
ON t3.a=1 AND t2.b=t4.b,
|
||||
t5
|
||||
LEFT JOIN
|
||||
(
|
||||
t6,
|
||||
t7
|
||||
LEFT JOIN
|
||||
t8
|
||||
ON t7.b=t8.b AND t6.b < 10
|
||||
)
|
||||
ON t6.b >= 2 AND t5.b=t7.b
|
||||
)
|
||||
ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
|
||||
(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
|
||||
(t1.a != 2),
|
||||
t9
|
||||
WHERE t0.a=1 AND
|
||||
t0.b=t1.b AND
|
||||
(t2.a >= 4 OR t2.c IS NULL) AND
|
||||
(t3.a < 5 OR t3.c IS NULL) AND
|
||||
(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
|
||||
(t5.a >=2 OR t5.c IS NULL) AND
|
||||
(t6.a >=4 OR t6.c IS NULL) AND
|
||||
(t7.a <= 2 OR t7.c IS NULL) AND
|
||||
(t8.a < 1 OR t8.c IS NULL) AND
|
||||
(t8.b=t9.b OR t8.c IS NULL) AND
|
||||
(t9.a=1);
|
||||
|
||||
CREATE INDEX idx_b ON t8(b);
|
||||
|
||||
EXPLAIN
|
||||
SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
|
||||
t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
|
||||
FROM t0,t1
|
||||
LEFT JOIN
|
||||
(
|
||||
t2
|
||||
LEFT JOIN
|
||||
(t3, t4)
|
||||
ON t3.a=1 AND t2.b=t4.b,
|
||||
t5
|
||||
LEFT JOIN
|
||||
(
|
||||
t6,
|
||||
t7
|
||||
LEFT JOIN
|
||||
t8
|
||||
ON t7.b=t8.b AND t6.b < 10
|
||||
)
|
||||
ON t6.b >= 2 AND t5.b=t7.b
|
||||
)
|
||||
ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
|
||||
(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
|
||||
(t1.a != 2),
|
||||
t9
|
||||
WHERE t0.a=1 AND
|
||||
t0.b=t1.b AND
|
||||
(t2.a >= 4 OR t2.c IS NULL) AND
|
||||
(t3.a < 5 OR t3.c IS NULL) AND
|
||||
(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
|
||||
(t5.a >=2 OR t5.c IS NULL) AND
|
||||
(t6.a >=4 OR t6.c IS NULL) AND
|
||||
(t7.a <= 2 OR t7.c IS NULL) AND
|
||||
(t8.a < 1 OR t8.c IS NULL) AND
|
||||
(t8.b=t9.b OR t8.c IS NULL) AND
|
||||
(t9.a=1);
|
||||
|
||||
CREATE INDEX idx_b ON t1(b);
|
||||
CREATE INDEX idx_a ON t0(a);
|
||||
|
||||
EXPLAIN
|
||||
SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
|
||||
t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
|
||||
FROM t0,t1
|
||||
LEFT JOIN
|
||||
(
|
||||
t2
|
||||
LEFT JOIN
|
||||
(t3, t4)
|
||||
ON t3.a=1 AND t2.b=t4.b,
|
||||
t5
|
||||
LEFT JOIN
|
||||
(
|
||||
t6,
|
||||
t7
|
||||
LEFT JOIN
|
||||
t8
|
||||
ON t7.b=t8.b AND t6.b < 10
|
||||
)
|
||||
ON t6.b >= 2 AND t5.b=t7.b
|
||||
)
|
||||
ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
|
||||
(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
|
||||
(t1.a != 2),
|
||||
t9
|
||||
WHERE t0.a=1 AND
|
||||
t0.b=t1.b AND
|
||||
(t2.a >= 4 OR t2.c IS NULL) AND
|
||||
(t3.a < 5 OR t3.c IS NULL) AND
|
||||
(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
|
||||
(t5.a >=2 OR t5.c IS NULL) AND
|
||||
(t6.a >=4 OR t6.c IS NULL) AND
|
||||
(t7.a <= 2 OR t7.c IS NULL) AND
|
||||
(t8.a < 1 OR t8.c IS NULL) AND
|
||||
(t8.b=t9.b OR t8.c IS NULL) AND
|
||||
(t9.a=1);
|
||||
|
||||
SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
|
||||
t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
|
||||
FROM t0,t1
|
||||
LEFT JOIN
|
||||
(
|
||||
t2
|
||||
LEFT JOIN
|
||||
(t3, t4)
|
||||
ON t3.a=1 AND t2.b=t4.b,
|
||||
t5
|
||||
LEFT JOIN
|
||||
(
|
||||
t6,
|
||||
t7
|
||||
LEFT JOIN
|
||||
t8
|
||||
ON t7.b=t8.b AND t6.b < 10
|
||||
)
|
||||
ON t6.b >= 2 AND t5.b=t7.b
|
||||
)
|
||||
ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
|
||||
(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
|
||||
(t1.a != 2),
|
||||
t9
|
||||
WHERE t0.a=1 AND
|
||||
t0.b=t1.b AND
|
||||
(t2.a >= 4 OR t2.c IS NULL) AND
|
||||
(t3.a < 5 OR t3.c IS NULL) AND
|
||||
(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
|
||||
(t5.a >=2 OR t5.c IS NULL) AND
|
||||
(t6.a >=4 OR t6.c IS NULL) AND
|
||||
(t7.a <= 2 OR t7.c IS NULL) AND
|
||||
(t8.a < 1 OR t8.c IS NULL) AND
|
||||
(t8.b=t9.b OR t8.c IS NULL) AND
|
||||
(t9.a=1);
|
||||
|
||||
SELECT t2.a,t2.b
|
||||
FROM t2;
|
||||
|
||||
SELECT t3.a,t3.b
|
||||
FROM t3;
|
||||
|
||||
SELECT t2.a,t2.b,t3.a,t3.b
|
||||
FROM t2 LEFT JOIN t3 ON t2.b=t3.b
|
||||
WHERE t2.a = 4 OR (t2.a > 4 AND t3.a IS NULL);
|
||||
|
||||
SELECT t2.a,t2.b,t3.a,t3.b
|
||||
FROM t2 LEFT JOIN (t3) ON t2.b=t3.b
|
||||
WHERE t2.a = 4 OR (t2.a > 4 AND t3.a IS NULL);
|
||||
|
||||
ALTER TABLE t3
|
||||
CHANGE COLUMN a a1 int,
|
||||
CHANGE COLUMN c c1 int;
|
||||
|
||||
SELECT t2.a,t2.b,t3.a1,t3.b
|
||||
FROM t2 LEFT JOIN t3 ON t2.b=t3.b
|
||||
WHERE t2.a = 4 OR (t2.a > 4 AND t3.a1 IS NULL);
|
||||
|
||||
SELECT t2.a,t2.b,t3.a1,t3.b
|
||||
FROM t2 NATURAL LEFT JOIN t3
|
||||
WHERE t2.a = 4 OR (t2.a > 4 AND t3.a1 IS NULL);
|
||||
|
||||
DROP TABLE t0,t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
@ -214,6 +214,40 @@ public:
|
||||
Item *neg_transformer();
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
The class Item_func_trig_cond is used for guarded predicates
|
||||
which are employed only for internal purposes.
|
||||
A guarded predicates is an object consisting of an a regular or
|
||||
a guarded predicate P and a pointer to a boolean guard variable g.
|
||||
A guarded predicate P/g is evaluated to true if the value of the
|
||||
guard g is false, otherwise it is evaluated to the same value that
|
||||
the predicate P: val(P/g)= g ? val(P):true.
|
||||
Guarded predicates allow us to include predicates into a conjunction
|
||||
conditionally. Currently they are utilized for pushed down predicates
|
||||
in queries with outer join operations.
|
||||
|
||||
In the future, probably, it makes sense to extend this class to
|
||||
the objects consisting of three elements: a predicate P, a pointer
|
||||
to a variable g and a firing value s with following evaluation
|
||||
rule: val(P/g,s)= g==s? val(P) : true. It will allow us to build only
|
||||
one item for the objects of the form P/g1/g2...
|
||||
|
||||
Objects of this class are built only for query execution after
|
||||
the execution plan has been already selected. That's why this
|
||||
class needs only val_int out of generic methods.
|
||||
*/
|
||||
|
||||
class Item_func_trig_cond: public Item_bool_func
|
||||
{
|
||||
bool *trig_var;
|
||||
public:
|
||||
Item_func_trig_cond(Item *a, bool *f) : Item_bool_func(a) { trig_var= f; }
|
||||
longlong val_int() { return *trig_var ? args[0]->val_int() : 1; }
|
||||
enum Functype functype() const { return TRIG_COND_FUNC; };
|
||||
const char *func_name() const { return "trigcond"; };
|
||||
};
|
||||
|
||||
class Item_func_not_all :public Item_func_not
|
||||
{
|
||||
bool abort_on_null;
|
||||
@ -793,7 +827,7 @@ public:
|
||||
}
|
||||
const char *func_name() const { return "isnotnull"; }
|
||||
optimize_type select_optimize() const { return OPTIMIZE_NULL; }
|
||||
table_map not_null_tables() const { return 0; }
|
||||
table_map not_null_tables() const { return used_tables(); }
|
||||
Item *neg_transformer();
|
||||
void print(String *str);
|
||||
};
|
||||
|
@ -47,7 +47,7 @@ public:
|
||||
SP_CONTAINS_FUNC,SP_OVERLAPS_FUNC,
|
||||
SP_STARTPOINT,SP_ENDPOINT,SP_EXTERIORRING,
|
||||
SP_POINTN,SP_GEOMETRYN,SP_INTERIORRINGN,
|
||||
NOT_FUNC, NOT_ALL_FUNC,
|
||||
NOT_FUNC, NOT_ALL_FUNC, TRIG_COND_FUNC,
|
||||
GUSERVAR_FUNC};
|
||||
enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL };
|
||||
enum Type type() const { return FUNC_ITEM; }
|
||||
|
152
sql/sql_base.cc
152
sql/sql_base.cc
@ -2204,80 +2204,110 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
|
||||
thd->where="where clause";
|
||||
if ((*conds)->fix_fields(thd, tables, conds) || (*conds)->check_cols(1))
|
||||
DBUG_RETURN(1);
|
||||
not_null_tables= (*conds)->not_null_tables();
|
||||
}
|
||||
|
||||
/* Check if we are using outer joins */
|
||||
for (TABLE_LIST *table=tables ; table ; table=table->next)
|
||||
{
|
||||
if (table->on_expr)
|
||||
{
|
||||
/* Make a join an a expression */
|
||||
thd->where="on clause";
|
||||
if (table->on_expr->fix_fields(thd, tables, &table->on_expr) ||
|
||||
table->on_expr->check_cols(1))
|
||||
DBUG_RETURN(1);
|
||||
thd->lex->current_select->cond_count++;
|
||||
|
||||
/*
|
||||
If it's a normal join or a LEFT JOIN which can be optimized away
|
||||
add the ON/USING expression to the WHERE
|
||||
*/
|
||||
if (!table->outer_join ||
|
||||
((table->table->map & not_null_tables) &&
|
||||
!(specialflag & SPECIAL_NO_NEW_FUNC)))
|
||||
TABLE_LIST *embedded;
|
||||
TABLE_LIST *embedding= table;
|
||||
do
|
||||
{
|
||||
embedded= embedding;
|
||||
if (embedded->on_expr)
|
||||
{
|
||||
table->outer_join= 0;
|
||||
if (!(*conds=and_conds(*conds, table->on_expr)))
|
||||
/* Make a join an a expression */
|
||||
thd->where="on clause";
|
||||
if (embedded->on_expr->fix_fields(thd, tables, &embedded->on_expr) ||
|
||||
embedded->on_expr->check_cols(1))
|
||||
DBUG_RETURN(1);
|
||||
table->on_expr=0;
|
||||
thd->lex->current_select->cond_count++;
|
||||
}
|
||||
}
|
||||
if (table->natural_join)
|
||||
{
|
||||
/* Make a join of all fields with have the same name */
|
||||
TABLE *t1=table->table;
|
||||
TABLE *t2=table->natural_join->table;
|
||||
Item_cond_and *cond_and=new Item_cond_and();
|
||||
if (!cond_and) // If not out of memory
|
||||
DBUG_RETURN(1);
|
||||
cond_and->top_level_item();
|
||||
|
||||
uint i,j;
|
||||
for (i=0 ; i < t1->fields ; i++)
|
||||
if (embedded->natural_join)
|
||||
{
|
||||
// TODO: This could be optimized to use hashed names if t2 had a hash
|
||||
for (j=0 ; j < t2->fields ; j++)
|
||||
{
|
||||
if (!my_strcasecmp(system_charset_info,
|
||||
t1->field[i]->field_name,
|
||||
t2->field[j]->field_name))
|
||||
/* Make a join of all fields with have the same name */
|
||||
TABLE_LIST *tab1= embedded;
|
||||
TABLE_LIST *tab2= embedded->natural_join;
|
||||
if (!(embedded->outer_join & JOIN_TYPE_RIGHT))
|
||||
{
|
||||
while (tab1->nested_join)
|
||||
{
|
||||
TABLE_LIST *next;
|
||||
List_iterator_fast<TABLE_LIST> it(tab1->nested_join->join_list);
|
||||
tab1= it++;
|
||||
while ((next= it++))
|
||||
tab1= next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (tab1->nested_join)
|
||||
tab1= tab1->nested_join->join_list.head();
|
||||
}
|
||||
if (embedded->outer_join & JOIN_TYPE_RIGHT)
|
||||
{
|
||||
while (tab2->nested_join)
|
||||
{
|
||||
TABLE_LIST *next;
|
||||
List_iterator_fast<TABLE_LIST> it(tab2->nested_join->join_list);
|
||||
tab2= it++;
|
||||
while ((next= it++))
|
||||
tab2= next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (tab2->nested_join)
|
||||
tab2= tab2->nested_join->join_list.head();
|
||||
}
|
||||
TABLE *t1=tab1->table;
|
||||
TABLE *t2=tab2->table;
|
||||
Item_cond_and *cond_and=new Item_cond_and();
|
||||
if (!cond_and) // If not out of memory
|
||||
DBUG_RETURN(1);
|
||||
cond_and->top_level_item();
|
||||
|
||||
uint i,j;
|
||||
for (i=0 ; i < t1->fields ; i++)
|
||||
{
|
||||
// TODO: This could be optimized to use hashed names if t2 had a hash
|
||||
for (j=0 ; j < t2->fields ; j++)
|
||||
{
|
||||
Item_func_eq *tmp=new Item_func_eq(new Item_field(t1->field[i]),
|
||||
new Item_field(t2->field[j]));
|
||||
if (!tmp)
|
||||
DBUG_RETURN(1);
|
||||
tmp->fix_length_and_dec(); // Update cmp_type
|
||||
tmp->const_item_cache=0;
|
||||
/* Mark field used for table cache */
|
||||
t1->field[i]->query_id=t2->field[j]->query_id=thd->query_id;
|
||||
cond_and->list.push_back(tmp);
|
||||
t1->used_keys.intersect(t1->field[i]->part_of_key);
|
||||
t2->used_keys.intersect(t2->field[j]->part_of_key);
|
||||
break;
|
||||
if (!my_strcasecmp(system_charset_info,
|
||||
t1->field[i]->field_name,
|
||||
t2->field[j]->field_name))
|
||||
{
|
||||
Item_func_eq *tmp=new Item_func_eq(new Item_field(t1->field[i]),
|
||||
new Item_field(t2->field[j]));
|
||||
if (!tmp)
|
||||
DBUG_RETURN(1);
|
||||
tmp->fix_length_and_dec(); // Update cmp_type
|
||||
tmp->const_item_cache=0;
|
||||
/* Mark field used for table cache */
|
||||
t1->field[i]->query_id=t2->field[j]->query_id=thd->query_id;
|
||||
cond_and->list.push_back(tmp);
|
||||
t1->used_keys.intersect(t1->field[i]->part_of_key);
|
||||
t2->used_keys.intersect(t2->field[j]->part_of_key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cond_and->used_tables_cache= t1->map | t2->map;
|
||||
thd->lex->current_select->cond_count+= cond_and->list.elements;
|
||||
COND *on_expr= cond_and;
|
||||
on_expr->fix_fields(thd, 0, &on_expr);
|
||||
if (!embedded->outer_join) // Not left join
|
||||
{
|
||||
if (!(*conds=and_conds(*conds, on_expr)))
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
else
|
||||
embedded->on_expr=and_conds(embedded->on_expr,on_expr);
|
||||
}
|
||||
cond_and->used_tables_cache= t1->map | t2->map;
|
||||
thd->lex->current_select->cond_count+= cond_and->list.elements;
|
||||
if (!table->outer_join) // Not left join
|
||||
{
|
||||
if (!(*conds=and_conds(*conds, cond_and)))
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
else
|
||||
table->on_expr=and_conds(table->on_expr,cond_and);
|
||||
embedding= embedded->embedding;
|
||||
}
|
||||
while (embedding &&
|
||||
embedding->nested_join->join_list.head() == embedded);
|
||||
}
|
||||
DBUG_RETURN(test(thd->net.report_error));
|
||||
}
|
||||
|
@ -1014,6 +1014,9 @@ void st_select_lex::init_query()
|
||||
{
|
||||
st_select_lex_node::init_query();
|
||||
table_list.empty();
|
||||
top_join_list.empty();
|
||||
join_list= &top_join_list;
|
||||
embedding= 0;
|
||||
item_list.empty();
|
||||
join= 0;
|
||||
where= 0;
|
||||
|
@ -400,7 +400,10 @@ public:
|
||||
List<Item_func_match> *ftfunc_list;
|
||||
List<Item_func_match> ftfunc_list_alloc;
|
||||
JOIN *join; /* after JOIN::prepare it is pointer to corresponding JOIN */
|
||||
const char *type; /* type of select for EXPLAIN */
|
||||
List<TABLE_LIST> top_join_list; /* join list of the top level */
|
||||
List<TABLE_LIST> *join_list; /* list for the currently parsed join */
|
||||
TABLE_LIST *embedding; /* table embedding to the above list */
|
||||
const char *type; /* type of select for EXPLAIN */
|
||||
|
||||
SQL_LIST order_list; /* ORDER clause */
|
||||
List<List_item> expr_list;
|
||||
@ -488,6 +491,12 @@ public:
|
||||
List<String> *ignore_index= 0,
|
||||
LEX_STRING *option= 0);
|
||||
TABLE_LIST* get_table_list();
|
||||
bool init_nested_join(THD *thd);
|
||||
TABLE_LIST *end_nested_join(THD *thd);
|
||||
TABLE_LIST *nest_last_join(THD *thd);
|
||||
void save_names_for_using_list(TABLE_LIST *tab1, TABLE_LIST *tab2);
|
||||
void add_joined_table(TABLE_LIST *table);
|
||||
TABLE_LIST *convert_right_join();
|
||||
List<Item>* get_item_list();
|
||||
List<String>* get_use_index();
|
||||
List<String>* get_ignore_index();
|
||||
|
232
sql/sql_parse.cc
232
sql/sql_parse.cc
@ -4686,6 +4686,238 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Initialize a new table list for a nested join
|
||||
|
||||
SYNOPSIS
|
||||
init_table_list()
|
||||
thd current thread
|
||||
|
||||
DESCRIPTION
|
||||
The function initializes a structure of the TABLE_LIST type
|
||||
for a nested join. It sets up its nested join list as empty.
|
||||
The created structure is added to the front of the current
|
||||
join list in the st_select_lex object. Then the function
|
||||
changes the current nest level for joins to refer to the newly
|
||||
created empty list after having saved the info on the old level
|
||||
in the initialized structure.
|
||||
|
||||
RETURN VALUE
|
||||
0, if success
|
||||
1, otherwise
|
||||
*/
|
||||
|
||||
bool st_select_lex::init_nested_join(THD *thd)
|
||||
{
|
||||
TABLE_LIST *ptr;
|
||||
NESTED_JOIN *nested_join;
|
||||
DBUG_ENTER("init_nested_join");
|
||||
|
||||
if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))) ||
|
||||
!(nested_join= ptr->nested_join=
|
||||
(NESTED_JOIN *) thd->calloc(sizeof(NESTED_JOIN))))
|
||||
DBUG_RETURN(1);
|
||||
join_list->push_front(ptr);
|
||||
ptr->embedding= embedding;
|
||||
ptr->join_list= join_list;
|
||||
embedding= ptr;
|
||||
join_list= &nested_join->join_list;
|
||||
join_list->empty();
|
||||
nested_join->used_tables= nested_join->not_null_tables= (table_map) 0;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
End a nested join table list
|
||||
|
||||
SYNOPSIS
|
||||
end_nested_join()
|
||||
thd current thread
|
||||
|
||||
DESCRIPTION
|
||||
The function returns to the previous join nest level.
|
||||
If the current level contains only one member, the function
|
||||
moves it one level up, eliminating the nest.
|
||||
|
||||
RETURN VALUE
|
||||
Pointer to TABLE_LIST element added to the total table list, if success
|
||||
0, otherwise
|
||||
*/
|
||||
|
||||
TABLE_LIST *st_select_lex::end_nested_join(THD *thd)
|
||||
{
|
||||
TABLE_LIST *ptr;
|
||||
DBUG_ENTER("end_nested_join");
|
||||
ptr= embedding;
|
||||
join_list= ptr->join_list;
|
||||
embedding= ptr->embedding;
|
||||
NESTED_JOIN *nested_join= ptr->nested_join;
|
||||
if (nested_join->join_list.elements == 1)
|
||||
{
|
||||
TABLE_LIST *embedded= nested_join->join_list.head();
|
||||
join_list->pop();
|
||||
embedded->join_list= join_list;
|
||||
embedded->embedding= embedding;
|
||||
join_list->push_front(embedded);
|
||||
ptr= embedded;
|
||||
}
|
||||
DBUG_RETURN(ptr);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Nest last join operation
|
||||
|
||||
SYNOPSIS
|
||||
nest_last_join()
|
||||
thd current thread
|
||||
|
||||
DESCRIPTION
|
||||
The function nest last join operation as if it was enclosed in braces.
|
||||
|
||||
RETURN VALUE
|
||||
Pointer to TABLE_LIST element created for the new nested join, if success
|
||||
0, otherwise
|
||||
*/
|
||||
|
||||
TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
|
||||
{
|
||||
TABLE_LIST *ptr;
|
||||
NESTED_JOIN *nested_join;
|
||||
DBUG_ENTER("nest_last_join");
|
||||
|
||||
if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))) ||
|
||||
!(nested_join= ptr->nested_join=
|
||||
(NESTED_JOIN *) thd->calloc(sizeof(NESTED_JOIN))))
|
||||
DBUG_RETURN(0);
|
||||
ptr->embedding= embedding;
|
||||
ptr->join_list= join_list;
|
||||
List<TABLE_LIST> *embedded_list= &nested_join->join_list;
|
||||
embedded_list->empty();
|
||||
for (int i=0; i < 2; i++)
|
||||
{
|
||||
TABLE_LIST *table= join_list->pop();
|
||||
table->join_list= embedded_list;
|
||||
table->embedding= ptr;
|
||||
embedded_list->push_back(table);
|
||||
}
|
||||
join_list->push_front(ptr);
|
||||
nested_join->used_tables= nested_join->not_null_tables= (table_map) 0;
|
||||
DBUG_RETURN(ptr);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Save names for a join with using clase
|
||||
|
||||
SYNOPSIS
|
||||
save_names_for_using_list
|
||||
tab1 left table in join
|
||||
tab2 right table in join
|
||||
|
||||
DESCRIPTION
|
||||
The function saves the full names of the tables in st_select_lex
|
||||
to be able to build later an on expression to replace the using clause.
|
||||
|
||||
RETURN VALUE
|
||||
None
|
||||
*/
|
||||
|
||||
void st_select_lex::save_names_for_using_list(TABLE_LIST *tab1,
|
||||
TABLE_LIST *tab2)
|
||||
{
|
||||
while (tab1->nested_join)
|
||||
{
|
||||
tab1= tab1->nested_join->join_list.head();
|
||||
}
|
||||
db1= tab1->db;
|
||||
table1= tab1->alias;
|
||||
while (tab2->nested_join)
|
||||
{
|
||||
TABLE_LIST *next;
|
||||
List_iterator_fast<TABLE_LIST> it(tab2->nested_join->join_list);
|
||||
tab2= it++;
|
||||
while ((next= it++))
|
||||
tab2= next;
|
||||
}
|
||||
db2= tab2->db;
|
||||
table2= tab2->alias;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Add a table to the current join list
|
||||
|
||||
SYNOPSIS
|
||||
add_joined_table()
|
||||
table the table to add
|
||||
|
||||
DESCRIPTION
|
||||
The function puts a table in front of the current join list
|
||||
of st_select_lex object.
|
||||
Thus, joined tables are put into this list in the reverse order
|
||||
(the most outer join operation follows first).
|
||||
|
||||
RETURN VALUE
|
||||
None
|
||||
*/
|
||||
|
||||
void st_select_lex::add_joined_table(TABLE_LIST *table)
|
||||
{
|
||||
DBUG_ENTER("add_joined_table");
|
||||
join_list->push_front(table);
|
||||
table->join_list= join_list;
|
||||
table->embedding= embedding;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Convert a right join into equivalent left join
|
||||
|
||||
SYNOPSIS
|
||||
convert_right_join()
|
||||
thd current thread
|
||||
|
||||
DESCRIPTION
|
||||
The function takes the current join list t[0],t[1] ... and
|
||||
effectively converts it into the list t[1],t[0] ...
|
||||
Although the outer_join flag for the new nested table contains
|
||||
JOIN_TYPE_RIGHT, it will be handled as the inner table of a left join
|
||||
operation.
|
||||
|
||||
EXAMPLES
|
||||
SELECT * FROM t1 RIGHT JOIN t2 ON on_expr =>
|
||||
SELECT * FROM t2 LEFT JOIN t1 ON on_expr
|
||||
|
||||
SELECT * FROM t1,t2 RIGHT JOIN t3 ON on_expr =>
|
||||
SELECT * FROM t1,t3 LEFT JOIN t2 ON on_expr
|
||||
|
||||
SELECT * FROM t1,t2 RIGHT JOIN (t3,t4) ON on_expr =>
|
||||
SELECT * FROM t1,(t3,t4) LEFT JOIN t2 ON on_expr
|
||||
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON on_expr1 RIGHT JOIN t3 ON on_expr2 =>
|
||||
SELECT * FROM t3 LEFT JOIN (t1 LEFT JOIN t2 ON on_expr2) ON on_expr1
|
||||
|
||||
RETURN
|
||||
Pointer to the table representing the inner table, if success
|
||||
0, otherwise
|
||||
*/
|
||||
|
||||
TABLE_LIST *st_select_lex::convert_right_join()
|
||||
{
|
||||
TABLE_LIST *tab2= join_list->pop();
|
||||
TABLE_LIST *tab1= join_list->pop();
|
||||
DBUG_ENTER("convert_right_join");
|
||||
|
||||
join_list->push_front(tab2);
|
||||
join_list->push_front(tab1);
|
||||
tab1->outer_join|= JOIN_TYPE_RIGHT;
|
||||
|
||||
DBUG_RETURN(tab1);
|
||||
}
|
||||
|
||||
/*
|
||||
Set lock for all tables in current select level
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -73,7 +73,6 @@ typedef struct st_join_cache {
|
||||
/*
|
||||
** The structs which holds the join connections and join states
|
||||
*/
|
||||
|
||||
enum join_type { JT_UNKNOWN,JT_SYSTEM,JT_CONST,JT_EQ_REF,JT_REF,JT_MAYBE_REF,
|
||||
JT_ALL, JT_RANGE, JT_NEXT, JT_FT, JT_REF_OR_NULL,
|
||||
JT_UNIQUE_SUBQUERY, JT_INDEX_SUBQUERY, JT_INDEX_MERGE};
|
||||
@ -86,7 +85,13 @@ typedef struct st_join_table {
|
||||
SQL_SELECT *select;
|
||||
COND *select_cond;
|
||||
QUICK_SELECT_I *quick;
|
||||
Item *on_expr;
|
||||
Item *on_expr; /* associated on expression */
|
||||
st_join_table *first_inner; /* first inner table for including outerjoin */
|
||||
bool found; /* true after all matches or null complement */
|
||||
bool not_null_compl;/* true before null complement is added */
|
||||
st_join_table *last_inner; /* last table table for embedding outer join */
|
||||
st_join_table *first_upper; /* first inner table for embedding outer join */
|
||||
st_join_table *first_unmatched; /* used for optimization purposes only */
|
||||
const char *info;
|
||||
byte *null_ref_key;
|
||||
int (*read_first_record)(struct st_join_table *tab);
|
||||
@ -196,8 +201,10 @@ class JOIN :public Sql_alloc
|
||||
ORDER *order, *group_list, *proc_param; //hold parameters of mysql_select
|
||||
COND *conds; // ---"---
|
||||
Item *conds_history; // store WHERE for explain
|
||||
TABLE_LIST *tables_list; //hold 'tables' parameter of mysql_selec
|
||||
TABLE_LIST *tables_list; //hold 'tables' parameter of mysql_select
|
||||
List<TABLE_LIST> *join_list; // list of joined tables in reverse order
|
||||
SQL_SELECT *select; //created in optimisation phase
|
||||
JOIN_TAB *return_tab; //used only for outer joins
|
||||
Item **ref_pointer_array; //used pointer reference for this select
|
||||
// Copy of above to be used with different lists
|
||||
Item **items0, **items1, **items2, **items3, **current_ref_pointer_array;
|
||||
@ -221,6 +228,7 @@ class JOIN :public Sql_alloc
|
||||
table= 0;
|
||||
tables= 0;
|
||||
const_tables= 0;
|
||||
join_list= 0;
|
||||
sort_and_group= 0;
|
||||
first_record= 0;
|
||||
do_send_rows= 1;
|
||||
@ -251,6 +259,7 @@ class JOIN :public Sql_alloc
|
||||
fields_list= fields_arg;
|
||||
error= 0;
|
||||
select= 0;
|
||||
return_tab= 0;
|
||||
ref_pointer_array= items0= items1= items2= items3= 0;
|
||||
ref_pointer_array_size= 0;
|
||||
zero_result_cause= 0;
|
||||
|
@ -698,6 +698,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
||||
|
||||
%type <table_list>
|
||||
join_table_list join_table
|
||||
table_factor table_ref
|
||||
|
||||
%type <udf>
|
||||
UDF_CHAR_FUNC UDF_FLOAT_FUNC UDF_INT_FUNC
|
||||
@ -4192,59 +4193,80 @@ when_list2:
|
||||
sel->when_list.head()->push_back($5);
|
||||
};
|
||||
|
||||
table_ref:
|
||||
table_factor { $$=$1; }
|
||||
| join_table { $$=$1; }
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
if (!($$= lex->current_select->nest_last_join(lex->thd)))
|
||||
YYABORT;
|
||||
}
|
||||
;
|
||||
|
||||
join_table_list:
|
||||
'(' join_table_list ')' { $$=$2; }
|
||||
| join_table { $$=$1; }
|
||||
| join_table_list ',' join_table_list { $$=$3; }
|
||||
| join_table_list normal_join join_table_list { $$=$3; }
|
||||
| join_table_list STRAIGHT_JOIN join_table_list
|
||||
{ $$=$3 ; $1->next->straight=1; }
|
||||
| join_table_list normal_join join_table_list ON expr
|
||||
table_ref { $$=$1; }
|
||||
| join_table_list ',' table_ref { $$=$3; }
|
||||
;
|
||||
|
||||
join_table:
|
||||
table_ref normal_join table_ref { $$=$3; }
|
||||
| table_ref STRAIGHT_JOIN table_factor
|
||||
{ $3->straight=1; $$=$3 ; }
|
||||
| table_ref normal_join table_ref ON expr
|
||||
{ add_join_on($3,$5); $$=$3; }
|
||||
| join_table_list normal_join join_table_list
|
||||
| table_ref normal_join table_ref
|
||||
USING
|
||||
{
|
||||
SELECT_LEX *sel= Select;
|
||||
sel->db1=$1->db; sel->table1=$1->alias;
|
||||
sel->db2=$3->db; sel->table2=$3->alias;
|
||||
sel->save_names_for_using_list($1, $3);
|
||||
}
|
||||
'(' using_list ')'
|
||||
{ add_join_on($3,$7); $$=$3; }
|
||||
|
||||
| join_table_list LEFT opt_outer JOIN_SYM join_table_list ON expr
|
||||
| table_ref LEFT opt_outer JOIN_SYM table_ref ON expr
|
||||
{ add_join_on($5,$7); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; }
|
||||
| join_table_list LEFT opt_outer JOIN_SYM join_table_list
|
||||
| table_ref LEFT opt_outer JOIN_SYM table_ref
|
||||
{
|
||||
SELECT_LEX *sel= Select;
|
||||
sel->db1=$1->db; sel->table1=$1->alias;
|
||||
sel->db2=$5->db; sel->table2=$5->alias;
|
||||
sel->save_names_for_using_list($1, $5);
|
||||
}
|
||||
USING '(' using_list ')'
|
||||
{ add_join_on($5,$9); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; }
|
||||
| join_table_list NATURAL LEFT opt_outer JOIN_SYM join_table_list
|
||||
| table_ref NATURAL LEFT opt_outer JOIN_SYM table_factor
|
||||
{
|
||||
add_join_natural($1,$1->next);
|
||||
$1->next->outer_join|=JOIN_TYPE_LEFT;
|
||||
add_join_natural($1,$6);
|
||||
$6->outer_join|=JOIN_TYPE_LEFT;
|
||||
$$=$6;
|
||||
}
|
||||
| join_table_list RIGHT opt_outer JOIN_SYM join_table_list ON expr
|
||||
{ add_join_on($1,$7); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$5; }
|
||||
| join_table_list RIGHT opt_outer JOIN_SYM join_table_list
|
||||
| table_ref RIGHT opt_outer JOIN_SYM table_ref ON expr
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
if (!($$= lex->current_select->convert_right_join()))
|
||||
YYABORT;
|
||||
add_join_on($$, $7);
|
||||
}
|
||||
| table_ref RIGHT opt_outer JOIN_SYM table_ref
|
||||
{
|
||||
SELECT_LEX *sel= Select;
|
||||
sel->db1=$1->db; sel->table1=$1->alias;
|
||||
sel->db2=$5->db; sel->table2=$5->alias;
|
||||
sel->save_names_for_using_list($1, $5);
|
||||
}
|
||||
USING '(' using_list ')'
|
||||
{ add_join_on($1,$9); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$5; }
|
||||
| join_table_list NATURAL RIGHT opt_outer JOIN_SYM join_table_list
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
if (!($$= lex->current_select->convert_right_join()))
|
||||
YYABORT;
|
||||
add_join_on($$, $9);
|
||||
}
|
||||
| table_ref NATURAL RIGHT opt_outer JOIN_SYM table_factor
|
||||
{
|
||||
add_join_natural($1->next,$1);
|
||||
$1->outer_join|=JOIN_TYPE_RIGHT;
|
||||
$$=$6;
|
||||
add_join_natural($6,$1);
|
||||
LEX *lex= Lex;
|
||||
if (!($$= lex->current_select->convert_right_join()))
|
||||
YYABORT;
|
||||
}
|
||||
| join_table_list NATURAL JOIN_SYM join_table_list
|
||||
{ add_join_natural($1,$1->next); $$=$4; };
|
||||
| table_ref NATURAL JOIN_SYM table_factor
|
||||
{ add_join_natural($1,$4); $$=$4; };
|
||||
|
||||
|
||||
normal_join:
|
||||
JOIN_SYM {}
|
||||
@ -4252,7 +4274,7 @@ normal_join:
|
||||
| CROSS JOIN_SYM {}
|
||||
;
|
||||
|
||||
join_table:
|
||||
table_factor:
|
||||
{
|
||||
SELECT_LEX *sel= Select;
|
||||
sel->use_index_ptr=sel->ignore_index_ptr=0;
|
||||
@ -4268,8 +4290,21 @@ join_table:
|
||||
sel->get_use_index(),
|
||||
sel->get_ignore_index())))
|
||||
YYABORT;
|
||||
sel->add_joined_table($$);
|
||||
}
|
||||
| '{' ident join_table LEFT OUTER JOIN_SYM join_table ON expr '}'
|
||||
| '('
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
if (lex->current_select->init_nested_join(lex->thd))
|
||||
YYABORT;
|
||||
}
|
||||
join_table_list ')'
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
if (!($$= lex->current_select->end_nested_join(lex->thd)))
|
||||
YYABORT;
|
||||
}
|
||||
| '{' ident table_ref LEFT OUTER JOIN_SYM table_ref ON expr '}'
|
||||
{ add_join_on($7,$9); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; }
|
||||
| '(' SELECT_SYM select_derived ')' opt_table_alias
|
||||
{
|
||||
@ -4289,6 +4324,7 @@ join_table:
|
||||
(List<String> *)0)))
|
||||
|
||||
YYABORT;
|
||||
lex->current_select->add_joined_table($$);
|
||||
};
|
||||
|
||||
select_derived:
|
||||
|
29
sql/table.h
29
sql/table.h
@ -143,12 +143,8 @@ struct st_table {
|
||||
uint quick_key_parts[MAX_KEY];
|
||||
key_part_map const_key_parts[MAX_KEY];
|
||||
ulong query_id;
|
||||
|
||||
union /* Temporary variables */
|
||||
{
|
||||
uint temp_pool_slot; /* Used by intern temp tables */
|
||||
struct st_table_list *pos_in_table_list;
|
||||
};
|
||||
uint temp_pool_slot; /* Used by intern temp tables */
|
||||
struct st_table_list *pos_in_table_list;/* Element referring to this table */
|
||||
/* number of select if it is derived table */
|
||||
uint derived_select_number;
|
||||
THD *in_use; /* Which thread uses this */
|
||||
@ -178,10 +174,24 @@ typedef struct st_table_list
|
||||
uint32 db_length, real_name_length;
|
||||
bool straight; /* optimize with prev table */
|
||||
bool updating; /* for replicate-do/ignore table */
|
||||
bool force_index; /* Prefer index over table scan */
|
||||
bool ignore_leaves; /* Preload only non-leaf nodes */
|
||||
bool force_index; /* prefer index over table scan */
|
||||
bool ignore_leaves; /* preload only non-leaf nodes */
|
||||
table_map dep_tables; /* tables the table depends on */
|
||||
table_map on_expr_dep_tables; /* tables on expression depends on */
|
||||
struct st_nested_join *nested_join; /* if the element is a nested join */
|
||||
st_table_list *embedding; /* nested join containing the table */
|
||||
List<struct st_table_list> *join_list;/* join list the table belongs to */
|
||||
} TABLE_LIST;
|
||||
|
||||
typedef struct st_nested_join
|
||||
{
|
||||
List<TABLE_LIST> join_list; /* list of elements in the nested join */
|
||||
table_map used_tables; /* bitmap of tables in the nested join */
|
||||
table_map not_null_tables; /* tables that rejects nulls */
|
||||
struct st_join_table *first_nested;/* the first nested table in the plan */
|
||||
uint counter; /* to count tables in the nested join */
|
||||
} NESTED_JOIN;
|
||||
|
||||
typedef struct st_changed_table_list
|
||||
{
|
||||
struct st_changed_table_list *next;
|
||||
@ -189,8 +199,7 @@ typedef struct st_changed_table_list
|
||||
uint32 key_length;
|
||||
} CHANGED_TABLE_LIST;
|
||||
|
||||
typedef struct st_open_table_list
|
||||
{
|
||||
typedef struct st_open_table_list{
|
||||
struct st_open_table_list *next;
|
||||
char *db,*table;
|
||||
uint32 in_use,locked;
|
||||
|
Loading…
x
Reference in New Issue
Block a user