Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
MariaDB
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
64d46dfe
Commit
64d46dfe
authored
Jun 25, 2004
by
igor@rurik.mysql.com
Browse files
Options
Browse Files
Download
Plain Diff
After merge fix
parents
f874071a
c5b289c5
Changes
13
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
3661 additions
and
2300 deletions
+3661
-2300
mysql-test/r/join_nested.result
mysql-test/r/join_nested.result
+1161
-0
mysql-test/r/join_outer.result
mysql-test/r/join_outer.result
+1
-7
mysql-test/r/select.result
mysql-test/r/select.result
+4
-35
mysql-test/t/join_nested.test
mysql-test/t/join_nested.test
+693
-0
sql/item_cmpfunc.h
sql/item_cmpfunc.h
+35
-1
sql/item_func.h
sql/item_func.h
+2
-1
sql/sql_base.cc
sql/sql_base.cc
+219
-438
sql/sql_lex.cc
sql/sql_lex.cc
+3
-0
sql/sql_lex.h
sql/sql_lex.h
+10
-1
sql/sql_parse.cc
sql/sql_parse.cc
+231
-0
sql/sql_select.cc
sql/sql_select.cc
+1266
-1782
sql/sql_select.h
sql/sql_select.h
+12
-3
sql/table.h
sql/table.h
+24
-32
No files found.
mysql-test/r/join_nested.result
0 → 100644
View file @
64d46dfe
DROP TABLE IF EXISTS t0,t1,t2,t3,t4,t5,t6,t7,t8,t9;
Warnings:
Note 1051 Unknown table 't0'
Note 1051 Unknown table 't1'
Note 1051 Unknown table 't2'
Note 1051 Unknown table 't3'
Note 1051 Unknown table 't4'
Note 1051 Unknown table 't5'
Note 1051 Unknown table 't6'
Note 1051 Unknown table 't7'
Note 1051 Unknown table 't8'
Note 1051 Unknown table '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;
a b
3 3
4 2
5 3
SELECT t3.a,t3.b
FROM t3;
a b
1 2
2 2
SELECT t4.a,t4.b
FROM t4;
a b
3 2
4 2
SELECT t3.a,t3.b,t4.a,t4.b
FROM t3,t4;
a b a b
1 2 3 2
2 2 3 2
1 2 4 2
2 2 4 2
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
FROM t2
LEFT JOIN
(t3, t4)
ON t2.b=t4.b;
a b a b a b
3 3 NULL NULL NULL NULL
4 2 1 2 3 2
4 2 1 2 4 2
4 2 2 2 3 2
4 2 2 2 4 2
5 3 NULL NULL NULL 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;
a b a b a b
3 3 NULL NULL NULL NULL
4 2 1 2 3 2
4 2 1 2 4 2
5 3 NULL NULL NULL NULL
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;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 3
1 SIMPLE t3 ALL NULL NULL NULL NULL 2 Using where
1 SIMPLE t4 ALL NULL NULL NULL NULL 2
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;
a b a b a b
3 3 NULL NULL NULL NULL
4 2 1 2 3 2
4 2 1 2 4 2
5 3 NULL NULL NULL 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;
a b a b a b
3 3 NULL NULL NULL NULL
4 2 2 2 3 2
4 2 2 2 4 2
5 3 NULL NULL NULL NULL
SELECT t5.a,t5.b
FROM t5;
a b
3 1
2 2
3 3
SELECT t3.a,t3.b,t4.a,t4.b,t5.a,t5.b
FROM t3,t4,t5;
a b a b a b
1 2 3 2 3 1
2 2 3 2 3 1
1 2 4 2 3 1
2 2 4 2 3 1
1 2 3 2 2 2
2 2 3 2 2 2
1 2 4 2 2 2
2 2 4 2 2 2
1 2 3 2 3 3
2 2 3 2 3 3
1 2 4 2 3 3
2 2 4 2 3 3
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;
a b a b a b a b
3 3 NULL NULL NULL NULL NULL NULL
4 2 1 2 3 2 3 1
4 2 1 2 3 2 2 2
4 2 1 2 3 2 3 3
4 2 1 2 4 2 3 1
4 2 1 2 4 2 2 2
4 2 1 2 4 2 3 3
4 2 2 2 3 2 3 1
4 2 2 2 3 2 2 2
4 2 2 2 3 2 3 3
4 2 2 2 4 2 3 1
4 2 2 2 4 2 2 2
4 2 2 2 4 2 3 3
5 3 NULL NULL NULL NULL NULL 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;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 3
1 SIMPLE t3 ALL NULL NULL NULL NULL 2 Using where
1 SIMPLE t4 ALL NULL NULL NULL NULL 2
1 SIMPLE t5 ALL NULL NULL NULL NULL 3
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;
a b a b a b a b
3 3 NULL NULL NULL NULL NULL NULL
4 2 2 2 3 2 3 1
4 2 2 2 3 2 2 2
4 2 2 2 3 2 3 3
4 2 2 2 4 2 3 1
4 2 2 2 4 2 2 2
4 2 2 2 4 2 3 3
5 3 NULL NULL NULL NULL NULL 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);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 3
1 SIMPLE t3 ALL NULL NULL NULL NULL 2 Using where
1 SIMPLE t4 ALL NULL NULL NULL NULL 2
1 SIMPLE t5 ALL NULL NULL NULL NULL 3 Using where
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);
a b a b a b a b
3 3 NULL NULL NULL NULL NULL NULL
4 2 2 2 3 2 2 2
4 2 2 2 4 2 2 2
5 3 NULL NULL NULL NULL NULL NULL
SELECT t6.a,t6.b
FROM t6;
a b
3 2
6 2
6 1
SELECT t7.a,t7.b
FROM t7;
a b
1 1
2 2
SELECT t6.a,t6.b,t7.a,t7.b
FROM t6,t7;
a b a b
3 2 1 1
6 2 1 1
6 1 1 1
3 2 2 2
6 2 2 2
6 1 2 2
SELECT t8.a,t8.b
FROM t8;
a b
0 2
1 2
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;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t6 ALL NULL NULL NULL NULL 3
1 SIMPLE t7 ALL NULL NULL NULL NULL 2
1 SIMPLE t8 ALL NULL NULL NULL NULL 2
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;
a b a b a b
3 2 1 1 NULL NULL
6 2 1 1 NULL NULL
6 1 1 1 NULL NULL
3 2 2 2 0 2
3 2 2 2 1 2
6 2 2 2 0 2
6 2 2 2 1 2
6 1 2 2 0 2
6 1 2 2 1 2
SELECT t5.a,t5.b
FROM t5;
a b
3 1
2 2
3 3
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;
a b a b a b a b
3 1 3 2 1 1 NULL NULL
3 1 6 2 1 1 NULL NULL
2 2 3 2 2 2 0 2
2 2 3 2 2 2 1 2
2 2 6 2 2 2 0 2
2 2 6 2 2 2 1 2
3 3 NULL NULL NULL NULL NULL NULL
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);
a b a b a b a b
3 1 3 2 1 1 NULL NULL
3 1 6 2 1 1 NULL NULL
2 2 3 2 2 2 0 2
2 2 6 2 2 2 0 2
3 3 NULL NULL NULL NULL NULL 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;
a b a b a b
3 3 NULL NULL NULL NULL
4 2 1 2 3 2
4 2 1 2 4 2
5 3 NULL NULL NULL NULL
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;
a b a b a b a b a b a b a b
3 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL
3 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL
4 2 1 2 3 2 3 1 3 2 1 1 NULL NULL
4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL
4 2 1 2 4 2 3 1 3 2 1 1 NULL NULL
4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL
5 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL
5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL
3 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2
3 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2
3 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2
3 3 NULL NULL NULL NULL 2 2 6 2 2 2 1 2
4 2 1 2 3 2 2 2 3 2 2 2 0 2
4 2 1 2 3 2 2 2 3 2 2 2 1 2
4 2 1 2 3 2 2 2 6 2 2 2 0 2
4 2 1 2 3 2 2 2 6 2 2 2 1 2
4 2 1 2 4 2 2 2 3 2 2 2 0 2
4 2 1 2 4 2 2 2 3 2 2 2 1 2
4 2 1 2 4 2 2 2 6 2 2 2 0 2
4 2 1 2 4 2 2 2 6 2 2 2 1 2
5 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2
5 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2
5 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2
5 3 NULL NULL NULL NULL 2 2 6 2 2 2 1 2
3 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL
4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL
4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL
5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL
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);
a b a b a b a b a b a b a b
4 2 1 2 3 2 3 1 3 2 1 1 NULL NULL
4 2 1 2 4 2 3 1 3 2 1 1 NULL NULL
5 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL
4 2 1 2 3 2 2 2 3 2 2 2 0 2
4 2 1 2 3 2 2 2 3 2 2 2 1 2
4 2 1 2 4 2 2 2 3 2 2 2 0 2
4 2 1 2 4 2 2 2 3 2 2 2 1 2
5 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2
5 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2
4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL
4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL
5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL
SELECT t1.a,t1.b
FROM t1;
a b
1 3
2 2
3 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);
a b a b a b a b a b a b a b a b
1 3 3 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL
1 3 3 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL
1 3 3 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2
1 3 3 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2
1 3 3 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2
1 3 3 3 NULL NULL NULL NULL 2 2 6 2 2 2 1 2
1 3 3 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL
1 3 4 2 1 2 3 2 3 1 3 2 1 1 NULL NULL
1 3 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL
1 3 4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL
1 3 4 2 1 2 4 2 3 1 3 2 1 1 NULL NULL
1 3 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL
1 3 4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL
1 3 5 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL
1 3 5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL
1 3 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2
1 3 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2
1 3 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2
1 3 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 1 2
1 3 5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL
2 2 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
3 2 3 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL
3 2 3 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL
3 2 3 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2
3 2 3 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2
3 2 3 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2
3 2 3 3 NULL NULL NULL NULL 2 2 6 2 2 2 1 2
3 2 3 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL
3 2 4 2 1 2 3 2 3 1 3 2 1 1 NULL NULL
3 2 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL
3 2 4 2 1 2 3 2 2 2 3 2 2 2 0 2
3 2 4 2 1 2 3 2 2 2 3 2 2 2 1 2
3 2 4 2 1 2 3 2 2 2 6 2 2 2 0 2
3 2 4 2 1 2 3 2 2 2 6 2 2 2 1 2
3 2 4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL
3 2 4 2 1 2 4 2 3 1 3 2 1 1 NULL NULL
3 2 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL
3 2 4 2 1 2 4 2 2 2 3 2 2 2 0 2
3 2 4 2 1 2 4 2 2 2 3 2 2 2 1 2
3 2 4 2 1 2 4 2 2 2 6 2 2 2 0 2
3 2 4 2 1 2 4 2 2 2 6 2 2 2 1 2
3 2 4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL
3 2 5 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL
3 2 5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL
3 2 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2
3 2 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2
3 2 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2
3 2 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 1 2
3 2 5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL
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);
a b a b a b a b a b a b a b a b
1 3 4 2 1 2 3 2 3 1 3 2 1 1 NULL NULL
1 3 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL
1 3 4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL
1 3 4 2 1 2 4 2 3 1 3 2 1 1 NULL NULL
1 3 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL
1 3 4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL
1 3 5 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL
1 3 5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL
1 3 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2
1 3 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2
1 3 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2
1 3 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 1 2
1 3 5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL
2 2 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
3 2 4 2 1 2 3 2 3 1 3 2 1 1 NULL NULL
3 2 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL
3 2 4 2 1 2 3 2 2 2 3 2 2 2 0 2
3 2 4 2 1 2 3 2 2 2 3 2 2 2 1 2
3 2 4 2 1 2 3 2 2 2 6 2 2 2 0 2
3 2 4 2 1 2 3 2 2 2 6 2 2 2 1 2
3 2 4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL
3 2 4 2 1 2 4 2 3 1 3 2 1 1 NULL NULL
3 2 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL
3 2 4 2 1 2 4 2 2 2 3 2 2 2 0 2
3 2 4 2 1 2 4 2 2 2 3 2 2 2 1 2
3 2 4 2 1 2 4 2 2 2 6 2 2 2 0 2
3 2 4 2 1 2 4 2 2 2 6 2 2 2 1 2
3 2 4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL
3 2 5 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL
3 2 5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL
3 2 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2
3 2 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2
3 2 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2
3 2 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 1 2
3 2 5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL
SELECT t0.a,t0.b
FROM t0;
a b
1 1
1 2
2 2
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);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t0 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t3 ALL NULL NULL NULL NULL 2
1 SIMPLE t4 ALL NULL NULL NULL NULL 2
1 SIMPLE t5 ALL NULL NULL NULL NULL 3
1 SIMPLE t7 ALL NULL NULL NULL NULL 2
1 SIMPLE t6 ALL NULL NULL NULL NULL 3
1 SIMPLE t8 ALL NULL NULL NULL NULL 2
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);
a b a b a b a b a b a b a b a b a b
1 2 2 2 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
1 2 3 2 4 2 1 2 3 2 3 1 3 2 1 1 NULL NULL
1 2 3 2 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL
1 2 3 2 4 2 1 2 3 2 2 2 3 2 2 2 0 2
1 2 3 2 4 2 1 2 3 2 2 2 3 2 2 2 1 2
1 2 3 2 4 2 1 2 3 2 2 2 6 2 2 2 0 2
1 2 3 2 4 2 1 2 3 2 2 2 6 2 2 2 1 2
1 2 3 2 4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL
1 2 3 2 4 2 1 2 4 2 3 1 3 2 1 1 NULL NULL
1 2 3 2 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL
1 2 3 2 4 2 1 2 4 2 2 2 3 2 2 2 0 2
1 2 3 2 4 2 1 2 4 2 2 2 3 2 2 2 1 2
1 2 3 2 4 2 1 2 4 2 2 2 6 2 2 2 0 2
1 2 3 2 4 2 1 2 4 2 2 2 6 2 2 2 1 2
1 2 3 2 4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL
1 2 3 2 5 3 NULL NULL NULL NULL 3 1 3 2 1 1 NULL NULL
1 2 3 2 5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL
1 2 3 2 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 0 2
1 2 3 2 5 3 NULL NULL NULL NULL 2 2 3 2 2 2 1 2
1 2 3 2 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2
1 2 3 2 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 1 2
1 2 3 2 5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL 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);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t0 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t3 ALL NULL NULL NULL NULL 2 Using where
1 SIMPLE t4 ALL NULL NULL NULL NULL 2 Using where
1 SIMPLE t5 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t7 ALL NULL NULL NULL NULL 2 Using where
1 SIMPLE t6 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t8 ALL NULL NULL NULL NULL 2 Using where
1 SIMPLE t9 ALL NULL NULL NULL NULL 3 Using where
SELECT t9.a,t9.b
FROM t9;
a b
1 1
1 2
3 3
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);
a b a b a b a b a b a b a b a b a b a b
1 2 2 2 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1 1
1 2 3 2 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL 1 1
1 2 3 2 4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL 1 1
1 2 3 2 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL 1 1
1 2 3 2 4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL 1 1
1 2 3 2 5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL 1 1
1 2 3 2 5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL 1 1
1 2 2 2 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1 2
1 2 3 2 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL 1 2
1 2 3 2 4 2 1 2 3 2 2 2 6 2 2 2 0 2 1 2
1 2 3 2 4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL 1 2
1 2 3 2 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL 1 2
1 2 3 2 4 2 1 2 4 2 2 2 6 2 2 2 0 2 1 2
1 2 3 2 4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL 1 2
1 2 3 2 5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL 1 2
1 2 3 2 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2 1 2
1 2 3 2 5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL 1 2
SELECT t1.a,t1.b
FROM t1;
a b
1 3
2 2
3 2
SELECT t2.a,t2.b
FROM t2;
a b
3 3
4 2
5 3
SELECT t3.a,t3.b
FROM t3;
a b
1 2
2 2
SELECT t2.a,t2.b,t3.a,t3.b
FROM t2
LEFT JOIN
t3
ON t2.b=t3.b;
a b a b
3 3 NULL NULL
4 2 1 2
4 2 2 2
5 3 NULL NULL
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;
a b a b a b
1 3 3 3 NULL NULL
2 2 3 3 NULL NULL
1 3 4 2 1 2
1 3 4 2 2 2
2 2 4 2 1 2
2 2 4 2 2 2
1 3 5 3 NULL NULL
2 2 5 3 NULL NULL
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;
a b a b a b
1 3 3 3 NULL NULL
2 2 3 3 NULL NULL
1 3 4 2 1 2
1 3 4 2 2 2
2 2 4 2 1 2
2 2 4 2 2 2
1 3 5 3 NULL NULL
2 2 5 3 NULL NULL
SELECT t3.a,t3.b,t4.a,t4.b
FROM t3,t4;
a b a b
1 2 3 2
2 2 3 2
1 2 4 2
2 2 4 2
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;
a b a b a b
3 3 NULL NULL NULL NULL
4 2 1 2 3 2
4 2 1 2 4 2
5 3 NULL NULL NULL NULL
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;
a b a b a b a b
1 3 3 3 NULL NULL NULL NULL
2 2 3 3 NULL NULL NULL NULL
1 3 4 2 1 2 3 2
1 3 4 2 1 2 4 2
2 2 4 2 1 2 3 2
2 2 4 2 1 2 4 2
1 3 5 3 NULL NULL NULL NULL
2 2 5 3 NULL NULL NULL NULL
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;
a b a b a b a b
1 3 3 3 NULL NULL NULL NULL
2 2 3 3 NULL NULL NULL NULL
1 3 4 2 1 2 3 2
1 3 4 2 1 2 4 2
2 2 4 2 1 2 3 2
2 2 4 2 1 2 4 2
1 3 5 3 NULL NULL NULL NULL
2 2 5 3 NULL NULL NULL NULL
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;
a b a b a b a b
1 3 3 3 1 2 NULL NULL
2 2 3 3 1 2 NULL NULL
1 3 3 3 2 2 NULL NULL
2 2 3 3 2 2 NULL NULL
1 3 4 2 1 2 3 2
1 3 4 2 1 2 4 2
2 2 4 2 1 2 3 2
2 2 4 2 1 2 4 2
1 3 4 2 2 2 NULL NULL
2 2 4 2 2 2 NULL NULL
1 3 5 3 1 2 NULL NULL
2 2 5 3 1 2 NULL NULL
1 3 5 3 2 2 NULL NULL
2 2 5 3 2 2 NULL NULL
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;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t3 ALL NULL NULL NULL NULL 2
1 SIMPLE t4 ALL NULL NULL NULL NULL 2
1 SIMPLE t2 ref idx_b idx_b 5 test.t3.b 2
1 SIMPLE t1 ALL NULL NULL NULL NULL 3
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;
a b a b a b
4 2 1 2 3 2
4 2 1 2 3 2
4 2 1 2 3 2
NULL NULL 2 2 3 2
4 2 1 2 4 2
4 2 1 2 4 2
4 2 1 2 4 2
NULL NULL 2 2 4 2
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);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t0 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t3 ALL NULL NULL NULL NULL 2 Using where
1 SIMPLE t4 ALL NULL NULL NULL NULL 2 Using where
1 SIMPLE t5 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t7 ALL NULL NULL NULL NULL 2 Using where
1 SIMPLE t6 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t8 ALL NULL NULL NULL NULL 2 Using where
1 SIMPLE t9 ALL NULL NULL NULL NULL 3 Using where
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);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t0 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t3 ALL NULL NULL NULL NULL 2 Using where
1 SIMPLE t4 ref idx_b idx_b 5 test.t2.b 2 Using where
1 SIMPLE t5 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t7 ALL NULL NULL NULL NULL 2 Using where
1 SIMPLE t6 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t8 ALL NULL NULL NULL NULL 2 Using where
1 SIMPLE t9 ALL NULL NULL NULL NULL 3 Using where
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);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t0 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t3 ALL NULL NULL NULL NULL 2 Using where
1 SIMPLE t4 ref idx_b idx_b 5 test.t2.b 2 Using where
1 SIMPLE t5 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t7 ALL NULL NULL NULL NULL 2 Using where
1 SIMPLE t6 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t8 ref idx_b idx_b 5 test.t7.b 2 Using where
1 SIMPLE t9 ALL NULL NULL NULL NULL 3 Using where
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);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t0 ref idx_a idx_a 5 const 1 Using where
1 SIMPLE t1 ref idx_b idx_b 5 test.t0.b 2 Using where
1 SIMPLE t2 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t3 ALL NULL NULL NULL NULL 2 Using where
1 SIMPLE t4 ref idx_b idx_b 5 test.t2.b 2 Using where
1 SIMPLE t5 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t7 ALL NULL NULL NULL NULL 2 Using where
1 SIMPLE t6 ALL NULL NULL NULL NULL 3 Using where
1 SIMPLE t8 ref idx_b idx_b 5 test.t7.b 2 Using where
1 SIMPLE t9 ALL NULL NULL NULL NULL 3 Using where
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);
a b a b a b a b a b a b a b a b a b a b
1 2 2 2 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1 1
1 2 3 2 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL 1 1
1 2 3 2 4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL 1 1
1 2 3 2 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL 1 1
1 2 3 2 4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL 1 1
1 2 3 2 5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL 1 1
1 2 3 2 5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL 1 1
1 2 2 2 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 1 2
1 2 3 2 4 2 1 2 3 2 3 1 6 2 1 1 NULL NULL 1 2
1 2 3 2 4 2 1 2 3 2 2 2 6 2 2 2 0 2 1 2
1 2 3 2 4 2 1 2 3 2 3 3 NULL NULL NULL NULL NULL NULL 1 2
1 2 3 2 4 2 1 2 4 2 3 1 6 2 1 1 NULL NULL 1 2
1 2 3 2 4 2 1 2 4 2 2 2 6 2 2 2 0 2 1 2
1 2 3 2 4 2 1 2 4 2 3 3 NULL NULL NULL NULL NULL NULL 1 2
1 2 3 2 5 3 NULL NULL NULL NULL 3 1 6 2 1 1 NULL NULL 1 2
1 2 3 2 5 3 NULL NULL NULL NULL 2 2 6 2 2 2 0 2 1 2
1 2 3 2 5 3 NULL NULL NULL NULL 3 3 NULL NULL NULL NULL NULL NULL 1 2
SELECT t2.a,t2.b
FROM t2;
a b
3 3
4 2
5 3
SELECT t3.a,t3.b
FROM t3;
a b
1 2
2 2
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);
a b a b
4 2 1 2
4 2 2 2
5 3 NULL 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);
a b a b
4 2 1 2
4 2 2 2
5 3 NULL 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);
a b a1 b
4 2 1 2
4 2 2 2
5 3 NULL 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);
a b a1 b
4 2 1 2
4 2 2 2
5 3 NULL NULL
DROP TABLE t0,t1,t2,t3,t4,t5,t6,t7,t8,t9;
mysql-test/r/join_outer.result
View file @
64d46dfe
...
@@ -356,13 +356,7 @@ select t1.name, t2.name, t2.id, t2.owner, t3.id from t1 left join t2 on (t1.id =
...
@@ -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
name name id owner id
Antonio Paz El Gato 1 1 1
Antonio Paz El Gato 1 1 1
Antonio Paz Perrito 2 1 1
Antonio Paz Perrito 2 1 1
Lilliana Angelovska NULL NULL NULL 1
NULL NULL NULL NULL 2
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
Thimble Smith Happy 3 3 3
Thimble Smith Happy 3 3 3
drop table t1,t2;
drop table t1,t2;
create table t1 (id int not null, str char(10), index(str));
create table t1 (id int not null, str char(10), index(str));
...
...
mysql-test/r/select.result
View file @
64d46dfe
...
@@ -2157,13 +2157,10 @@ a a a
...
@@ -2157,13 +2157,10 @@ a a a
3 3 3
3 3 3
select * from t1 inner join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1;
select * from t1 inner join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1;
a a a
a a a
1 1 NULL
2 1 1
2 1 1
3 1 1
3 1 1
1 2 NULL
2 2 2
2 2 2
3 2 2
3 2 2
1 3 NULL
2 3 3
2 3 3
3 3 3
3 3 3
select * from (t1 as t2 left join t1 as t3 using (a)) inner join t1 using ( a );
select * from (t1 as t2 left join t1 as t3 using (a)) inner join t1 using ( a );
...
@@ -2174,13 +2171,7 @@ a a 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 );
select * from t1 inner join (t1 as t2 left join t1 as t3 using (a)) using ( a );
a a a
a a a
1 1 1
1 1 1
2 1 NULL
3 1 NULL
1 2 NULL
2 2 2
2 2 2
3 2 NULL
1 3 NULL
2 3 NULL
3 3 3
3 3 3
select * from (t1 as t2 left join t1 as t3 using (a)) left outer join t1 on t1.a>1;
select * from (t1 as t2 left join t1 as t3 using (a)) left outer join t1 on t1.a>1;
a a a
a a a
...
@@ -2192,14 +2183,12 @@ a a a
...
@@ -2192,14 +2183,12 @@ a a a
3 3 3
3 3 3
select * from t1 left outer join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1;
select * from t1 left outer join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1;
a a a
a a a
1
1
NULL
1
NULL
NULL
2 1 1
2 1 1
3 1 1
1 2 NULL
2 2 2
2 2 2
3 2 2
1 3 NULL
2 3 3
2 3 3
3 1 1
3 2 2
3 3 3
3 3 3
select * from (t1 as t2 left join t1 as t3 using (a)) left join t1 using ( a );
select * from (t1 as t2 left join t1 as t3 using (a)) left join t1 using ( a );
a a a
a a a
...
@@ -2209,13 +2198,7 @@ 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 );
select * from t1 left join (t1 as t2 left join t1 as t3 using (a)) using ( a );
a a a
a a a
1 1 1
1 1 1
2 1 NULL
3 1 NULL
1 2 NULL
2 2 2
2 2 2
3 2 NULL
1 3 NULL
2 3 NULL
3 3 3
3 3 3
select * from (t1 as t2 left join t1 as t3 using (a)) natural left join t1;
select * from (t1 as t2 left join t1 as t3 using (a)) natural left join t1;
a a a
a a a
...
@@ -2229,9 +2212,7 @@ a a a
...
@@ -2229,9 +2212,7 @@ a a a
3 3 3
3 3 3
select * from (t1 as t2 left join t1 as t3 using (a)) right join t1 on t1.a>1;
select * from (t1 as t2 left join t1 as t3 using (a)) right join t1 on t1.a>1;
a a a
a a a
1 NULL 1
NULL NULL 1
2 NULL 1
3 NULL 1
1 1 2
1 1 2
2 2 2
2 2 2
3 3 2
3 3 2
...
@@ -2249,13 +2230,7 @@ a a a
...
@@ -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 );
select * from (t1 as t2 left join t1 as t3 using (a)) right outer join t1 using ( a );
a a a
a a a
1 1 1
1 1 1
2 NULL 1
3 NULL 1
1 NULL 2
2 2 2
2 2 2
3 NULL 2
1 NULL 3
2 NULL 3
3 3 3
3 3 3
select * from t1 right outer join (t1 as t2 left join t1 as t3 using (a)) using ( a );
select * from t1 right outer join (t1 as t2 left join t1 as t3 using (a)) using ( a );
a a a
a a a
...
@@ -2265,13 +2240,7 @@ 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;
select * from (t1 as t2 left join t1 as t3 using (a)) natural right join t1;
a a a
a a a
1 1 1
1 1 1
2 NULL 1
3 NULL 1
1 NULL 2
2 2 2
2 2 2
3 NULL 2
1 NULL 3
2 NULL 3
3 3 3
3 3 3
select * from t1 natural right join (t1 as t2 left join t1 as t3 using (a));
select * from t1 natural right join (t1 as t2 left join t1 as t3 using (a));
a a a
a a a
...
...
mysql-test/t/join_nested.test
0 → 100644
View file @
64d46dfe
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
;
sql/item_cmpfunc.h
View file @
64d46dfe
...
@@ -233,6 +233,40 @@ class Item_func_not :public Item_bool_func
...
@@ -233,6 +233,40 @@ class Item_func_not :public Item_bool_func
Item
*
neg_transformer
(
THD
*
thd
);
Item
*
neg_transformer
(
THD
*
thd
);
};
};
/*
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
class
Item_func_not_all
:
public
Item_func_not
{
{
bool
abort_on_null
;
bool
abort_on_null
;
...
@@ -817,7 +851,7 @@ class Item_func_isnotnull :public Item_bool_func
...
@@ -817,7 +851,7 @@ class Item_func_isnotnull :public Item_bool_func
}
}
const
char
*
func_name
()
const
{
return
"isnotnull"
;
}
const
char
*
func_name
()
const
{
return
"isnotnull"
;
}
optimize_type
select_optimize
()
const
{
return
OPTIMIZE_NULL
;
}
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
(
THD
*
thd
);
Item
*
neg_transformer
(
THD
*
thd
);
void
print
(
String
*
str
);
void
print
(
String
*
str
);
CHARSET_INFO
*
compare_collation
()
{
return
args
[
0
]
->
collation
.
collation
;
}
CHARSET_INFO
*
compare_collation
()
{
return
args
[
0
]
->
collation
.
collation
;
}
...
...
sql/item_func.h
View file @
64d46dfe
...
@@ -47,7 +47,8 @@ class Item_func :public Item_result_field
...
@@ -47,7 +47,8 @@ class Item_func :public Item_result_field
SP_CONTAINS_FUNC
,
SP_OVERLAPS_FUNC
,
SP_CONTAINS_FUNC
,
SP_OVERLAPS_FUNC
,
SP_STARTPOINT
,
SP_ENDPOINT
,
SP_EXTERIORRING
,
SP_STARTPOINT
,
SP_ENDPOINT
,
SP_EXTERIORRING
,
SP_POINTN
,
SP_GEOMETRYN
,
SP_INTERIORRINGN
,
SP_POINTN
,
SP_GEOMETRYN
,
SP_INTERIORRINGN
,
NOT_FUNC
,
NOT_ALL_FUNC
,
NOW_FUNC
,
NOT_FUNC
,
NOT_ALL_FUNC
,
NOW_FUNC
,
TRIG_COND_FUNC
,
GUSERVAR_FUNC
};
GUSERVAR_FUNC
};
enum
optimize_type
{
OPTIMIZE_NONE
,
OPTIMIZE_KEY
,
OPTIMIZE_OP
,
OPTIMIZE_NULL
};
enum
optimize_type
{
OPTIMIZE_NONE
,
OPTIMIZE_KEY
,
OPTIMIZE_OP
,
OPTIMIZE_NULL
};
enum
Type
type
()
const
{
return
FUNC_ITEM
;
}
enum
Type
type
()
const
{
return
FUNC_ITEM
;
}
...
...
sql/sql_base.cc
View file @
64d46dfe
...
@@ -46,12 +46,12 @@ extern "C" byte *table_cache_key(const byte *record,uint *length,
...
@@ -46,12 +46,12 @@ extern "C" byte *table_cache_key(const byte *record,uint *length,
return
(
byte
*
)
entry
->
table_cache_key
;
return
(
byte
*
)
entry
->
table_cache_key
;
}
}
bool
table_cache_init
(
void
)
void
table_cache_init
(
void
)
{
{
VOID
(
hash_init
(
&
open_cache
,
&
my_charset_bin
,
table_cache_size
+
16
,
0
,
0
,
table_cache_key
,
(
hash_free_key
)
free_cache_entry
,
0
));
mysql_rm_tmp_tables
();
mysql_rm_tmp_tables
();
return
hash_init
(
&
open_cache
,
&
my_charset_bin
,
table_cache_size
+
16
,
0
,
0
,
table_cache_key
,
(
hash_free_key
)
free_cache_entry
,
0
)
!=
0
;
}
}
void
table_cache_free
(
void
)
void
table_cache_free
(
void
)
...
@@ -156,7 +156,6 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild)
...
@@ -156,7 +156,6 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild)
table_list
.
db
=
(
char
*
)
entry
->
table_cache_key
;
table_list
.
db
=
(
char
*
)
entry
->
table_cache_key
;
table_list
.
real_name
=
entry
->
real_name
;
table_list
.
real_name
=
entry
->
real_name
;
table_list
.
grant
.
privilege
=
0
;
table_list
.
grant
.
privilege
=
0
;
if
(
check_table_access
(
thd
,
SELECT_ACL
|
EXTRA_ACL
,
&
table_list
,
1
))
if
(
check_table_access
(
thd
,
SELECT_ACL
|
EXTRA_ACL
,
&
table_list
,
1
))
continue
;
continue
;
/* need to check if we haven't already listed it */
/* need to check if we haven't already listed it */
...
@@ -285,10 +284,8 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
...
@@ -285,10 +284,8 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
if
(
!
found
)
if
(
!
found
)
if_wait_for_refresh
=
0
;
// Nothing to wait for
if_wait_for_refresh
=
0
;
// Nothing to wait for
}
}
#ifndef EMBEDDED_LIBRARY
if
(
!
tables
)
if
(
!
tables
)
kill_delayed_threads
();
kill_delayed_threads
();
#endif
if
(
if_wait_for_refresh
)
if
(
if_wait_for_refresh
)
{
{
/*
/*
...
@@ -444,7 +441,7 @@ bool close_thread_table(THD *thd, TABLE **table_ptr)
...
@@ -444,7 +441,7 @@ bool close_thread_table(THD *thd, TABLE **table_ptr)
else
else
{
{
// Free memory and reset for next loop
// Free memory and reset for next loop
table
->
file
->
reset
(
);
table
->
file
->
extra
(
HA_EXTRA_RESET
);
}
}
table
->
in_use
=
0
;
table
->
in_use
=
0
;
if
(
unused_tables
)
if
(
unused_tables
)
...
@@ -488,19 +485,13 @@ void close_temporary_tables(THD *thd)
...
@@ -488,19 +485,13 @@ void close_temporary_tables(THD *thd)
return
;
return
;
LINT_INIT
(
end
);
LINT_INIT
(
end
);
query_buf_size
=
50
;
// Enough for DROP ... TABLE
IF EXISTS
query_buf_size
=
50
;
// Enough for DROP ... TABLE
for
(
table
=
thd
->
temporary_tables
;
table
;
table
=
table
->
next
)
for
(
table
=
thd
->
temporary_tables
;
table
;
table
=
table
->
next
)
/*
We are going to add 4 ` around the db/table names, so 1 does not look
enough; indeed it is enough, because table->key_length is greater (by 8,
because of server_id and thread_id) than db||table.
*/
query_buf_size
+=
table
->
key_length
+
1
;
query_buf_size
+=
table
->
key_length
+
1
;
if
((
query
=
alloc_root
(
&
thd
->
mem_root
,
query_buf_size
)))
if
((
query
=
alloc_root
(
&
thd
->
mem_root
,
query_buf_size
)))
// Better add "if exists", in case a RESET MASTER has been done
end
=
strmov
(
query
,
"DROP /*!40005 TEMPORARY */ TABLE "
);
end
=
strmov
(
query
,
"DROP /*!40005 TEMPORARY */ TABLE IF EXISTS "
);
for
(
table
=
thd
->
temporary_tables
;
table
;
table
=
next
)
for
(
table
=
thd
->
temporary_tables
;
table
;
table
=
next
)
{
{
...
@@ -513,8 +504,8 @@ void close_temporary_tables(THD *thd)
...
@@ -513,8 +504,8 @@ void close_temporary_tables(THD *thd)
Here we assume table_cache_key always starts
Here we assume table_cache_key always starts
with \0 terminated db name
with \0 terminated db name
*/
*/
end
=
strxmov
(
end
,
"`"
,
table
->
table_cache_key
,
"`
.`
"
,
end
=
strxmov
(
end
,
"`"
,
table
->
table_cache_key
,
"`"
,
table
->
real_name
,
"`,"
,
NullS
);
".`"
,
table
->
real_name
,
"`,"
,
NullS
);
}
}
next
=
table
->
next
;
next
=
table
->
next
;
close_temporary
(
table
);
close_temporary
(
table
);
...
@@ -524,16 +515,6 @@ void close_temporary_tables(THD *thd)
...
@@ -524,16 +515,6 @@ void close_temporary_tables(THD *thd)
/* The -1 is to remove last ',' */
/* The -1 is to remove last ',' */
thd
->
clear_error
();
thd
->
clear_error
();
Query_log_event
qinfo
(
thd
,
query
,
(
ulong
)(
end
-
query
)
-
1
,
0
);
Query_log_event
qinfo
(
thd
,
query
,
(
ulong
)(
end
-
query
)
-
1
,
0
);
/*
Imagine the thread had created a temp table, then was doing a SELECT, and
the SELECT was killed. Then it's not clever to mark the statement above as
"killed", because it's not really a statement updating data, and there
are 99.99% chances it will succeed on slave.
If a real update (one updating a persistent table) was killed on the
master, then this real update will be logged with error_code=killed,
rightfully causing the slave to stop.
*/
qinfo
.
error_code
=
0
;
mysql_bin_log
.
write
(
&
qinfo
);
mysql_bin_log
.
write
(
&
qinfo
);
}
}
thd
->
temporary_tables
=
0
;
thd
->
temporary_tables
=
0
;
...
@@ -568,7 +549,7 @@ TABLE_LIST * find_table_in_list(TABLE_LIST *table,
...
@@ -568,7 +549,7 @@ TABLE_LIST * find_table_in_list(TABLE_LIST *table,
Find real table in given list.
Find real table in given list.
SYNOPSIS
SYNOPSIS
find_
real_
table_in_list()
find_table_in_list()
table - pointer to table list
table - pointer to table list
db_name - data base name
db_name - data base name
table_name - table name
table_name - table name
...
@@ -827,13 +808,9 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
...
@@ -827,13 +808,9 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
{
{
if
(
table
->
key_length
==
key_length
&&
if
(
table
->
key_length
==
key_length
&&
!
memcmp
(
table
->
table_cache_key
,
key
,
key_length
)
&&
!
memcmp
(
table
->
table_cache_key
,
key
,
key_length
)
&&
!
my_strcasecmp
(
system_charset_info
,
table
->
table_name
,
alias
)
&&
!
my_strcasecmp
(
system_charset_info
,
table
->
table_name
,
alias
))
table
->
query_id
!=
thd
->
query_id
)
{
table
->
query_id
=
thd
->
query_id
;
goto
reset
;
goto
reset
;
}
}
}
my_printf_error
(
ER_TABLE_NOT_LOCKED
,
ER
(
ER_TABLE_NOT_LOCKED
),
MYF
(
0
),
alias
);
my_printf_error
(
ER_TABLE_NOT_LOCKED
,
ER
(
ER_TABLE_NOT_LOCKED
),
MYF
(
0
),
alias
);
DBUG_RETURN
(
0
);
DBUG_RETURN
(
0
);
}
}
...
@@ -940,8 +917,6 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
...
@@ -940,8 +917,6 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
table
->
status
=
STATUS_NO_RECORD
;
table
->
status
=
STATUS_NO_RECORD
;
table
->
keys_in_use_for_query
=
table
->
keys_in_use
;
table
->
keys_in_use_for_query
=
table
->
keys_in_use
;
table
->
used_keys
=
table
->
keys_for_keyread
;
table
->
used_keys
=
table
->
keys_for_keyread
;
if
(
table
->
timestamp_field
)
table
->
timestamp_field
->
set_timestamp_offsets
();
DBUG_ASSERT
(
table
->
key_read
==
0
);
DBUG_ASSERT
(
table
->
key_read
==
0
);
DBUG_RETURN
(
table
);
DBUG_RETURN
(
table
);
}
}
...
@@ -1029,15 +1004,14 @@ bool reopen_table(TABLE *table,bool locked)
...
@@ -1029,15 +1004,14 @@ bool reopen_table(TABLE *table,bool locked)
*
table
=
tmp
;
*
table
=
tmp
;
table
->
file
->
change_table_ptr
(
table
);
table
->
file
->
change_table_ptr
(
table
);
DBUG_ASSERT
(
table
->
table_name
);
for
(
field
=
table
->
field
;
*
field
;
field
++
)
for
(
field
=
table
->
field
;
*
field
;
field
++
)
{
{
(
*
field
)
->
table
=
(
*
field
)
->
orig_table
=
table
;
(
*
field
)
->
table
=
table
;
(
*
field
)
->
table_name
=
table
->
table_name
;
(
*
field
)
->
table_name
=
table
->
table_name
;
}
}
for
(
key
=
0
;
key
<
table
->
keys
;
key
++
)
for
(
key
=
0
;
key
<
table
->
keys
;
key
++
)
for
(
part
=
0
;
part
<
table
->
key_info
[
key
].
usable_key_parts
;
part
++
)
for
(
part
=
0
;
part
<
table
->
key_info
[
key
].
usable_key_parts
;
part
++
)
table
->
key_info
[
key
].
key_part
[
part
].
field
->
table
=
table
;
table
->
key_info
[
key
].
key_part
[
part
].
field
->
table
=
table
;
VOID
(
pthread_cond_broadcast
(
&
COND_refresh
));
VOID
(
pthread_cond_broadcast
(
&
COND_refresh
));
error
=
0
;
error
=
0
;
...
@@ -1318,39 +1292,22 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
...
@@ -1318,39 +1292,22 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
{
{
char
path
[
FN_REFLEN
];
char
path
[
FN_REFLEN
];
int
error
;
int
error
;
uint
discover_retry_count
=
0
;
DBUG_ENTER
(
"open_unireg_entry"
);
DBUG_ENTER
(
"open_unireg_entry"
);
strxmov
(
path
,
mysql_data_home
,
"/"
,
db
,
"/"
,
name
,
NullS
);
strxmov
(
path
,
mysql_data_home
,
"/"
,
db
,
"/"
,
name
,
NullS
);
while
(
openfrm
(
path
,
alias
,
if
(
openfrm
(
path
,
alias
,
(
uint
)
(
HA_OPEN_KEYFILE
|
HA_OPEN_RNDFILE
|
HA_GET_INDEX
|
(
uint
)
(
HA_OPEN_KEYFILE
|
HA_OPEN_RNDFILE
|
HA_GET_INDEX
|
HA_TRY_READ_ONLY
),
HA_TRY_READ_ONLY
),
READ_KEYINFO
|
COMPUTE_TYPES
|
EXTRA_RECORD
,
READ_KEYINFO
|
COMPUTE_TYPES
|
EXTRA_RECORD
,
thd
->
open_options
,
entry
))
thd
->
open_options
,
entry
))
{
{
if
(
!
entry
->
crashed
)
if
(
!
entry
->
crashed
)
{
goto
err
;
// Can't repair the table
/*
Frm file could not be found on disk
Since it does not exist, no one can be using it
LOCK_open has been locked to protect from someone else
trying to discover the table at the same time.
*/
if
(
discover_retry_count
++
!=
0
)
goto
err
;
if
(
create_table_from_handler
(
db
,
name
,
true
)
!=
0
)
goto
err
;
thd
->
clear_error
();
// Clear error message
continue
;
}
// Code below is for repairing a crashed file
TABLE_LIST
table_list
;
TABLE_LIST
table_list
;
bzero
((
char
*
)
&
table_list
,
sizeof
(
table_list
));
// just for safe
table_list
.
db
=
(
char
*
)
db
;
table_list
.
db
=
(
char
*
)
db
;
table_list
.
real_name
=
(
char
*
)
name
;
table_list
.
real_name
=
(
char
*
)
name
;
table_list
.
next
=
0
;
safe_mutex_assert_owner
(
&
LOCK_open
);
safe_mutex_assert_owner
(
&
LOCK_open
);
if
((
error
=
lock_table_name
(
thd
,
&
table_list
)))
if
((
error
=
lock_table_name
(
thd
,
&
table_list
)))
...
@@ -1385,68 +1342,25 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
...
@@ -1385,68 +1342,25 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
error
=
1
;
error
=
1
;
}
}
else
else
{
thd
->
clear_error
();
// Clear error message
thd
->
clear_error
();
// Clear error message
}
pthread_mutex_lock
(
&
LOCK_open
);
pthread_mutex_lock
(
&
LOCK_open
);
unlock_table_name
(
thd
,
&
table_list
);
unlock_table_name
(
thd
,
&
table_list
);
if
(
error
)
if
(
error
)
goto
err
;
goto
err
;
break
;
}
/*
If we are here, there was no fatal error (but error may be still
unitialized).
*/
if
(
unlikely
(
entry
->
file
->
implicit_emptied
))
{
entry
->
file
->
implicit_emptied
=
0
;
if
(
mysql_bin_log
.
is_open
())
{
char
*
query
,
*
end
;
uint
query_buf_size
=
20
+
2
*
NAME_LEN
+
1
;
if
((
query
=
(
char
*
)
my_malloc
(
query_buf_size
,
MYF
(
MY_WME
))))
{
end
=
strxmov
(
strmov
(
query
,
"DELETE FROM `"
),
db
,
"`.`"
,
name
,
"`"
,
NullS
);
Query_log_event
qinfo
(
thd
,
query
,
(
ulong
)(
end
-
query
),
0
);
mysql_bin_log
.
write
(
&
qinfo
);
my_free
(
query
,
MYF
(
0
));
}
else
{
/*
As replication is maybe going to be corrupted, we need to warn the
DBA on top of warning the client (which will automatically be done
because of MYF(MY_WME) in my_malloc() above).
*/
sql_print_error
(
"Error: when opening HEAP table, could not allocate \
memory to write 'DELETE FROM `%s`.`%s`' to the binary log"
,
db
,
name
);
if
(
entry
->
file
)
closefrm
(
entry
);
goto
err
;
}
}
}
}
DBUG_RETURN
(
0
);
DBUG_RETURN
(
0
);
err:
err:
DBUG_RETURN
(
1
);
DBUG_RETURN
(
1
);
}
}
/*
/*****************************************************************************
Open all tables in list
** open all tables in list
*****************************************************************************/
SYNOPSIS
open_tables()
thd - thread handler
start - list of tables
counter - number of opened tables will be return using this parameter
RETURN
0 - OK
-1 - error
*/
int
open_tables
(
THD
*
thd
,
TABLE_LIST
*
start
,
uint
*
counter
)
int
open_tables
(
THD
*
thd
,
TABLE_LIST
*
start
)
{
{
TABLE_LIST
*
tables
;
TABLE_LIST
*
tables
;
bool
refresh
;
bool
refresh
;
...
@@ -1455,19 +1369,11 @@ int open_tables(THD *thd, TABLE_LIST *start, uint *counter)
...
@@ -1455,19 +1369,11 @@ int open_tables(THD *thd, TABLE_LIST *start, uint *counter)
thd
->
current_tablenr
=
0
;
thd
->
current_tablenr
=
0
;
restart:
restart:
*
counter
=
0
;
thd
->
proc_info
=
"Opening tables"
;
thd
->
proc_info
=
"Opening tables"
;
for
(
tables
=
start
;
tables
;
tables
=
tables
->
next
)
for
(
tables
=
start
;
tables
;
tables
=
tables
->
next
)
{
{
/*
Ignore placeholders for derived tables. After derived tables
processing, link to created temporary table will be put here.
*/
if
(
tables
->
derived
)
continue
;
(
*
counter
)
++
;
if
(
!
tables
->
table
&&
if
(
!
tables
->
table
&&
!
(
tables
->
table
=
open_table
(
thd
,
!
(
tables
->
table
=
open_table
(
thd
,
tables
->
db
,
tables
->
db
,
tables
->
real_name
,
tables
->
real_name
,
tables
->
alias
,
&
refresh
)))
tables
->
alias
,
&
refresh
)))
...
@@ -1616,57 +1522,15 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
...
@@ -1616,57 +1522,15 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
/*
/*
Open all tables in list and locks them for read without derived
Open all tables in list and locks them for read.
tables processing.
SYNOPSIS
simple_open_n_lock_tables()
thd - thread handler
tables - list of tables for open&locking
RETURN
0 - ok
-1 - error
NOTE
The lock will automaticly be freed by close_thread_tables()
*/
int
simple_open_n_lock_tables
(
THD
*
thd
,
TABLE_LIST
*
tables
)
{
DBUG_ENTER
(
"simple_open_n_lock_tables"
);
uint
counter
;
if
(
open_tables
(
thd
,
tables
,
&
counter
)
||
lock_tables
(
thd
,
tables
,
counter
))
DBUG_RETURN
(
-
1
);
/* purecov: inspected */
DBUG_RETURN
(
0
);
}
/*
Open all tables in list, locks them and process derived tables
tables processing.
SYNOPSIS
open_and_lock_tables()
thd - thread handler
tables - list of tables for open&locking
RETURN
0 - ok
-1 - error
NOTE
The lock will automaticly be freed by close_thread_tables()
The lock will automaticly be freed by close_thread_tables()
*/
*/
int
open_and_lock_tables
(
THD
*
thd
,
TABLE_LIST
*
tables
)
int
open_and_lock_tables
(
THD
*
thd
,
TABLE_LIST
*
tables
)
{
{
DBUG_ENTER
(
"open_and_lock_tables"
);
if
(
open_tables
(
thd
,
tables
)
||
lock_tables
(
thd
,
tables
))
uint
counter
;
return
-
1
;
/* purecov: inspected */
if
(
open_tables
(
thd
,
tables
,
&
counter
)
||
lock_tables
(
thd
,
tables
,
counter
))
return
0
;
DBUG_RETURN
(
-
1
);
/* purecov: inspected */
fix_tables_pointers
(
thd
->
lex
->
all_selects_list
);
DBUG_RETURN
(
mysql_handle_derived
(
thd
->
lex
));
}
}
...
@@ -1677,7 +1541,6 @@ int open_and_lock_tables(THD *thd, TABLE_LIST *tables)
...
@@ -1677,7 +1541,6 @@ int open_and_lock_tables(THD *thd, TABLE_LIST *tables)
lock_tables()
lock_tables()
thd Thread handler
thd Thread handler
tables Tables to lock
tables Tables to lock
count umber of opened tables
NOTES
NOTES
You can't call lock_tables twice, as this would break the dead-lock-free
You can't call lock_tables twice, as this would break the dead-lock-free
...
@@ -1689,7 +1552,7 @@ int open_and_lock_tables(THD *thd, TABLE_LIST *tables)
...
@@ -1689,7 +1552,7 @@ int open_and_lock_tables(THD *thd, TABLE_LIST *tables)
-1 Error
-1 Error
*/
*/
int
lock_tables
(
THD
*
thd
,
TABLE_LIST
*
tables
,
uint
count
)
int
lock_tables
(
THD
*
thd
,
TABLE_LIST
*
tables
)
{
{
TABLE_LIST
*
table
;
TABLE_LIST
*
table
;
if
(
!
tables
)
if
(
!
tables
)
...
@@ -1698,14 +1561,14 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count)
...
@@ -1698,14 +1561,14 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count)
if
(
!
thd
->
locked_tables
)
if
(
!
thd
->
locked_tables
)
{
{
DBUG_ASSERT
(
thd
->
lock
==
0
);
// You must lock everything at once
DBUG_ASSERT
(
thd
->
lock
==
0
);
// You must lock everything at once
uint
count
=
0
;
for
(
table
=
tables
;
table
;
table
=
table
->
next
)
count
++
;
TABLE
**
start
,
**
ptr
;
TABLE
**
start
,
**
ptr
;
if
(
!
(
ptr
=
start
=
(
TABLE
**
)
sql_alloc
(
sizeof
(
TABLE
*
)
*
count
)))
if
(
!
(
ptr
=
start
=
(
TABLE
**
)
sql_alloc
(
sizeof
(
TABLE
*
)
*
count
)))
return
-
1
;
return
-
1
;
for
(
table
=
tables
;
table
;
table
=
table
->
next
)
for
(
table
=
tables
;
table
;
table
=
table
->
next
)
{
if
(
!
table
->
derived
)
*
(
ptr
++
)
=
table
->
table
;
*
(
ptr
++
)
=
table
->
table
;
}
if
(
!
(
thd
->
lock
=
mysql_lock_tables
(
thd
,
start
,
count
)))
if
(
!
(
thd
->
lock
=
mysql_lock_tables
(
thd
,
start
,
count
)))
return
-
1
;
/* purecov: inspected */
return
-
1
;
/* purecov: inspected */
}
}
...
@@ -1713,8 +1576,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count)
...
@@ -1713,8 +1576,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count)
{
{
for
(
table
=
tables
;
table
;
table
=
table
->
next
)
for
(
table
=
tables
;
table
;
table
=
table
->
next
)
{
{
if
(
!
table
->
derived
&&
if
(
check_lock_and_start_stmt
(
thd
,
table
->
table
,
table
->
lock_type
))
check_lock_and_start_stmt
(
thd
,
table
->
table
,
table
->
lock_type
))
{
{
ha_rollback_stmt
(
thd
);
ha_rollback_stmt
(
thd
);
return
-
1
;
return
-
1
;
...
@@ -1797,11 +1659,7 @@ bool rm_temporary_table(enum db_type base, char *path)
...
@@ -1797,11 +1659,7 @@ bool rm_temporary_table(enum db_type base, char *path)
*
fn_ext
(
path
)
=
'\0'
;
// remove extension
*
fn_ext
(
path
)
=
'\0'
;
// remove extension
handler
*
file
=
get_new_handler
((
TABLE
*
)
0
,
base
);
handler
*
file
=
get_new_handler
((
TABLE
*
)
0
,
base
);
if
(
file
&&
file
->
delete_table
(
path
))
if
(
file
&&
file
->
delete_table
(
path
))
{
error
=
1
;
error
=
1
;
sql_print_error
(
"Warning: Could not remove tmp table: '%s', error: %d"
,
path
,
my_errno
);
}
delete
file
;
delete
file
;
DBUG_RETURN
(
error
);
DBUG_RETURN
(
error
);
}
}
...
@@ -1815,42 +1673,33 @@ bool rm_temporary_table(enum db_type base, char *path)
...
@@ -1815,42 +1673,33 @@ bool rm_temporary_table(enum db_type base, char *path)
#define WRONG_GRANT (Field*) -1
#define WRONG_GRANT (Field*) -1
Field
*
find_field_in_table
(
THD
*
thd
,
TABLE
*
table
,
const
char
*
name
,
uint
length
,
Field
*
find_field_in_table
(
THD
*
thd
,
TABLE
*
table
,
const
char
*
name
,
uint
length
,
bool
check_grants
,
bool
allow_rowid
,
bool
check_grants
,
bool
allow_rowid
)
uint
*
cached_field_index_ptr
)
{
{
Field
**
field_ptr
,
*
field
;
Field
*
field
;
uint
cached_field_index
=
*
cached_field_index_ptr
;
if
(
table
->
name_hash
.
records
)
{
/* We assume here that table->field < NO_CACHED_FIELD_INDEX = UINT_MAX */
if
((
field
=
(
Field
*
)
hash_search
(
&
table
->
name_hash
,(
byte
*
)
name
,
if
(
cached_field_index
<
table
->
fields
&&
length
)))
!
my_strcasecmp
(
system_charset_info
,
goto
found
;
table
->
field
[
cached_field_index
]
->
field_name
,
name
))
}
field_ptr
=
table
->
field
+
cached_field_index
;
else
if
(
table
->
name_hash
.
records
)
field_ptr
=
(
Field
**
)
hash_search
(
&
table
->
name_hash
,(
byte
*
)
name
,
length
);
else
else
{
{
if
(
!
(
field_ptr
=
table
->
field
))
Field
**
ptr
;
if
(
!
(
ptr
=
table
->
field
))
return
(
Field
*
)
0
;
return
(
Field
*
)
0
;
for
(;
*
field_ptr
;
++
field_ptr
)
while
((
field
=
*
ptr
++
))
if
(
!
my_strcasecmp
(
system_charset_info
,
(
*
field_ptr
)
->
field_name
,
name
))
break
;
}
if
(
field_ptr
&&
*
field_ptr
)
{
{
*
cached_field_index_ptr
=
field_ptr
-
table
->
field
;
if
(
!
my_strcasecmp
(
system_charset_info
,
field
->
field_name
,
name
))
field
=
*
field_ptr
;
goto
found
;
}
}
else
{
if
(
!
allow_rowid
||
my_strcasecmp
(
system_charset_info
,
name
,
"_rowid"
)
||
!
(
field
=
table
->
rowid_field
))
return
(
Field
*
)
0
;
}
}
if
(
allow_rowid
&&
!
my_strcasecmp
(
system_charset_info
,
name
,
"_rowid"
)
&&
(
field
=
table
->
rowid_field
))
goto
found
;
return
(
Field
*
)
0
;
found:
if
(
thd
->
set_query_id
)
if
(
thd
->
set_query_id
)
{
{
if
(
field
->
query_id
!=
thd
->
query_id
)
if
(
field
->
query_id
!=
thd
->
query_id
)
...
@@ -1877,7 +1726,7 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
...
@@ -1877,7 +1726,7 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
find_field_in_tables()
find_field_in_tables()
thd Pointer to current thread structure
thd Pointer to current thread structure
item Field item that should be found
item Field item that should be found
tables Tables for scan
n
ing
tables Tables for scaning
where Table where field found will be returned via
where Table where field found will be returned via
this parameter
this parameter
report_error If FALSE then do not report error if item not found
report_error If FALSE then do not report error if item not found
...
@@ -1905,32 +1754,6 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
...
@@ -1905,32 +1754,6 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
uint
length
=
(
uint
)
strlen
(
name
);
uint
length
=
(
uint
)
strlen
(
name
);
char
name_buff
[
NAME_LEN
+
1
];
char
name_buff
[
NAME_LEN
+
1
];
if
(
item
->
cached_table
)
{
/*
This shortcut is used by prepared statements. We assuming that
TABLE_LIST *tables is not changed during query execution (which
is true for all queries except RENAME but luckily RENAME doesn't
use fields...) so we can rely on reusing pointer to its member.
With this optimisation we also miss case when addition of one more
field makes some prepared query ambiguous and so erronous, but we
accept this trade off.
*/
found
=
find_field_in_table
(
thd
,
item
->
cached_table
->
table
,
name
,
length
,
test
(
item
->
cached_table
->
table
->
grant
.
want_privilege
),
1
,
&
(
item
->
cached_field_index
));
if
(
found
)
{
(
*
where
)
=
tables
;
if
(
found
==
WRONG_GRANT
)
return
(
Field
*
)
0
;
return
found
;
}
}
if
(
db
&&
lower_case_table_names
)
if
(
db
&&
lower_case_table_names
)
{
{
/*
/*
...
@@ -1955,12 +1778,10 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
...
@@ -1955,12 +1778,10 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
Field
*
find
=
find_field_in_table
(
thd
,
tables
->
table
,
name
,
length
,
Field
*
find
=
find_field_in_table
(
thd
,
tables
->
table
,
name
,
length
,
test
(
tables
->
table
->
grant
.
test
(
tables
->
table
->
grant
.
want_privilege
),
want_privilege
),
1
,
&
(
item
->
cached_field_index
)
);
1
);
if
(
find
)
if
(
find
)
{
{
(
*
where
)
=
item
->
cached_table
=
tables
;
(
*
where
)
=
tables
;
if
(
!
tables
->
cacheable_table
)
item
->
cached_table
=
0
;
if
(
find
==
WRONG_GRANT
)
if
(
find
==
WRONG_GRANT
)
return
(
Field
*
)
0
;
return
(
Field
*
)
0
;
if
(
db
||
!
thd
->
where
)
if
(
db
||
!
thd
->
where
)
...
@@ -2014,14 +1835,12 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
...
@@ -2014,14 +1835,12 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
Field
*
field
=
find_field_in_table
(
thd
,
tables
->
table
,
name
,
length
,
Field
*
field
=
find_field_in_table
(
thd
,
tables
->
table
,
name
,
length
,
test
(
tables
->
table
->
grant
.
want_privilege
),
test
(
tables
->
table
->
grant
.
want_privilege
),
allow_rowid
,
&
(
item
->
cached_field_index
)
);
allow_rowid
);
if
(
field
)
if
(
field
)
{
{
if
(
field
==
WRONG_GRANT
)
if
(
field
==
WRONG_GRANT
)
return
(
Field
*
)
0
;
return
(
Field
*
)
0
;
(
*
where
)
=
item
->
cached_table
=
tables
;
(
*
where
)
=
tables
;
if
(
!
tables
->
cacheable_table
)
item
->
cached_table
=
0
;
if
(
found
)
if
(
found
)
{
{
if
(
!
thd
->
where
)
// Returns first found
if
(
!
thd
->
where
)
// Returns first found
...
@@ -2096,16 +1915,7 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
...
@@ -2096,16 +1915,7 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
if
(
field_name
&&
item
->
type
()
==
Item
::
FIELD_ITEM
)
if
(
field_name
&&
item
->
type
()
==
Item
::
FIELD_ITEM
)
{
{
Item_field
*
item_field
=
(
Item_field
*
)
item
;
Item_field
*
item_field
=
(
Item_field
*
)
item
;
/*
if
(
!
my_strcasecmp
(
system_charset_info
,
item_field
->
name
,
field_name
))
In case of group_concat() with ORDER BY condition in the QUERY
item_field can be field of temporary table without item name
(if this field created from expression argument of group_concat()),
=> we have to check presence of name before compare
*/
if
(
item_field
->
name
&&
(
!
my_strcasecmp
(
system_charset_info
,
item_field
->
name
,
field_name
)
||
!
my_strcasecmp
(
system_charset_info
,
item_field
->
field_name
,
field_name
)))
{
{
if
(
!
table_name
)
if
(
!
table_name
)
{
{
...
@@ -2125,7 +1935,7 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
...
@@ -2125,7 +1935,7 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
{
{
if
(
!
strcmp
(
item_field
->
table_name
,
table_name
)
&&
if
(
!
strcmp
(
item_field
->
table_name
,
table_name
)
&&
(
!
db_name
||
(
db_name
&&
item_field
->
db_name
&&
(
!
db_name
||
(
db_name
&&
item_field
->
db_name
&&
!
strcmp
(
item_field
->
db_name
,
db
_name
))))
!
strcmp
(
item_field
->
table_name
,
table
_name
))))
{
{
found
=
li
.
ref
();
found
=
li
.
ref
();
*
counter
=
i
;
*
counter
=
i
;
...
@@ -2167,14 +1977,6 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
...
@@ -2167,14 +1977,6 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
{
{
if
(
!
wild_num
)
if
(
!
wild_num
)
return
0
;
return
0
;
Item_arena
*
arena
=
thd
->
current_arena
,
backup
;
/*
If we are in preparing prepared statement phase then we have change
temporary mem_root to statement mem root to save changes of SELECT list
*/
if
(
arena
)
thd
->
set_n_backup_item_arena
(
arena
,
&
backup
);
reg2
Item
*
item
;
reg2
Item
*
item
;
List_iterator
<
Item
>
it
(
fields
);
List_iterator
<
Item
>
it
(
fields
);
while
(
wild_num
&&
(
item
=
it
++
))
while
(
wild_num
&&
(
item
=
it
++
))
...
@@ -2186,11 +1988,7 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
...
@@ -2186,11 +1988,7 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
uint
elem
=
fields
.
elements
;
uint
elem
=
fields
.
elements
;
if
(
insert_fields
(
thd
,
tables
,((
Item_field
*
)
item
)
->
db_name
,
if
(
insert_fields
(
thd
,
tables
,((
Item_field
*
)
item
)
->
db_name
,
((
Item_field
*
)
item
)
->
table_name
,
&
it
))
((
Item_field
*
)
item
)
->
table_name
,
&
it
))
{
if
(
arena
)
thd
->
restore_backup_item_arena
(
arena
,
&
backup
);
return
(
-
1
);
return
(
-
1
);
}
if
(
sum_func_list
)
if
(
sum_func_list
)
{
{
/*
/*
...
@@ -2203,15 +2001,6 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
...
@@ -2203,15 +2001,6 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
wild_num
--
;
wild_num
--
;
}
}
}
}
if
(
arena
)
{
/* make * substituting permanent */
SELECT_LEX
*
select_lex
=
thd
->
lex
->
current_select
;
select_lex
->
with_wild
=
0
;
select_lex
->
item_list
=
fields
;
thd
->
restore_backup_item_arena
(
arena
,
&
backup
);
}
return
0
;
return
0
;
}
}
...
@@ -2234,9 +2023,10 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
...
@@ -2234,9 +2023,10 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
Item
**
ref
=
ref_pointer_array
;
Item
**
ref
=
ref_pointer_array
;
while
((
item
=
it
++
))
while
((
item
=
it
++
))
{
{
if
(
!
item
->
fixed
&&
item
->
fix_fields
(
thd
,
tables
,
it
.
ref
())
||
if
(
item
->
fix_fields
(
thd
,
tables
,
it
.
ref
())
||
(
item
=
*
(
it
.
ref
()))
->
check_cols
(
1
))
item
->
check_cols
(
1
))
DBUG_RETURN
(
-
1
);
/* purecov: inspected */
DBUG_RETURN
(
-
1
);
/* purecov: inspected */
item
=
*
(
it
.
ref
());
//Item can be changed in fix fields
if
(
ref
)
if
(
ref
)
*
(
ref
++
)
=
item
;
*
(
ref
++
)
=
item
;
if
(
item
->
with_sum_func
&&
item
->
type
()
!=
Item
::
SUM_FUNC_ITEM
&&
if
(
item
->
with_sum_func
&&
item
->
type
()
!=
Item
::
SUM_FUNC_ITEM
&&
...
@@ -2249,17 +2039,6 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
...
@@ -2249,17 +2039,6 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
/*
/*
prepare tables
SYNOPSIS
setup_tables()
tables - tables list
RETURN
0 ok; In this case *map will includes the choosed index
1 error
NOTE
Remap table numbers if INSERT ... SELECT
Remap table numbers if INSERT ... SELECT
Check also that the 'used keys' and 'ignored keys' exists and set up the
Check also that the 'used keys' and 'ignored keys' exists and set up the
table structure accordingly
table structure accordingly
...
@@ -2295,6 +2074,13 @@ bool setup_tables(TABLE_LIST *tables)
...
@@ -2295,6 +2074,13 @@ bool setup_tables(TABLE_LIST *tables)
table
->
keys_in_use_for_query
.
subtract
(
map
);
table
->
keys_in_use_for_query
.
subtract
(
map
);
}
}
table
->
used_keys
.
intersect
(
table
->
keys_in_use_for_query
);
table
->
used_keys
.
intersect
(
table
->
keys_in_use_for_query
);
if
(
table_list
->
shared
||
table
->
clear_query_id
)
{
table
->
clear_query_id
=
0
;
/* Clear query_id that may have been set by previous select */
for
(
Field
**
ptr
=
table
->
field
;
*
ptr
;
ptr
++
)
(
*
ptr
)
->
query_id
=
0
;
}
}
}
if
(
tablenr
>
MAX_TABLES
)
if
(
tablenr
>
MAX_TABLES
)
{
{
...
@@ -2370,29 +2156,14 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
...
@@ -2370,29 +2156,14 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
DBUG_RETURN
(
-
1
);
DBUG_RETURN
(
-
1
);
#endif
#endif
Field
**
ptr
=
table
->
field
,
*
field
;
Field
**
ptr
=
table
->
field
,
*
field
;
TABLE
*
natural_join_table
=
0
;
thd
->
used_tables
|=
table
->
map
;
thd
->
used_tables
|=
table
->
map
;
if
(
!
table
->
outer_join
&&
tables
->
natural_join
&&
!
tables
->
natural_join
->
table
->
outer_join
)
natural_join_table
=
tables
->
natural_join
->
table
;
while
((
field
=
*
ptr
++
))
while
((
field
=
*
ptr
++
))
{
{
uint
not_used_field_index
=
NO_CACHED_FIELD_INDEX
;
Item_field
*
item
=
new
Item_field
(
field
);
/* Skip duplicate field names if NATURAL JOIN is used */
if
(
!
natural_join_table
||
!
find_field_in_table
(
thd
,
natural_join_table
,
field
->
field_name
,
strlen
(
field
->
field_name
),
0
,
0
,
&
not_used_field_index
))
{
Item_field
*
item
=
new
Item_field
(
thd
,
field
);
if
(
!
found
++
)
if
(
!
found
++
)
(
void
)
it
->
replace
(
item
);
// Replace '*'
(
void
)
it
->
replace
(
item
);
// Replace '*'
else
else
it
->
after
(
item
);
it
->
after
(
item
);
}
/*
/*
Mark if field used before in this select.
Mark if field used before in this select.
Used by 'insert' to verify if a field name is used twice
Used by 'insert' to verify if a field name is used twice
...
@@ -2424,143 +2195,121 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
...
@@ -2424,143 +2195,121 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
int
setup_conds
(
THD
*
thd
,
TABLE_LIST
*
tables
,
COND
**
conds
)
int
setup_conds
(
THD
*
thd
,
TABLE_LIST
*
tables
,
COND
**
conds
)
{
{
table_map
not_null_tables
=
0
;
table_map
not_null_tables
=
0
;
SELECT_LEX
*
select_lex
=
thd
->
lex
->
current_select
;
Item_arena
*
arena
=
((
thd
->
current_arena
&&
!
select_lex
->
conds_processed_with_permanent_arena
)
?
thd
->
current_arena
:
0
);
Item_arena
backup
;
DBUG_ENTER
(
"setup_conds"
);
DBUG_ENTER
(
"setup_conds"
);
thd
->
set_query_id
=
1
;
thd
->
set_query_id
=
1
;
select_lex
->
cond_count
=
0
;
thd
->
lex
->
current_select
->
cond_count
=
0
;
if
(
*
conds
)
if
(
*
conds
)
{
{
thd
->
where
=
"where clause"
;
thd
->
where
=
"where clause"
;
if
(
!
(
*
conds
)
->
fixed
&&
(
*
conds
)
->
fix_fields
(
thd
,
tables
,
conds
)
||
if
((
*
conds
)
->
fix_fields
(
thd
,
tables
,
conds
)
||
(
*
conds
)
->
check_cols
(
1
))
(
*
conds
)
->
check_cols
(
1
))
DBUG_RETURN
(
1
);
DBUG_RETURN
(
1
);
not_null_tables
=
(
*
conds
)
->
not_null_tables
();
}
}
/* Check if we are using outer joins */
/* Check if we are using outer joins */
for
(
TABLE_LIST
*
table
=
tables
;
table
;
table
=
table
->
next
)
for
(
TABLE_LIST
*
table
=
tables
;
table
;
table
=
table
->
next
)
{
{
if
(
table
->
on_expr
)
TABLE_LIST
*
embedded
;
TABLE_LIST
*
embedding
=
table
;
do
{
embedded
=
embedding
;
if
(
embedded
->
on_expr
)
{
{
/* Make a join an a expression */
/* Make a join an a expression */
thd
->
where
=
"on clause"
;
thd
->
where
=
"on clause"
;
if
(
embedded
->
on_expr
->
fix_fields
(
thd
,
tables
,
&
embedded
->
on_expr
)
||
if
(
!
table
->
on_expr
->
fixed
&&
embedded
->
on_expr
->
check_cols
(
1
))
table
->
on_expr
->
fix_fields
(
thd
,
tables
,
&
table
->
on_expr
)
||
table
->
on_expr
->
check_cols
(
1
))
DBUG_RETURN
(
1
);
select_lex
->
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
->
outer_join
=
0
;
if
(
arena
)
thd
->
set_n_backup_item_arena
(
arena
,
&
backup
);
*
conds
=
and_conds
(
*
conds
,
table
->
on_expr
);
table
->
on_expr
=
0
;
if
(
arena
)
thd
->
restore_backup_item_arena
(
arena
,
&
backup
);
if
((
*
conds
)
&&
!
(
*
conds
)
->
fixed
&&
(
*
conds
)
->
fix_fields
(
thd
,
tables
,
conds
))
DBUG_RETURN
(
1
);
DBUG_RETURN
(
1
);
thd
->
lex
->
current_select
->
cond_count
++
;
}
}
}
if
(
embedded
->
natural_join
)
if
(
table
->
natural_join
)
{
{
if
(
arena
)
thd
->
set_n_backup_item_arena
(
arena
,
&
backup
);
/* Make a join of all fields with have the same name */
/* Make a join of all fields with have the same name */
TABLE
*
t1
=
table
->
table
;
TABLE_LIST
*
tab1
=
embedded
;
TABLE
*
t2
=
table
->
natural_join
->
table
;
TABLE_LIST
*
tab2
=
embedded
->
natural_join
;
Item_cond_and
*
cond_and
=
new
Item_cond_and
();
if
(
!
(
embedded
->
outer_join
&
JOIN_TYPE_RIGHT
))
if
(
!
cond_and
)
// If not out of memory
goto
err
;
cond_and
->
top_level_item
();
Field
**
t1_field
,
*
t2_field
;
for
(
t1_field
=
t1
->
field
;
(
*
t1_field
);
t1_field
++
)
{
{
const
char
*
t1_field_name
=
(
*
t1_field
)
->
field_name
;
while
(
tab1
->
nested_join
)
uint
not_used_field_index
=
NO_CACHED_FIELD_INDEX
;
if
((
t2_field
=
find_field_in_table
(
thd
,
t2
,
t1_field_name
,
strlen
(
t1_field_name
),
0
,
0
,
&
not_used_field_index
)))
{
{
Item_func_eq
*
tmp
=
new
Item_func_eq
(
new
Item_field
(
*
t1_field
),
TABLE_LIST
*
next
;
new
Item_field
(
t2_field
));
List_iterator_fast
<
TABLE_LIST
>
it
(
tab1
->
nested_join
->
join_list
);
if
(
!
tmp
)
tab1
=
it
++
;
goto
err
;
while
((
next
=
it
++
))
/* Mark field used for table cache */
tab1
=
next
;
(
*
t1_field
)
->
query_id
=
t2_field
->
query_id
=
thd
->
query_id
;
cond_and
->
list
.
push_back
(
tmp
);
t1
->
used_keys
.
intersect
((
*
t1_field
)
->
part_of_key
);
t2
->
used_keys
.
intersect
(
t2_field
->
part_of_key
);
}
}
}
}
select_lex
->
cond_count
+=
cond_and
->
list
.
elements
;
else
// to prevent natural join processing during PS re-execution
table
->
natural_join
=
0
;
if
(
!
table
->
outer_join
)
// Not left join
{
{
*
conds
=
and_conds
(
*
conds
,
cond_and
);
while
(
tab1
->
nested_join
)
// fix_fields() should be made with temporary memory pool
tab1
=
tab1
->
nested_join
->
join_list
.
head
();
if
(
arena
)
}
thd
->
restore_backup_item_arena
(
arena
,
&
backup
);
if
(
embedded
->
outer_join
&
JOIN_TYPE_RIGHT
)
if
(
*
conds
&&
!
(
*
conds
)
->
fixed
)
{
{
if
((
*
conds
)
->
fix_fields
(
thd
,
tables
,
conds
))
while
(
tab2
->
nested_join
)
DBUG_RETURN
(
1
);
{
TABLE_LIST
*
next
;
List_iterator_fast
<
TABLE_LIST
>
it
(
tab2
->
nested_join
->
join_list
);
tab2
=
it
++
;
while
((
next
=
it
++
))
tab2
=
next
;
}
}
}
}
else
else
{
{
table
->
on_expr
=
and_conds
(
table
->
on_expr
,
cond_and
);
while
(
tab2
->
nested_join
)
// fix_fields() should be made with temporary memory pool
tab2
=
tab2
->
nested_join
->
join_list
.
head
();
if
(
arena
)
}
thd
->
restore_backup_item_arena
(
arena
,
&
backup
);
TABLE
*
t1
=
tab1
->
table
;
if
(
table
->
on_expr
&&
!
table
->
on_expr
->
fixed
)
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
++
)
{
{
if
(
table
->
on_expr
->
fix_fields
(
thd
,
tables
,
&
table
->
on_expr
))
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
);
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
;
if
(
arena
)
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
)))
We are in prepared statement preparation code => we should store
DBUG_RETURN
(
1
);
WHERE clause changing for next executions.
}
else
We do this ON -> WHERE transformation only once per PS/SP statement.
embedded
->
on_expr
=
and_conds
(
embedded
->
on_expr
,
on_expr
);
*/
}
select_lex
->
where
=
*
conds
;
embedding
=
embedded
->
embedding
;
select_lex
->
conds_processed_with_permanent_arena
=
1
;
}
while
(
embedding
&&
embedding
->
nested_join
->
join_list
.
head
()
==
embedded
);
}
}
DBUG_RETURN
(
test
(
thd
->
net
.
report_error
));
DBUG_RETURN
(
test
(
thd
->
net
.
report_error
));
err:
if
(
arena
)
thd
->
restore_backup_item_arena
(
arena
,
&
backup
);
DBUG_RETURN
(
1
);
}
}
...
@@ -2584,7 +2333,7 @@ fill_record(List<Item> &fields,List<Item> &values, bool ignore_errors)
...
@@ -2584,7 +2333,7 @@ fill_record(List<Item> &fields,List<Item> &values, bool ignore_errors)
TABLE
*
table
=
rfield
->
table
;
TABLE
*
table
=
rfield
->
table
;
if
(
rfield
==
table
->
next_number_field
)
if
(
rfield
==
table
->
next_number_field
)
table
->
auto_increment_field_not_null
=
true
;
table
->
auto_increment_field_not_null
=
true
;
if
(
(
value
->
save_in_field
(
rfield
,
0
)
<
0
)
&&
!
ignore_errors
)
if
(
value
->
save_in_field
(
rfield
,
0
)
>
0
&&
!
ignore_errors
)
DBUG_RETURN
(
1
);
DBUG_RETURN
(
1
);
}
}
DBUG_RETURN
(
0
);
DBUG_RETURN
(
0
);
...
@@ -2605,7 +2354,7 @@ fill_record(Field **ptr,List<Item> &values, bool ignore_errors)
...
@@ -2605,7 +2354,7 @@ fill_record(Field **ptr,List<Item> &values, bool ignore_errors)
TABLE
*
table
=
field
->
table
;
TABLE
*
table
=
field
->
table
;
if
(
field
==
table
->
next_number_field
)
if
(
field
==
table
->
next_number_field
)
table
->
auto_increment_field_not_null
=
true
;
table
->
auto_increment_field_not_null
=
true
;
if
(
(
value
->
save_in_field
(
field
,
0
)
<
0
)
&&
!
ignore_errors
)
if
(
value
->
save_in_field
(
field
,
0
)
==
1
&&
!
ignore_errors
)
DBUG_RETURN
(
1
);
DBUG_RETURN
(
1
);
}
}
DBUG_RETURN
(
0
);
DBUG_RETURN
(
0
);
...
@@ -2629,15 +2378,9 @@ static void mysql_rm_tmp_tables(void)
...
@@ -2629,15 +2378,9 @@ static void mysql_rm_tmp_tables(void)
/* Remove all SQLxxx tables from directory */
/* Remove all SQLxxx tables from directory */
for
(
idx
=
0
;
idx
<
(
uint
)
dirp
->
number_off_files
;
idx
++
)
for
(
idx
=
2
;
idx
<
(
uint
)
dirp
->
number_off_files
;
idx
++
)
{
{
file
=
dirp
->
dir_entry
+
idx
;
file
=
dirp
->
dir_entry
+
idx
;
/* skiping . and .. */
if
(
file
->
name
[
0
]
==
'.'
&&
(
!
file
->
name
[
1
]
||
(
file
->
name
[
1
]
==
'.'
&&
!
file
->
name
[
2
])))
continue
;
if
(
!
bcmp
(
file
->
name
,
tmp_file_prefix
,
tmp_file_prefix_length
))
if
(
!
bcmp
(
file
->
name
,
tmp_file_prefix
,
tmp_file_prefix_length
))
{
{
sprintf
(
filePath
,
"%s%s"
,
tmpdir
,
file
->
name
);
sprintf
(
filePath
,
"%s%s"
,
tmpdir
,
file
->
name
);
...
@@ -2650,6 +2393,45 @@ static void mysql_rm_tmp_tables(void)
...
@@ -2650,6 +2393,45 @@ static void mysql_rm_tmp_tables(void)
}
}
/*
CREATE INDEX and DROP INDEX are implemented by calling ALTER TABLE with
the proper arguments. This isn't very fast but it should work for most
cases.
One should normally create all indexes with CREATE TABLE or ALTER TABLE.
*/
int
mysql_create_index
(
THD
*
thd
,
TABLE_LIST
*
table_list
,
List
<
Key
>
&
keys
)
{
List
<
create_field
>
fields
;
List
<
Alter_drop
>
drop
;
List
<
Alter_column
>
alter
;
HA_CREATE_INFO
create_info
;
DBUG_ENTER
(
"mysql_create_index"
);
bzero
((
char
*
)
&
create_info
,
sizeof
(
create_info
));
create_info
.
db_type
=
DB_TYPE_DEFAULT
;
create_info
.
default_table_charset
=
thd
->
variables
.
collation_database
;
DBUG_RETURN
(
mysql_alter_table
(
thd
,
table_list
->
db
,
table_list
->
real_name
,
&
create_info
,
table_list
,
fields
,
keys
,
drop
,
alter
,
0
,
(
ORDER
*
)
0
,
FALSE
,
DUP_ERROR
));
}
int
mysql_drop_index
(
THD
*
thd
,
TABLE_LIST
*
table_list
,
List
<
Alter_drop
>
&
drop
)
{
List
<
create_field
>
fields
;
List
<
Key
>
keys
;
List
<
Alter_column
>
alter
;
HA_CREATE_INFO
create_info
;
DBUG_ENTER
(
"mysql_drop_index"
);
bzero
((
char
*
)
&
create_info
,
sizeof
(
create_info
));
create_info
.
db_type
=
DB_TYPE_DEFAULT
;
create_info
.
default_table_charset
=
thd
->
variables
.
collation_database
;
DBUG_RETURN
(
mysql_alter_table
(
thd
,
table_list
->
db
,
table_list
->
real_name
,
&
create_info
,
table_list
,
fields
,
keys
,
drop
,
alter
,
0
,
(
ORDER
*
)
0
,
FALSE
,
DUP_ERROR
));
}
/*****************************************************************************
/*****************************************************************************
unireg support functions
unireg support functions
...
@@ -2723,8 +2505,7 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
...
@@ -2723,8 +2505,7 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
if
(
table
->
db_stat
)
if
(
table
->
db_stat
)
result
=
1
;
result
=
1
;
/* Kill delayed insert threads */
/* Kill delayed insert threads */
if
((
in_use
->
system_thread
&
SYSTEM_THREAD_DELAYED_INSERT
)
&&
if
(
in_use
->
system_thread
&&
!
in_use
->
killed
)
!
in_use
->
killed
)
{
{
in_use
->
killed
=
THD
::
KILL_CONNECTION
;
in_use
->
killed
=
THD
::
KILL_CONNECTION
;
pthread_mutex_lock
(
&
in_use
->
mysys_var
->
mutex
);
pthread_mutex_lock
(
&
in_use
->
mysys_var
->
mutex
);
...
...
sql/sql_lex.cc
View file @
64d46dfe
...
@@ -1003,6 +1003,9 @@ void st_select_lex::init_query()
...
@@ -1003,6 +1003,9 @@ void st_select_lex::init_query()
{
{
st_select_lex_node
::
init_query
();
st_select_lex_node
::
init_query
();
table_list
.
empty
();
table_list
.
empty
();
top_join_list
.
empty
();
join_list
=
&
top_join_list
;
embedding
=
0
;
item_list
.
empty
();
item_list
.
empty
();
join
=
0
;
join
=
0
;
where
=
0
;
where
=
0
;
...
...
sql/sql_lex.h
View file @
64d46dfe
...
@@ -416,6 +416,9 @@ class st_select_lex: public st_select_lex_node
...
@@ -416,6 +416,9 @@ class st_select_lex: public st_select_lex_node
List
<
Item_func_match
>
*
ftfunc_list
;
List
<
Item_func_match
>
*
ftfunc_list
;
List
<
Item_func_match
>
ftfunc_list_alloc
;
List
<
Item_func_match
>
ftfunc_list_alloc
;
JOIN
*
join
;
/* after JOIN::prepare it is pointer to corresponding JOIN */
JOIN
*
join
;
/* after JOIN::prepare it is pointer to corresponding JOIN */
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 */
const
char
*
type
;
/* type of select for EXPLAIN */
SQL_LIST
order_list
;
/* ORDER clause */
SQL_LIST
order_list
;
/* ORDER clause */
...
@@ -513,6 +516,12 @@ class st_select_lex: public st_select_lex_node
...
@@ -513,6 +516,12 @@ class st_select_lex: public st_select_lex_node
List
<
String
>
*
ignore_index
=
0
,
List
<
String
>
*
ignore_index
=
0
,
LEX_STRING
*
option
=
0
);
LEX_STRING
*
option
=
0
);
TABLE_LIST
*
get_table_list
();
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
<
Item
>*
get_item_list
();
List
<
String
>*
get_use_index
();
List
<
String
>*
get_use_index
();
List
<
String
>*
get_ignore_index
();
List
<
String
>*
get_ignore_index
();
...
...
sql/sql_parse.cc
View file @
64d46dfe
...
@@ -4796,6 +4796,237 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
...
@@ -4796,6 +4796,237 @@ 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
();
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
Set lock for all tables in current select level
...
...
sql/sql_select.cc
View file @
64d46dfe
This source diff could not be displayed because it is too large. You can
view the blob
instead.
sql/sql_select.h
View file @
64d46dfe
...
@@ -75,7 +75,6 @@ typedef struct st_join_cache {
...
@@ -75,7 +75,6 @@ typedef struct st_join_cache {
/*
/*
** The structs which holds the join connections and join states
** 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
,
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_ALL
,
JT_RANGE
,
JT_NEXT
,
JT_FT
,
JT_REF_OR_NULL
,
JT_UNIQUE_SUBQUERY
,
JT_INDEX_SUBQUERY
,
JT_INDEX_MERGE
};
JT_UNIQUE_SUBQUERY
,
JT_INDEX_SUBQUERY
,
JT_INDEX_MERGE
};
...
@@ -88,7 +87,13 @@ typedef struct st_join_table {
...
@@ -88,7 +87,13 @@ typedef struct st_join_table {
SQL_SELECT
*
select
;
SQL_SELECT
*
select
;
COND
*
select_cond
;
COND
*
select_cond
;
QUICK_SELECT_I
*
quick
;
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
;
const
char
*
info
;
int
(
*
read_first_record
)(
struct
st_join_table
*
tab
);
int
(
*
read_first_record
)(
struct
st_join_table
*
tab
);
int
(
*
next_select
)(
JOIN
*
,
struct
st_join_table
*
,
bool
);
int
(
*
next_select
)(
JOIN
*
,
struct
st_join_table
*
,
bool
);
...
@@ -201,8 +206,10 @@ class JOIN :public Sql_alloc
...
@@ -201,8 +206,10 @@ class JOIN :public Sql_alloc
ORDER
*
order
,
*
group_list
,
*
proc_param
;
//hold parameters of mysql_select
ORDER
*
order
,
*
group_list
,
*
proc_param
;
//hold parameters of mysql_select
COND
*
conds
;
// ---"---
COND
*
conds
;
// ---"---
Item
*
conds_history
;
// store WHERE for explain
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
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
Item
**
ref_pointer_array
;
//used pointer reference for this select
// Copy of above to be used with different lists
// Copy of above to be used with different lists
Item
**
items0
,
**
items1
,
**
items2
,
**
items3
,
**
current_ref_pointer_array
;
Item
**
items0
,
**
items1
,
**
items2
,
**
items3
,
**
current_ref_pointer_array
;
...
@@ -226,6 +233,7 @@ class JOIN :public Sql_alloc
...
@@ -226,6 +233,7 @@ class JOIN :public Sql_alloc
table
=
0
;
table
=
0
;
tables
=
0
;
tables
=
0
;
const_tables
=
0
;
const_tables
=
0
;
join_list
=
0
;
sort_and_group
=
0
;
sort_and_group
=
0
;
first_record
=
0
;
first_record
=
0
;
do_send_rows
=
1
;
do_send_rows
=
1
;
...
@@ -256,6 +264,7 @@ class JOIN :public Sql_alloc
...
@@ -256,6 +264,7 @@ class JOIN :public Sql_alloc
fields_list
=
fields_arg
;
fields_list
=
fields_arg
;
error
=
0
;
error
=
0
;
select
=
0
;
select
=
0
;
return_tab
=
0
;
ref_pointer_array
=
items0
=
items1
=
items2
=
items3
=
0
;
ref_pointer_array
=
items0
=
items1
=
items2
=
items3
=
0
;
ref_pointer_array_size
=
0
;
ref_pointer_array_size
=
0
;
zero_result_cause
=
0
;
zero_result_cause
=
0
;
...
...
sql/table.h
View file @
64d46dfe
...
@@ -26,7 +26,6 @@ class st_select_lex_unit;
...
@@ -26,7 +26,6 @@ class st_select_lex_unit;
typedef
struct
st_order
{
typedef
struct
st_order
{
struct
st_order
*
next
;
struct
st_order
*
next
;
Item
**
item
;
/* Point at item in select fields */
Item
**
item
;
/* Point at item in select fields */
Item
*
item_ptr
;
/* Storage for initial item */
Item
**
item_copy
;
/* For SPs; the original item ptr */
Item
**
item_copy
;
/* For SPs; the original item ptr */
bool
asc
;
/* true if ascending */
bool
asc
;
/* true if ascending */
bool
free_me
;
/* true if item isn't shared */
bool
free_me
;
/* true if item isn't shared */
...
@@ -67,8 +66,7 @@ struct st_table {
...
@@ -67,8 +66,7 @@ struct st_table {
handler
*
file
;
handler
*
file
;
Field
**
field
;
/* Pointer to fields */
Field
**
field
;
/* Pointer to fields */
Field_blob
**
blob_field
;
/* Pointer to blob fields */
Field_blob
**
blob_field
;
/* Pointer to blob fields */
/* hash of field names (contains pointers to elements of field array) */
HASH
name_hash
;
/* hash of field names */
HASH
name_hash
;
byte
*
record
[
2
];
/* Pointer to records */
byte
*
record
[
2
];
/* Pointer to records */
byte
*
default_values
;
/* Default values for INSERT */
byte
*
default_values
;
/* Default values for INSERT */
byte
*
insert_values
;
/* used by INSERT ... UPDATE */
byte
*
insert_values
;
/* used by INSERT ... UPDATE */
...
@@ -99,20 +97,8 @@ struct st_table {
...
@@ -99,20 +97,8 @@ struct st_table {
uint
raid_type
,
raid_chunks
;
uint
raid_type
,
raid_chunks
;
uint
status
;
/* Used by postfix.. */
uint
status
;
/* Used by postfix.. */
uint
system
;
/* Set if system record */
uint
system
;
/* Set if system record */
ulong
time_stamp
;
/* Set to offset+1 of record */
/*
These two members hold offset in record + 1 for TIMESTAMP field
with NOW() as default value or/and with ON UPDATE NOW() option.
If 0 then such field is absent in this table or auto-set for default
or/and on update should be temporaly disabled for some reason.
These values is setup to offset value for each statement in open_table()
and turned off in statement processing code (see mysql_update as example).
*/
ulong
timestamp_default_now
;
ulong
timestamp_on_update_now
;
/* Index of auto-updated TIMESTAMP field in field array */
uint
timestamp_field_offset
;
uint
timestamp_field_offset
;
uint
next_number_index
;
uint
next_number_index
;
uint
blob_ptr_size
;
/* 4 or 8 */
uint
blob_ptr_size
;
/* 4 or 8 */
uint
next_number_key_offset
;
uint
next_number_key_offset
;
...
@@ -123,7 +109,7 @@ struct st_table {
...
@@ -123,7 +109,7 @@ struct st_table {
my_bool
maybe_null
,
outer_join
;
/* Used with OUTER JOIN */
my_bool
maybe_null
,
outer_join
;
/* Used with OUTER JOIN */
my_bool
force_index
;
my_bool
force_index
;
my_bool
distinct
,
const_table
,
no_rows
;
my_bool
distinct
,
const_table
,
no_rows
;
my_bool
key_read
;
my_bool
key_read
,
bulk_insert
;
my_bool
crypted
;
my_bool
crypted
;
my_bool
db_low_byte_first
;
/* Portable row format */
my_bool
db_low_byte_first
;
/* Portable row format */
my_bool
locked_by_flush
;
my_bool
locked_by_flush
;
...
@@ -157,12 +143,8 @@ struct st_table {
...
@@ -157,12 +143,8 @@ struct st_table {
uint
quick_key_parts
[
MAX_KEY
];
uint
quick_key_parts
[
MAX_KEY
];
key_part_map
const_key_parts
[
MAX_KEY
];
key_part_map
const_key_parts
[
MAX_KEY
];
ulong
query_id
;
ulong
query_id
;
union
/* Temporary variables */
{
uint
temp_pool_slot
;
/* Used by intern temp tables */
uint
temp_pool_slot
;
/* Used by intern temp tables */
struct
st_table_list
*
pos_in_table_list
;
struct
st_table_list
*
pos_in_table_list
;
/* Element referring to this table */
};
/* number of select if it is derived table */
/* number of select if it is derived table */
uint
derived_select_number
;
uint
derived_select_number
;
THD
*
in_use
;
/* Which thread uses this */
THD
*
in_use
;
/* Which thread uses this */
...
@@ -188,17 +170,28 @@ typedef struct st_table_list
...
@@ -188,17 +170,28 @@ typedef struct st_table_list
GRANT_INFO
grant
;
GRANT_INFO
grant
;
thr_lock_type
lock_type
;
thr_lock_type
lock_type
;
uint
outer_join
;
/* Which join type */
uint
outer_join
;
/* Which join type */
uint
shared
;
/* Used in multi-upd */
uint
shared
;
/* Used in
union or in
multi-upd */
uint32
db_length
,
real_name_length
;
uint32
db_length
,
real_name_length
;
bool
straight
;
/* optimize with prev table */
bool
straight
;
/* optimize with prev table */
bool
updating
;
/* for replicate-do/ignore table */
bool
updating
;
/* for replicate-do/ignore table */
bool
force_index
;
/* Prefer index over table scan */
bool
force_index
;
/* prefer index over table scan */
bool
ignore_leaves
;
/* Preload only non-leaf nodes */
bool
ignore_leaves
;
/* preload only non-leaf nodes */
bool
cacheable_table
;
/* stop PS caching */
table_map
dep_tables
;
/* tables the table depends on */
/* used in multi-upd privelege check */
table_map
on_expr_dep_tables
;
/* tables on expression depends on */
bool
table_in_update_from_clause
;
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
;
}
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
typedef
struct
st_changed_table_list
{
{
struct
st_changed_table_list
*
next
;
struct
st_changed_table_list
*
next
;
...
@@ -206,8 +199,7 @@ typedef struct st_changed_table_list
...
@@ -206,8 +199,7 @@ typedef struct st_changed_table_list
uint32
key_length
;
uint32
key_length
;
}
CHANGED_TABLE_LIST
;
}
CHANGED_TABLE_LIST
;
typedef
struct
st_open_table_list
typedef
struct
st_open_table_list
{
{
struct
st_open_table_list
*
next
;
struct
st_open_table_list
*
next
;
char
*
db
,
*
table
;
char
*
db
,
*
table
;
uint32
in_use
,
locked
;
uint32
in_use
,
locked
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment