mirror of
https://github.com/MariaDB/server.git
synced 2025-01-18 04:53:01 +01:00
After merge fix
This commit is contained in:
commit
64d46dfe9b
13 changed files with 3556 additions and 2195 deletions
1161
mysql-test/r/join_nested.result
Normal file
1161
mysql-test/r/join_nested.result
Normal file
File diff suppressed because it is too large
Load diff
|
@ -356,13 +356,7 @@ select t1.name, t2.name, t2.id, t2.owner, t3.id from t1 left join t2 on (t1.id =
|
||||||
name name id owner id
|
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));
|
||||||
|
|
|
@ -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
|
||||||
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
|
||||||
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
|
||||||
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
|
||||||
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
|
||||||
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
|
||||||
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
|
||||||
|
|
693
mysql-test/t/join_nested.test
Normal file
693
mysql-test/t/join_nested.test
Normal file
|
@ -0,0 +1,693 @@
|
||||||
|
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS t0,t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||||
|
|
||||||
|
CREATE TABLE t0 (a int, b int, c int);
|
||||||
|
CREATE TABLE t1 (a int, b int, c int);
|
||||||
|
CREATE TABLE t2 (a int, b int, c int);
|
||||||
|
CREATE TABLE t3 (a int, b int, c int);
|
||||||
|
CREATE TABLE t4 (a int, b int, c int);
|
||||||
|
CREATE TABLE t5 (a int, b int, c int);
|
||||||
|
CREATE TABLE t6 (a int, b int, c int);
|
||||||
|
CREATE TABLE t7 (a int, b int, c int);
|
||||||
|
CREATE TABLE t8 (a int, b int, c int);
|
||||||
|
CREATE TABLE t9 (a int, b int, c int);
|
||||||
|
|
||||||
|
INSERT INTO t0 VALUES (1,1,0), (1,2,0), (2,2,0);
|
||||||
|
INSERT INTO t1 VALUES (1,3,0), (2,2,0), (3,2,0);
|
||||||
|
INSERT INTO t2 VALUES (3,3,0), (4,2,0), (5,3,0);
|
||||||
|
INSERT INTO t3 VALUES (1,2,0), (2,2,0);
|
||||||
|
INSERT INTO t4 VALUES (3,2,0), (4,2,0);
|
||||||
|
INSERT INTO t5 VALUES (3,1,0), (2,2,0), (3,3,0);
|
||||||
|
INSERT INTO t6 VALUES (3,2,0), (6,2,0), (6,1,0);
|
||||||
|
INSERT INTO t7 VALUES (1,1,0), (2,2,0);
|
||||||
|
INSERT INTO t8 VALUES (0,2,0), (1,2,0);
|
||||||
|
INSERT INTO t9 VALUES (1,1,0), (1,2,0), (3,3,0);
|
||||||
|
|
||||||
|
|
||||||
|
SELECT t2.a,t2.b
|
||||||
|
FROM t2;
|
||||||
|
|
||||||
|
SELECT t3.a,t3.b
|
||||||
|
FROM t3;
|
||||||
|
|
||||||
|
SELECT t4.a,t4.b
|
||||||
|
FROM t4;
|
||||||
|
|
||||||
|
SELECT t3.a,t3.b,t4.a,t4.b
|
||||||
|
FROM t3,t4;
|
||||||
|
|
||||||
|
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
|
||||||
|
FROM t2
|
||||||
|
LEFT JOIN
|
||||||
|
(t3, t4)
|
||||||
|
ON t2.b=t4.b;
|
||||||
|
|
||||||
|
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
|
||||||
|
FROM t2
|
||||||
|
LEFT JOIN
|
||||||
|
(t3, t4)
|
||||||
|
ON t3.a=1 AND t2.b=t4.b;
|
||||||
|
|
||||||
|
EXPLAIN
|
||||||
|
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
|
||||||
|
FROM t2
|
||||||
|
LEFT JOIN
|
||||||
|
(t3, t4)
|
||||||
|
ON t2.b=t4.b
|
||||||
|
WHERE t3.a=1 OR t3.c IS NULL;
|
||||||
|
|
||||||
|
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
|
||||||
|
FROM t2
|
||||||
|
LEFT JOIN
|
||||||
|
(t3, t4)
|
||||||
|
ON t2.b=t4.b
|
||||||
|
WHERE t3.a=1 OR t3.c IS NULL;
|
||||||
|
|
||||||
|
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
|
||||||
|
FROM t2
|
||||||
|
LEFT JOIN
|
||||||
|
(t3, t4)
|
||||||
|
ON t2.b=t4.b
|
||||||
|
WHERE t3.a>1 OR t3.c IS NULL;
|
||||||
|
|
||||||
|
SELECT t5.a,t5.b
|
||||||
|
FROM t5;
|
||||||
|
|
||||||
|
SELECT t3.a,t3.b,t4.a,t4.b,t5.a,t5.b
|
||||||
|
FROM t3,t4,t5;
|
||||||
|
|
||||||
|
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b
|
||||||
|
FROM t2
|
||||||
|
LEFT JOIN
|
||||||
|
(t3, t4, t5)
|
||||||
|
ON t2.b=t4.b;
|
||||||
|
|
||||||
|
EXPLAIN
|
||||||
|
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b
|
||||||
|
FROM t2
|
||||||
|
LEFT JOIN
|
||||||
|
(t3, t4, t5)
|
||||||
|
ON t2.b=t4.b
|
||||||
|
WHERE t3.a>1 OR t3.c IS NULL;
|
||||||
|
|
||||||
|
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b
|
||||||
|
FROM t2
|
||||||
|
LEFT JOIN
|
||||||
|
(t3, t4, t5)
|
||||||
|
ON t2.b=t4.b
|
||||||
|
WHERE t3.a>1 OR t3.c IS NULL;
|
||||||
|
|
||||||
|
EXPLAIN
|
||||||
|
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b
|
||||||
|
FROM t2
|
||||||
|
LEFT JOIN
|
||||||
|
(t3, t4, t5)
|
||||||
|
ON t2.b=t4.b
|
||||||
|
WHERE (t3.a>1 OR t3.c IS NULL) AND
|
||||||
|
(t5.a<3 OR t5.c IS NULL);
|
||||||
|
|
||||||
|
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,t5.a,t5.b
|
||||||
|
FROM t2
|
||||||
|
LEFT JOIN
|
||||||
|
(t3, t4, t5)
|
||||||
|
ON t2.b=t4.b
|
||||||
|
WHERE (t3.a>1 OR t3.c IS NULL) AND
|
||||||
|
(t5.a<3 OR t5.c IS NULL);
|
||||||
|
|
||||||
|
SELECT t6.a,t6.b
|
||||||
|
FROM t6;
|
||||||
|
|
||||||
|
SELECT t7.a,t7.b
|
||||||
|
FROM t7;
|
||||||
|
|
||||||
|
SELECT t6.a,t6.b,t7.a,t7.b
|
||||||
|
FROM t6,t7;
|
||||||
|
|
||||||
|
SELECT t8.a,t8.b
|
||||||
|
FROM t8;
|
||||||
|
|
||||||
|
EXPLAIN
|
||||||
|
SELECT t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
|
||||||
|
FROM t6,
|
||||||
|
t7
|
||||||
|
LEFT JOIN
|
||||||
|
t8
|
||||||
|
ON t7.b=t8.b AND t6.b < 10;
|
||||||
|
|
||||||
|
SELECT t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
|
||||||
|
FROM t6,
|
||||||
|
t7
|
||||||
|
LEFT JOIN
|
||||||
|
t8
|
||||||
|
ON t7.b=t8.b AND t6.b < 10;
|
||||||
|
|
||||||
|
SELECT t5.a,t5.b
|
||||||
|
FROM t5;
|
||||||
|
|
||||||
|
SELECT t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
|
||||||
|
FROM t5
|
||||||
|
LEFT JOIN
|
||||||
|
(
|
||||||
|
t6,
|
||||||
|
t7
|
||||||
|
LEFT JOIN
|
||||||
|
t8
|
||||||
|
ON t7.b=t8.b AND t6.b < 10
|
||||||
|
)
|
||||||
|
ON t6.b >= 2 AND t5.b=t7.b;
|
||||||
|
|
||||||
|
SELECT t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
|
||||||
|
FROM t5
|
||||||
|
LEFT JOIN
|
||||||
|
(
|
||||||
|
t6,
|
||||||
|
t7
|
||||||
|
LEFT JOIN
|
||||||
|
t8
|
||||||
|
ON t7.b=t8.b AND t6.b < 10
|
||||||
|
)
|
||||||
|
ON t6.b >= 2 AND t5.b=t7.b AND
|
||||||
|
(t8.a < 1 OR t8.c IS NULL);
|
||||||
|
|
||||||
|
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
|
||||||
|
FROM t2
|
||||||
|
LEFT JOIN
|
||||||
|
(t3, t4)
|
||||||
|
ON t3.a=1 AND t2.b=t4.b;
|
||||||
|
|
||||||
|
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
|
||||||
|
t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
|
||||||
|
FROM t2
|
||||||
|
LEFT JOIN
|
||||||
|
(t3, t4)
|
||||||
|
ON t3.a=1 AND t2.b=t4.b,
|
||||||
|
t5
|
||||||
|
LEFT JOIN
|
||||||
|
(
|
||||||
|
t6,
|
||||||
|
t7
|
||||||
|
LEFT JOIN
|
||||||
|
t8
|
||||||
|
ON t7.b=t8.b AND t6.b < 10
|
||||||
|
)
|
||||||
|
ON t6.b >= 2 AND t5.b=t7.b;
|
||||||
|
|
||||||
|
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
|
||||||
|
t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
|
||||||
|
FROM t2
|
||||||
|
LEFT JOIN
|
||||||
|
(t3, t4)
|
||||||
|
ON t3.a=1 AND t2.b=t4.b,
|
||||||
|
t5
|
||||||
|
LEFT JOIN
|
||||||
|
(
|
||||||
|
t6,
|
||||||
|
t7
|
||||||
|
LEFT JOIN
|
||||||
|
t8
|
||||||
|
ON t7.b=t8.b AND t6.b < 10
|
||||||
|
)
|
||||||
|
ON t6.b >= 2 AND t5.b=t7.b
|
||||||
|
WHERE t2.a > 3 AND
|
||||||
|
(t6.a < 6 OR t6.c IS NULL);
|
||||||
|
|
||||||
|
SELECT t1.a,t1.b
|
||||||
|
FROM t1;
|
||||||
|
|
||||||
|
SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
|
||||||
|
t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
|
||||||
|
FROM t1
|
||||||
|
LEFT JOIN
|
||||||
|
(
|
||||||
|
t2
|
||||||
|
LEFT JOIN
|
||||||
|
(t3, t4)
|
||||||
|
ON t3.a=1 AND t2.b=t4.b,
|
||||||
|
t5
|
||||||
|
LEFT JOIN
|
||||||
|
(
|
||||||
|
t6,
|
||||||
|
t7
|
||||||
|
LEFT JOIN
|
||||||
|
t8
|
||||||
|
ON t7.b=t8.b AND t6.b < 10
|
||||||
|
)
|
||||||
|
ON t6.b >= 2 AND t5.b=t7.b
|
||||||
|
)
|
||||||
|
ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
|
||||||
|
(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
|
||||||
|
(t1.a != 2);
|
||||||
|
|
||||||
|
SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
|
||||||
|
t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
|
||||||
|
FROM t1
|
||||||
|
LEFT JOIN
|
||||||
|
(
|
||||||
|
t2
|
||||||
|
LEFT JOIN
|
||||||
|
(t3, t4)
|
||||||
|
ON t3.a=1 AND t2.b=t4.b,
|
||||||
|
t5
|
||||||
|
LEFT JOIN
|
||||||
|
(
|
||||||
|
t6,
|
||||||
|
t7
|
||||||
|
LEFT JOIN
|
||||||
|
t8
|
||||||
|
ON t7.b=t8.b AND t6.b < 10
|
||||||
|
)
|
||||||
|
ON t6.b >= 2 AND t5.b=t7.b
|
||||||
|
)
|
||||||
|
ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
|
||||||
|
(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
|
||||||
|
(t1.a != 2)
|
||||||
|
WHERE (t2.a >= 4 OR t2.c IS NULL);
|
||||||
|
|
||||||
|
SELECT t0.a,t0.b
|
||||||
|
FROM t0;
|
||||||
|
|
||||||
|
EXPLAIN
|
||||||
|
SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
|
||||||
|
t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
|
||||||
|
FROM t0,t1
|
||||||
|
LEFT JOIN
|
||||||
|
(
|
||||||
|
t2
|
||||||
|
LEFT JOIN
|
||||||
|
(t3, t4)
|
||||||
|
ON t3.a=1 AND t2.b=t4.b,
|
||||||
|
t5
|
||||||
|
LEFT JOIN
|
||||||
|
(
|
||||||
|
t6,
|
||||||
|
t7
|
||||||
|
LEFT JOIN
|
||||||
|
t8
|
||||||
|
ON t7.b=t8.b AND t6.b < 10
|
||||||
|
)
|
||||||
|
ON t6.b >= 2 AND t5.b=t7.b
|
||||||
|
)
|
||||||
|
ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
|
||||||
|
(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
|
||||||
|
(t1.a != 2)
|
||||||
|
WHERE t0.a=1 AND
|
||||||
|
t0.b=t1.b AND
|
||||||
|
(t2.a >= 4 OR t2.c IS NULL);
|
||||||
|
|
||||||
|
SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
|
||||||
|
t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b
|
||||||
|
FROM t0,t1
|
||||||
|
LEFT JOIN
|
||||||
|
(
|
||||||
|
t2
|
||||||
|
LEFT JOIN
|
||||||
|
(t3, t4)
|
||||||
|
ON t3.a=1 AND t2.b=t4.b,
|
||||||
|
t5
|
||||||
|
LEFT JOIN
|
||||||
|
(
|
||||||
|
t6,
|
||||||
|
t7
|
||||||
|
LEFT JOIN
|
||||||
|
t8
|
||||||
|
ON t7.b=t8.b AND t6.b < 10
|
||||||
|
)
|
||||||
|
ON t6.b >= 2 AND t5.b=t7.b
|
||||||
|
)
|
||||||
|
ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
|
||||||
|
(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
|
||||||
|
(t1.a != 2)
|
||||||
|
WHERE t0.a=1 AND
|
||||||
|
t0.b=t1.b AND
|
||||||
|
(t2.a >= 4 OR t2.c IS NULL);
|
||||||
|
|
||||||
|
EXPLAIN
|
||||||
|
SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
|
||||||
|
t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
|
||||||
|
FROM t0,t1
|
||||||
|
LEFT JOIN
|
||||||
|
(
|
||||||
|
t2
|
||||||
|
LEFT JOIN
|
||||||
|
(t3, t4)
|
||||||
|
ON t3.a=1 AND t2.b=t4.b,
|
||||||
|
t5
|
||||||
|
LEFT JOIN
|
||||||
|
(
|
||||||
|
t6,
|
||||||
|
t7
|
||||||
|
LEFT JOIN
|
||||||
|
t8
|
||||||
|
ON t7.b=t8.b AND t6.b < 10
|
||||||
|
)
|
||||||
|
ON t6.b >= 2 AND t5.b=t7.b
|
||||||
|
)
|
||||||
|
ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
|
||||||
|
(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
|
||||||
|
(t1.a != 2),
|
||||||
|
t9
|
||||||
|
WHERE t0.a=1 AND
|
||||||
|
t0.b=t1.b AND
|
||||||
|
(t2.a >= 4 OR t2.c IS NULL) AND
|
||||||
|
(t3.a < 5 OR t3.c IS NULL) AND
|
||||||
|
(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
|
||||||
|
(t5.a >=2 OR t5.c IS NULL) AND
|
||||||
|
(t6.a >=4 OR t6.c IS NULL) AND
|
||||||
|
(t7.a <= 2 OR t7.c IS NULL) AND
|
||||||
|
(t8.a < 1 OR t8.c IS NULL) AND
|
||||||
|
(t8.b=t9.b OR t8.c IS NULL) AND
|
||||||
|
(t9.a=1);
|
||||||
|
|
||||||
|
SELECT t9.a,t9.b
|
||||||
|
FROM t9;
|
||||||
|
|
||||||
|
SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
|
||||||
|
t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
|
||||||
|
FROM t0,t1
|
||||||
|
LEFT JOIN
|
||||||
|
(
|
||||||
|
t2
|
||||||
|
LEFT JOIN
|
||||||
|
(t3, t4)
|
||||||
|
ON t3.a=1 AND t2.b=t4.b,
|
||||||
|
t5
|
||||||
|
LEFT JOIN
|
||||||
|
(
|
||||||
|
t6,
|
||||||
|
t7
|
||||||
|
LEFT JOIN
|
||||||
|
t8
|
||||||
|
ON t7.b=t8.b AND t6.b < 10
|
||||||
|
)
|
||||||
|
ON t6.b >= 2 AND t5.b=t7.b
|
||||||
|
)
|
||||||
|
ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
|
||||||
|
(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
|
||||||
|
(t1.a != 2),
|
||||||
|
t9
|
||||||
|
WHERE t0.a=1 AND
|
||||||
|
t0.b=t1.b AND
|
||||||
|
(t2.a >= 4 OR t2.c IS NULL) AND
|
||||||
|
(t3.a < 5 OR t3.c IS NULL) AND
|
||||||
|
(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
|
||||||
|
(t5.a >=2 OR t5.c IS NULL) AND
|
||||||
|
(t6.a >=4 OR t6.c IS NULL) AND
|
||||||
|
(t7.a <= 2 OR t7.c IS NULL) AND
|
||||||
|
(t8.a < 1 OR t8.c IS NULL) AND
|
||||||
|
(t8.b=t9.b OR t8.c IS NULL) AND
|
||||||
|
(t9.a=1);
|
||||||
|
|
||||||
|
SELECT t1.a,t1.b
|
||||||
|
FROM t1;
|
||||||
|
|
||||||
|
SELECT t2.a,t2.b
|
||||||
|
FROM t2;
|
||||||
|
|
||||||
|
SELECT t3.a,t3.b
|
||||||
|
FROM t3;
|
||||||
|
|
||||||
|
SELECT t2.a,t2.b,t3.a,t3.b
|
||||||
|
FROM t2
|
||||||
|
LEFT JOIN
|
||||||
|
t3
|
||||||
|
ON t2.b=t3.b;
|
||||||
|
|
||||||
|
SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b
|
||||||
|
FROM t1, t2
|
||||||
|
LEFT JOIN
|
||||||
|
t3
|
||||||
|
ON t2.b=t3.b
|
||||||
|
WHERE t1.a <= 2;
|
||||||
|
|
||||||
|
SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b
|
||||||
|
FROM t1, t3
|
||||||
|
RIGHT JOIN
|
||||||
|
t2
|
||||||
|
ON t2.b=t3.b
|
||||||
|
WHERE t1.a <= 2;
|
||||||
|
|
||||||
|
SELECT t3.a,t3.b,t4.a,t4.b
|
||||||
|
FROM t3,t4;
|
||||||
|
|
||||||
|
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
|
||||||
|
FROM t2
|
||||||
|
LEFT JOIN
|
||||||
|
(t3, t4)
|
||||||
|
ON t3.a=1 AND t2.b=t4.b;
|
||||||
|
|
||||||
|
SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
|
||||||
|
FROM t1, t2
|
||||||
|
LEFT JOIN
|
||||||
|
(t3, t4)
|
||||||
|
ON t3.a=1 AND t2.b=t4.b
|
||||||
|
WHERE t1.a <= 2;
|
||||||
|
|
||||||
|
SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
|
||||||
|
FROM t1, (t3, t4)
|
||||||
|
RIGHT JOIN
|
||||||
|
t2
|
||||||
|
ON t3.a=1 AND t2.b=t4.b
|
||||||
|
WHERE t1.a <= 2;
|
||||||
|
|
||||||
|
SELECT t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
|
||||||
|
FROM t1, t3, t4
|
||||||
|
RIGHT JOIN
|
||||||
|
t2
|
||||||
|
ON t3.a=1 AND t2.b=t4.b
|
||||||
|
WHERE t1.a <= 2;
|
||||||
|
|
||||||
|
CREATE INDEX idx_b ON t2(b);
|
||||||
|
|
||||||
|
EXPLAIN
|
||||||
|
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
|
||||||
|
FROM t3,t4
|
||||||
|
LEFT JOIN
|
||||||
|
(t1,t2)
|
||||||
|
ON t3.a=1 AND t3.b=t2.b AND t2.b=t4.b;
|
||||||
|
|
||||||
|
SELECT t2.a,t2.b,t3.a,t3.b,t4.a,t4.b
|
||||||
|
FROM t3,t4
|
||||||
|
LEFT JOIN
|
||||||
|
(t1,t2)
|
||||||
|
ON t3.a=1 AND t3.b=t2.b AND t2.b=t4.b;
|
||||||
|
|
||||||
|
EXPLAIN
|
||||||
|
SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
|
||||||
|
t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
|
||||||
|
FROM t0,t1
|
||||||
|
LEFT JOIN
|
||||||
|
(
|
||||||
|
t2
|
||||||
|
LEFT JOIN
|
||||||
|
(t3, t4)
|
||||||
|
ON t3.a=1 AND t2.b=t4.b,
|
||||||
|
t5
|
||||||
|
LEFT JOIN
|
||||||
|
(
|
||||||
|
t6,
|
||||||
|
t7
|
||||||
|
LEFT JOIN
|
||||||
|
t8
|
||||||
|
ON t7.b=t8.b AND t6.b < 10
|
||||||
|
)
|
||||||
|
ON t6.b >= 2 AND t5.b=t7.b
|
||||||
|
)
|
||||||
|
ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
|
||||||
|
(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
|
||||||
|
(t1.a != 2),
|
||||||
|
t9
|
||||||
|
WHERE t0.a=1 AND
|
||||||
|
t0.b=t1.b AND
|
||||||
|
(t2.a >= 4 OR t2.c IS NULL) AND
|
||||||
|
(t3.a < 5 OR t3.c IS NULL) AND
|
||||||
|
(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
|
||||||
|
(t5.a >=2 OR t5.c IS NULL) AND
|
||||||
|
(t6.a >=4 OR t6.c IS NULL) AND
|
||||||
|
(t7.a <= 2 OR t7.c IS NULL) AND
|
||||||
|
(t8.a < 1 OR t8.c IS NULL) AND
|
||||||
|
(t8.b=t9.b OR t8.c IS NULL) AND
|
||||||
|
(t9.a=1);
|
||||||
|
|
||||||
|
CREATE INDEX idx_b ON t4(b);
|
||||||
|
CREATE INDEX idx_b ON t5(b);
|
||||||
|
|
||||||
|
EXPLAIN
|
||||||
|
SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
|
||||||
|
t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
|
||||||
|
FROM t0,t1
|
||||||
|
LEFT JOIN
|
||||||
|
(
|
||||||
|
t2
|
||||||
|
LEFT JOIN
|
||||||
|
(t3, t4)
|
||||||
|
ON t3.a=1 AND t2.b=t4.b,
|
||||||
|
t5
|
||||||
|
LEFT JOIN
|
||||||
|
(
|
||||||
|
t6,
|
||||||
|
t7
|
||||||
|
LEFT JOIN
|
||||||
|
t8
|
||||||
|
ON t7.b=t8.b AND t6.b < 10
|
||||||
|
)
|
||||||
|
ON t6.b >= 2 AND t5.b=t7.b
|
||||||
|
)
|
||||||
|
ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
|
||||||
|
(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
|
||||||
|
(t1.a != 2),
|
||||||
|
t9
|
||||||
|
WHERE t0.a=1 AND
|
||||||
|
t0.b=t1.b AND
|
||||||
|
(t2.a >= 4 OR t2.c IS NULL) AND
|
||||||
|
(t3.a < 5 OR t3.c IS NULL) AND
|
||||||
|
(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
|
||||||
|
(t5.a >=2 OR t5.c IS NULL) AND
|
||||||
|
(t6.a >=4 OR t6.c IS NULL) AND
|
||||||
|
(t7.a <= 2 OR t7.c IS NULL) AND
|
||||||
|
(t8.a < 1 OR t8.c IS NULL) AND
|
||||||
|
(t8.b=t9.b OR t8.c IS NULL) AND
|
||||||
|
(t9.a=1);
|
||||||
|
|
||||||
|
CREATE INDEX idx_b ON t8(b);
|
||||||
|
|
||||||
|
EXPLAIN
|
||||||
|
SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
|
||||||
|
t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
|
||||||
|
FROM t0,t1
|
||||||
|
LEFT JOIN
|
||||||
|
(
|
||||||
|
t2
|
||||||
|
LEFT JOIN
|
||||||
|
(t3, t4)
|
||||||
|
ON t3.a=1 AND t2.b=t4.b,
|
||||||
|
t5
|
||||||
|
LEFT JOIN
|
||||||
|
(
|
||||||
|
t6,
|
||||||
|
t7
|
||||||
|
LEFT JOIN
|
||||||
|
t8
|
||||||
|
ON t7.b=t8.b AND t6.b < 10
|
||||||
|
)
|
||||||
|
ON t6.b >= 2 AND t5.b=t7.b
|
||||||
|
)
|
||||||
|
ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
|
||||||
|
(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
|
||||||
|
(t1.a != 2),
|
||||||
|
t9
|
||||||
|
WHERE t0.a=1 AND
|
||||||
|
t0.b=t1.b AND
|
||||||
|
(t2.a >= 4 OR t2.c IS NULL) AND
|
||||||
|
(t3.a < 5 OR t3.c IS NULL) AND
|
||||||
|
(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
|
||||||
|
(t5.a >=2 OR t5.c IS NULL) AND
|
||||||
|
(t6.a >=4 OR t6.c IS NULL) AND
|
||||||
|
(t7.a <= 2 OR t7.c IS NULL) AND
|
||||||
|
(t8.a < 1 OR t8.c IS NULL) AND
|
||||||
|
(t8.b=t9.b OR t8.c IS NULL) AND
|
||||||
|
(t9.a=1);
|
||||||
|
|
||||||
|
CREATE INDEX idx_b ON t1(b);
|
||||||
|
CREATE INDEX idx_a ON t0(a);
|
||||||
|
|
||||||
|
EXPLAIN
|
||||||
|
SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
|
||||||
|
t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
|
||||||
|
FROM t0,t1
|
||||||
|
LEFT JOIN
|
||||||
|
(
|
||||||
|
t2
|
||||||
|
LEFT JOIN
|
||||||
|
(t3, t4)
|
||||||
|
ON t3.a=1 AND t2.b=t4.b,
|
||||||
|
t5
|
||||||
|
LEFT JOIN
|
||||||
|
(
|
||||||
|
t6,
|
||||||
|
t7
|
||||||
|
LEFT JOIN
|
||||||
|
t8
|
||||||
|
ON t7.b=t8.b AND t6.b < 10
|
||||||
|
)
|
||||||
|
ON t6.b >= 2 AND t5.b=t7.b
|
||||||
|
)
|
||||||
|
ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
|
||||||
|
(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
|
||||||
|
(t1.a != 2),
|
||||||
|
t9
|
||||||
|
WHERE t0.a=1 AND
|
||||||
|
t0.b=t1.b AND
|
||||||
|
(t2.a >= 4 OR t2.c IS NULL) AND
|
||||||
|
(t3.a < 5 OR t3.c IS NULL) AND
|
||||||
|
(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
|
||||||
|
(t5.a >=2 OR t5.c IS NULL) AND
|
||||||
|
(t6.a >=4 OR t6.c IS NULL) AND
|
||||||
|
(t7.a <= 2 OR t7.c IS NULL) AND
|
||||||
|
(t8.a < 1 OR t8.c IS NULL) AND
|
||||||
|
(t8.b=t9.b OR t8.c IS NULL) AND
|
||||||
|
(t9.a=1);
|
||||||
|
|
||||||
|
SELECT t0.a,t0.b,t1.a,t1.b,t2.a,t2.b,t3.a,t3.b,t4.a,t4.b,
|
||||||
|
t5.a,t5.b,t6.a,t6.b,t7.a,t7.b,t8.a,t8.b,t9.a,t9.b
|
||||||
|
FROM t0,t1
|
||||||
|
LEFT JOIN
|
||||||
|
(
|
||||||
|
t2
|
||||||
|
LEFT JOIN
|
||||||
|
(t3, t4)
|
||||||
|
ON t3.a=1 AND t2.b=t4.b,
|
||||||
|
t5
|
||||||
|
LEFT JOIN
|
||||||
|
(
|
||||||
|
t6,
|
||||||
|
t7
|
||||||
|
LEFT JOIN
|
||||||
|
t8
|
||||||
|
ON t7.b=t8.b AND t6.b < 10
|
||||||
|
)
|
||||||
|
ON t6.b >= 2 AND t5.b=t7.b
|
||||||
|
)
|
||||||
|
ON (t3.b=2 OR t3.c IS NULL) AND (t6.b=2 OR t6.c IS NULL) AND
|
||||||
|
(t1.b=t5.b OR t3.c IS NULL OR t6.c IS NULL or t8.c IS NULL) AND
|
||||||
|
(t1.a != 2),
|
||||||
|
t9
|
||||||
|
WHERE t0.a=1 AND
|
||||||
|
t0.b=t1.b AND
|
||||||
|
(t2.a >= 4 OR t2.c IS NULL) AND
|
||||||
|
(t3.a < 5 OR t3.c IS NULL) AND
|
||||||
|
(t3.b=t4.b OR t3.c IS NULL OR t4.c IS NULL) AND
|
||||||
|
(t5.a >=2 OR t5.c IS NULL) AND
|
||||||
|
(t6.a >=4 OR t6.c IS NULL) AND
|
||||||
|
(t7.a <= 2 OR t7.c IS NULL) AND
|
||||||
|
(t8.a < 1 OR t8.c IS NULL) AND
|
||||||
|
(t8.b=t9.b OR t8.c IS NULL) AND
|
||||||
|
(t9.a=1);
|
||||||
|
|
||||||
|
SELECT t2.a,t2.b
|
||||||
|
FROM t2;
|
||||||
|
|
||||||
|
SELECT t3.a,t3.b
|
||||||
|
FROM t3;
|
||||||
|
|
||||||
|
SELECT t2.a,t2.b,t3.a,t3.b
|
||||||
|
FROM t2 LEFT JOIN t3 ON t2.b=t3.b
|
||||||
|
WHERE t2.a = 4 OR (t2.a > 4 AND t3.a IS NULL);
|
||||||
|
|
||||||
|
SELECT t2.a,t2.b,t3.a,t3.b
|
||||||
|
FROM t2 LEFT JOIN (t3) ON t2.b=t3.b
|
||||||
|
WHERE t2.a = 4 OR (t2.a > 4 AND t3.a IS NULL);
|
||||||
|
|
||||||
|
ALTER TABLE t3
|
||||||
|
CHANGE COLUMN a a1 int,
|
||||||
|
CHANGE COLUMN c c1 int;
|
||||||
|
|
||||||
|
SELECT t2.a,t2.b,t3.a1,t3.b
|
||||||
|
FROM t2 LEFT JOIN t3 ON t2.b=t3.b
|
||||||
|
WHERE t2.a = 4 OR (t2.a > 4 AND t3.a1 IS NULL);
|
||||||
|
|
||||||
|
SELECT t2.a,t2.b,t3.a1,t3.b
|
||||||
|
FROM t2 NATURAL LEFT JOIN t3
|
||||||
|
WHERE t2.a = 4 OR (t2.a > 4 AND t3.a1 IS NULL);
|
||||||
|
|
||||||
|
DROP TABLE t0,t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
|
@ -233,6 +233,40 @@ public:
|
||||||
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 @@ public:
|
||||||
}
|
}
|
||||||
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; }
|
||||||
|
|
|
@ -47,7 +47,8 @@ public:
|
||||||
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; }
|
||||||
|
|
659
sql/sql_base.cc
659
sql/sql_base.cc
|
@ -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)
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
/* 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,
|
||||||
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,12 +808,8 @@ 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,
|
||||||
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)
|
||||||
*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,
|
||||||
{
|
{
|
||||||
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,
|
||||||
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
|
int open_tables(THD *thd,TABLE_LIST *start)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
TABLE_LIST *tables;
|
TABLE_LIST *tables;
|
||||||
bool refresh;
|
bool refresh;
|
||||||
|
@ -1455,22 +1369,14 @@ 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)))
|
||||||
{
|
{
|
||||||
if (refresh) // Refresh in progress
|
if (refresh) // Refresh in progress
|
||||||
{
|
{
|
||||||
|
@ -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.
|
The lock will automaticly be freed by close_thread_tables()
|
||||||
|
|
||||||
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)
|
int open_and_lock_tables(THD *thd,TABLE_LIST *tables)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("simple_open_n_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 */
|
|
||||||
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()
|
|
||||||
*/
|
|
||||||
|
|
||||||
int open_and_lock_tables(THD *thd, TABLE_LIST *tables)
|
|
||||||
{
|
|
||||||
DBUG_ENTER("open_and_lock_tables");
|
|
||||||
uint counter;
|
|
||||||
if (open_tables(thd, tables, &counter) || lock_tables(thd, tables, counter))
|
|
||||||
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)
|
||||||
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)
|
||||||
-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)
|
||||||
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)
|
||||||
{
|
*(ptr++)= table->table;
|
||||||
if (!table->derived)
|
|
||||||
*(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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
*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)
|
||||||
#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 (!my_strcasecmp(system_charset_info, field->field_name, name))
|
||||||
}
|
goto found;
|
||||||
|
}
|
||||||
if (field_ptr && *field_ptr)
|
|
||||||
{
|
|
||||||
*cached_field_index_ptr= field_ptr - table->field;
|
|
||||||
field= *field_ptr;
|
|
||||||
}
|
|
||||||
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,
|
||||||
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 scanning
|
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,
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
{
|
{
|
||||||
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,
|
||||||
{
|
{
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,23 +2039,12 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
prepare tables
|
Remap table numbers if INSERT ... SELECT
|
||||||
|
Check also that the 'used keys' and 'ignored keys' exists and set up the
|
||||||
|
table structure accordingly
|
||||||
|
|
||||||
SYNOPSIS
|
This has to be called for all tables that are used by items, as otherwise
|
||||||
setup_tables()
|
table->map is not set and all Item_field will be regarded as const items.
|
||||||
tables - tables list
|
|
||||||
|
|
||||||
RETURN
|
|
||||||
0 ok; In this case *map will includes the choosed index
|
|
||||||
1 error
|
|
||||||
|
|
||||||
NOTE
|
|
||||||
Remap table numbers if INSERT ... SELECT
|
|
||||||
Check also that the 'used keys' and 'ignored keys' exists and set up the
|
|
||||||
table structure accordingly
|
|
||||||
|
|
||||||
This has to be called for all tables that are used by items, as otherwise
|
|
||||||
table->map is not set and all Item_field will be regarded as const items.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool setup_tables(TABLE_LIST *tables)
|
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,
|
||||||
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 (!found++)
|
||||||
if (!natural_join_table ||
|
(void) it->replace(item); // Replace '*'
|
||||||
!find_field_in_table(thd, natural_join_table, field->field_name,
|
else
|
||||||
strlen(field->field_name), 0, 0,
|
it->after(item);
|
||||||
¬_used_field_index))
|
|
||||||
{
|
|
||||||
Item_field *item= new Item_field(thd, field);
|
|
||||||
if (!found++)
|
|
||||||
(void) it->replace(item); // Replace '*'
|
|
||||||
else
|
|
||||||
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,
|
||||||
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;
|
||||||
/* Make a join an a expression */
|
do
|
||||||
thd->where="on clause";
|
{
|
||||||
|
embedded= embedding;
|
||||||
if (!table->on_expr->fixed &&
|
if (embedded->on_expr)
|
||||||
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;
|
/* Make a join an a expression */
|
||||||
if (arena)
|
thd->where="on clause";
|
||||||
thd->set_n_backup_item_arena(arena, &backup);
|
if (embedded->on_expr->fix_fields(thd, tables, &embedded->on_expr) ||
|
||||||
*conds= and_conds(*conds, table->on_expr);
|
embedded->on_expr->check_cols(1))
|
||||||
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 */
|
|
||||||
TABLE *t1= table->table;
|
|
||||||
TABLE *t2= table->natural_join->table;
|
|
||||||
Item_cond_and *cond_and= new Item_cond_and();
|
|
||||||
if (!cond_and) // If not out of memory
|
|
||||||
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;
|
/* Make a join of all fields with have the same name */
|
||||||
uint not_used_field_index= NO_CACHED_FIELD_INDEX;
|
TABLE_LIST *tab1= embedded;
|
||||||
|
TABLE_LIST *tab2= embedded->natural_join;
|
||||||
if ((t2_field= find_field_in_table(thd, t2, t1_field_name,
|
if (!(embedded->outer_join & JOIN_TYPE_RIGHT))
|
||||||
strlen(t1_field_name), 0, 0,
|
|
||||||
¬_used_field_index)))
|
|
||||||
{
|
{
|
||||||
Item_func_eq *tmp=new Item_func_eq(new Item_field(*t1_field),
|
while (tab1->nested_join)
|
||||||
new Item_field(t2_field));
|
{
|
||||||
if (!tmp)
|
TABLE_LIST *next;
|
||||||
goto err;
|
List_iterator_fast<TABLE_LIST> it(tab1->nested_join->join_list);
|
||||||
/* Mark field used for table cache */
|
tab1= it++;
|
||||||
(*t1_field)->query_id= t2_field->query_id= thd->query_id;
|
while ((next= it++))
|
||||||
cond_and->list.push_back(tmp);
|
tab1= next;
|
||||||
t1->used_keys.intersect((*t1_field)->part_of_key);
|
}
|
||||||
t2->used_keys.intersect(t2_field->part_of_key);
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
select_lex->cond_count+= cond_and->list.elements;
|
{
|
||||||
|
while (tab1->nested_join)
|
||||||
|
tab1= tab1->nested_join->join_list.head();
|
||||||
|
}
|
||||||
|
if (embedded->outer_join & JOIN_TYPE_RIGHT)
|
||||||
|
{
|
||||||
|
while (tab2->nested_join)
|
||||||
|
{
|
||||||
|
TABLE_LIST *next;
|
||||||
|
List_iterator_fast<TABLE_LIST> it(tab2->nested_join->join_list);
|
||||||
|
tab2= it++;
|
||||||
|
while ((next= it++))
|
||||||
|
tab2= next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (tab2->nested_join)
|
||||||
|
tab2= tab2->nested_join->join_list.head();
|
||||||
|
}
|
||||||
|
TABLE *t1=tab1->table;
|
||||||
|
TABLE *t2=tab2->table;
|
||||||
|
Item_cond_and *cond_and=new Item_cond_and();
|
||||||
|
if (!cond_and) // If not out of memory
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
cond_and->top_level_item();
|
||||||
|
|
||||||
// to prevent natural join processing during PS re-execution
|
uint i,j;
|
||||||
table->natural_join= 0;
|
for (i=0 ; i < t1->fields ; i++)
|
||||||
|
{
|
||||||
if (!table->outer_join) // Not left join
|
// TODO: This could be optimized to use hashed names if t2 had a hash
|
||||||
{
|
for (j=0 ; j < t2->fields ; j++)
|
||||||
*conds= and_conds(*conds, cond_and);
|
{
|
||||||
// fix_fields() should be made with temporary memory pool
|
if (!my_strcasecmp(system_charset_info,
|
||||||
if (arena)
|
t1->field[i]->field_name,
|
||||||
thd->restore_backup_item_arena(arena, &backup);
|
t2->field[j]->field_name))
|
||||||
if (*conds && !(*conds)->fixed)
|
{
|
||||||
{
|
Item_func_eq *tmp=new Item_func_eq(new Item_field(t1->field[i]),
|
||||||
if ((*conds)->fix_fields(thd, tables, conds))
|
new Item_field(t2->field[j]));
|
||||||
|
if (!tmp)
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
tmp->fix_length_and_dec(); // Update cmp_type
|
||||||
|
tmp->const_item_cache=0;
|
||||||
|
/* Mark field used for table cache */
|
||||||
|
t1->field[i]->query_id=t2->field[j]->query_id=thd->query_id;
|
||||||
|
cond_and->list.push_back(tmp);
|
||||||
|
t1->used_keys.intersect(t1->field[i]->part_of_key);
|
||||||
|
t2->used_keys.intersect(t2->field[j]->part_of_key);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cond_and->used_tables_cache= t1->map | t2->map;
|
||||||
|
thd->lex->current_select->cond_count+= cond_and->list.elements;
|
||||||
|
COND *on_expr= cond_and;
|
||||||
|
on_expr->fix_fields(thd, 0, &on_expr);
|
||||||
|
if (!embedded->outer_join) // Not left join
|
||||||
|
{
|
||||||
|
if (!(*conds=and_conds(*conds, on_expr)))
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else
|
embedded->on_expr=and_conds(embedded->on_expr,on_expr);
|
||||||
{
|
|
||||||
table->on_expr= and_conds(table->on_expr, cond_and);
|
|
||||||
// fix_fields() should be made with temporary memory pool
|
|
||||||
if (arena)
|
|
||||||
thd->restore_backup_item_arena(arena, &backup);
|
|
||||||
if (table->on_expr && !table->on_expr->fixed)
|
|
||||||
{
|
|
||||||
if (table->on_expr->fix_fields(thd, tables, &table->on_expr))
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
embedding= embedded->embedding;
|
||||||
}
|
}
|
||||||
}
|
while (embedding &&
|
||||||
|
embedding->nested_join->join_list.head() == embedded);
|
||||||
if (arena)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
We are in prepared statement preparation code => we should store
|
|
||||||
WHERE clause changing for next executions.
|
|
||||||
|
|
||||||
We do this ON -> WHERE transformation only once per PS/SP statement.
|
|
||||||
*/
|
|
||||||
select_lex->where= *conds;
|
|
||||||
select_lex->conds_processed_with_permanent_arena= 1;
|
|
||||||
}
|
}
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
/* 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
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,
|
||||||
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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -416,7 +416,10 @@ public:
|
||||||
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 */
|
||||||
const char *type; /* type of select for EXPLAIN */
|
List<TABLE_LIST> top_join_list; /* join list of the top level */
|
||||||
|
List<TABLE_LIST> *join_list; /* list for the currently parsed join */
|
||||||
|
TABLE_LIST *embedding; /* table embedding to the above list */
|
||||||
|
const char *type; /* type of select for EXPLAIN */
|
||||||
|
|
||||||
SQL_LIST order_list; /* ORDER clause */
|
SQL_LIST order_list; /* ORDER clause */
|
||||||
List<List_item> expr_list;
|
List<List_item> expr_list;
|
||||||
|
@ -513,6 +516,12 @@ public:
|
||||||
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();
|
||||||
|
|
231
sql/sql_parse.cc
231
sql/sql_parse.cc
|
@ -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
|
||||||
|
|
||||||
|
|
2836
sql/sql_select.cc
2836
sql/sql_select.cc
File diff suppressed because it is too large
Load diff
|
@ -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 {
|
||||||
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
|
||||||
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
|
||||||
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
|
||||||
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;
|
||||||
|
|
56
sql/table.h
56
sql/table.h
|
@ -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 {
|
||||||
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 {
|
||||||
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 {
|
||||||
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;
|
||||||
|
@ -133,7 +119,7 @@ struct st_table {
|
||||||
my_bool is_view;
|
my_bool is_view;
|
||||||
my_bool no_keyread, no_cache;
|
my_bool no_keyread, no_cache;
|
||||||
my_bool clear_query_id; /* To reset query_id for tables and cols */
|
my_bool clear_query_id; /* To reset query_id for tables and cols */
|
||||||
my_bool auto_increment_field_not_null;
|
my_bool auto_increment_field_not_null;
|
||||||
Field *next_number_field, /* Set if next_number is activated */
|
Field *next_number_field, /* Set if next_number is activated */
|
||||||
*found_next_number_field, /* Set on open */
|
*found_next_number_field, /* Set on open */
|
||||||
*rowid_field;
|
*rowid_field;
|
||||||
|
@ -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;
|
||||||
|
uint temp_pool_slot; /* Used by intern temp tables */
|
||||||
union /* Temporary variables */
|
struct st_table_list *pos_in_table_list;/* Element referring to this table */
|
||||||
{
|
|
||||||
uint temp_pool_slot; /* Used by intern temp tables */
|
|
||||||
struct st_table_list *pos_in_table_list;
|
|
||||||
};
|
|
||||||
/* 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
|
||||||
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
|
||||||
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;
|
||||||
|
|
Loading…
Reference in a new issue