summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/create.result2
-rw-r--r--mysql-test/r/delete.result4
-rw-r--r--mysql-test/r/func_gconcat.result4
-rw-r--r--mysql-test/r/func_group.result16
-rw-r--r--mysql-test/r/func_str.result35
-rw-r--r--mysql-test/r/group_by.result4
-rw-r--r--mysql-test/r/heap_hash.result2
-rw-r--r--mysql-test/r/information_schema.result2
-rw-r--r--mysql-test/r/innodb_mysql.result8
-rw-r--r--mysql-test/r/join_outer.result2
-rw-r--r--mysql-test/r/olap.result2
-rw-r--r--mysql-test/r/range.result8
-rw-r--r--mysql-test/r/row.result125
-rw-r--r--mysql-test/r/subselect.result29
-rw-r--r--mysql-test/r/union.result2
-rw-r--r--mysql-test/r/view.result51
-rw-r--r--mysql-test/r/view_grant.result6
-rw-r--r--mysql-test/t/create.test6
-rw-r--r--mysql-test/t/delete.test10
-rw-r--r--mysql-test/t/func_group.test13
-rw-r--r--mysql-test/t/func_str.test27
-rw-r--r--mysql-test/t/row.test47
-rw-r--r--mysql-test/t/subselect.test26
-rw-r--r--mysql-test/t/view.test16
-rw-r--r--sql/item.cc41
-rw-r--r--sql/item.h45
-rw-r--r--sql/item_cmpfunc.cc61
-rw-r--r--sql/item_cmpfunc.h4
-rw-r--r--sql/item_func.cc64
-rw-r--r--sql/item_func.h2
-rw-r--r--sql/mysql_priv.h1
-rw-r--r--sql/opt_sum.cc4
-rw-r--r--sql/sql_list.h6
-rw-r--r--sql/sql_parse.cc4
-rw-r--r--sql/sql_select.cc505
-rw-r--r--sql/sql_yacc.yy150
36 files changed, 1034 insertions, 300 deletions
diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result
index 3f8083a0e20..5f885ad199b 100644
--- a/mysql-test/r/create.result
+++ b/mysql-test/r/create.result
@@ -773,3 +773,5 @@ Warnings:
Warning 1071 Specified key was too long; max key length is 765 bytes
insert into t1 values('aaa');
drop table t1;
+create table t1 (upgrade int);
+drop table t1;
diff --git a/mysql-test/r/delete.result b/mysql-test/r/delete.result
index 0946dc8f809..9d337a1ed34 100644
--- a/mysql-test/r/delete.result
+++ b/mysql-test/r/delete.result
@@ -172,6 +172,10 @@ a
0
2
DROP TABLE t1;
+create table t1 (a int);
+delete `4.t1` from t1 as `4.t1` where `4.t1`.a = 5;
+delete FROM `4.t1` USING t1 as `4.t1` where `4.t1`.a = 5;
+drop table t1;
CREATE TABLE t1 (a int not null,b int not null);
CREATE TABLE t2 (a int not null, b int not null, primary key (a,b));
CREATE TABLE t3 (a int not null, b int not null, primary key (a,b));
diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result
index dc09a68682c..6617ccc671e 100644
--- a/mysql-test/r/func_gconcat.result
+++ b/mysql-test/r/func_gconcat.result
@@ -566,14 +566,14 @@ COUNT(*) GROUP_CONCAT(DISTINCT t2.somename SEPARATOR ' |')
DROP TABLE t1,t2;
select * from (select group_concat('c') from DUAL) t;
group_concat('c')
-NULL
+c
create table t1 ( a int not null default 0);
select * from (select group_concat(a) from t1) t2;
group_concat(a)
NULL
select group_concat('x') UNION ALL select 1;
group_concat('x')
-NULL
+x
1
drop table t1;
CREATE TABLE t1 (id int, a varchar(9));
diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result
index f57b4ad6ce9..98eb9e9e2b3 100644
--- a/mysql-test/r/func_group.result
+++ b/mysql-test/r/func_group.result
@@ -856,6 +856,22 @@ EXPLAIN SELECT MAX(b) FROM t1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 4
DROP TABLE t1;
+CREATE TABLE t1 (a INT, b INT);
+INSERT INTO t1 VALUES (1,1),(1,2),(2,3);
+SELECT (SELECT COUNT(DISTINCT t1.b)) FROM t1 GROUP BY t1.a;
+(SELECT COUNT(DISTINCT t1.b))
+0
+2
+SELECT (SELECT COUNT(DISTINCT 12)) FROM t1 GROUP BY t1.a;
+(SELECT COUNT(DISTINCT 12))
+1
+1
+SELECT AVG(2), BIT_AND(2), BIT_OR(2), BIT_XOR(2), COUNT(*), COUNT(12),
+COUNT(DISTINCT 12), MIN(2),MAX(2),STD(2), VARIANCE(2),SUM(2),
+GROUP_CONCAT(2),GROUP_CONCAT(DISTINCT 2);
+AVG(2) BIT_AND(2) BIT_OR(2) BIT_XOR(2) COUNT(*) COUNT(12) COUNT(DISTINCT 12) MIN(2) MAX(2) STD(2) VARIANCE(2) SUM(2) GROUP_CONCAT(2) GROUP_CONCAT(DISTINCT 2)
+2.00000 2 2 2 1 1 1 2 2 0.00000 0.00000 2 2 2
+DROP TABLE t1;
create table t2 (ff double);
insert into t2 values (2.2);
select cast(sum(distinct ff) as decimal(5,2)) from t2;
diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result
index 14da630f61e..00642e1a570 100644
--- a/mysql-test/r/func_str.result
+++ b/mysql-test/r/func_str.result
@@ -1113,4 +1113,39 @@ conv("18383815659218730760",10,10) + 0
select "18383815659218730760" + 0;
"18383815659218730760" + 0
1.8383815659219e+19
+CREATE TABLE t1 (code varchar(10));
+INSERT INTO t1 VALUES ('a12'), ('A12'), ('a13');
+SELECT ASCII(code), code FROM t1 WHERE code='A12';
+ASCII(code) code
+97 a12
+65 A12
+SELECT ASCII(code), code FROM t1 WHERE code='A12' AND ASCII(code)=65;
+ASCII(code) code
+65 A12
+INSERT INTO t1 VALUES ('a12 '), ('A12 ');
+SELECT LENGTH(code), code FROM t1 WHERE code='A12';
+LENGTH(code) code
+3 a12
+3 A12
+4 a12
+5 A12
+SELECT LENGTH(code), code FROM t1 WHERE code='A12' AND LENGTH(code)=5;
+LENGTH(code) code
+5 A12
+ALTER TABLE t1 ADD INDEX (code);
+CREATE TABLE t2 (id varchar(10) PRIMARY KEY);
+INSERT INTO t2 VALUES ('a11'), ('a12'), ('a13'), ('a14');
+SELECT * FROM t1 INNER JOIN t2 ON t1.code=t2.id
+WHERE t2.id='a12' AND (LENGTH(code)=5 OR code < 'a00');
+code id
+A12 a12
+EXPLAIN EXTENDED
+SELECT * FROM t1 INNER JOIN t2 ON code=id
+WHERE id='a12' AND (LENGTH(code)=5 OR code < 'a00');
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref code code 13 const 3 Using where; Using index
+1 SIMPLE t2 ref PRIMARY PRIMARY 12 const 1 Using where; Using index
+Warnings:
+Note 1003 select `test`.`t1`.`code` AS `code`,`test`.`t2`.`id` AS `id` from `test`.`t1` join `test`.`t2` where ((`test`.`t1`.`code` = _latin1'a12') and (`test`.`t2`.`id` = _latin1'a12') and (length(`test`.`t1`.`code`) = 5))
+DROP TABLE t1,t2;
End of 5.0 tests
diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result
index 57cb09fe44c..ef057e04d1a 100644
--- a/mysql-test/r/group_by.result
+++ b/mysql-test/r/group_by.result
@@ -807,8 +807,8 @@ explain
SELECT straight_join sql_no_cache v1.a, v1.b, v1.real_b from t2, v1
where t2.b=v1.a GROUP BY t2.b;
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t2 index b b 2 NULL 10 Using index
-1 PRIMARY t1 eq_ref PRIMARY PRIMARY 1 test.t2.b 1
+1 SIMPLE t2 index b b 2 NULL 10 Using index
+1 SIMPLE t1 eq_ref PRIMARY PRIMARY 1 test.t2.b 1
SELECT straight_join sql_no_cache v1.a, v1.b, v1.real_b from t2, v1
where t2.b=v1.a GROUP BY t2.b;
a b real_b
diff --git a/mysql-test/r/heap_hash.result b/mysql-test/r/heap_hash.result
index e0835bbf8d6..80abcebbfea 100644
--- a/mysql-test/r/heap_hash.result
+++ b/mysql-test/r/heap_hash.result
@@ -354,7 +354,7 @@ t3 1 a 2 b NULL 13 NULL NULL HASH
explain select * from t1 ignore key(btree_idx), t3 where t1.name='matt' and t3.a = concat('',t1.name) and t3.b=t1.name;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref heap_idx heap_idx 22 const 7 Using where
-1 SIMPLE t3 ref a a 44 const,const 7 Using where
+1 SIMPLE t3 ref a a 44 func,const 7 Using where
drop table t1, t2, t3;
create temporary table t1 ( a int, index (a) ) engine=memory;
insert into t1 values (1),(2),(3),(4),(5);
diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result
index 652af1c8387..407f8a040b7 100644
--- a/mysql-test/r/information_schema.result
+++ b/mysql-test/r/information_schema.result
@@ -337,7 +337,7 @@ mysql
test
explain select * from v0;
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY # ALL NULL NULL NULL NULL 2
+1 SIMPLE # ALL NULL NULL NULL NULL 2
create view v1 (c) as select table_name from information_schema.tables
where table_name="v1";
select * from v1;
diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result
index e7d097a1d2f..b4101e037f2 100644
--- a/mysql-test/r/innodb_mysql.result
+++ b/mysql-test/r/innodb_mysql.result
@@ -118,7 +118,7 @@ min(7)
NULL
select min(7) from DUAL;
min(7)
-NULL
+7
explain select min(7) from t2m join t1m;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
@@ -133,7 +133,7 @@ max(7)
NULL
select max(7) from DUAL;
max(7)
-NULL
+7
explain select max(7) from t2m join t1m;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
@@ -172,7 +172,7 @@ min(7)
NULL
select min(7) from DUAL;
min(7)
-NULL
+7
explain select min(7) from t2i join t1i;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2i ALL NULL NULL NULL NULL 1
@@ -188,7 +188,7 @@ max(7)
NULL
select max(7) from DUAL;
max(7)
-NULL
+7
explain select max(7) from t2i join t1i;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2i ALL NULL NULL NULL NULL 1
diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result
index 2d9652ff0e3..89bb26c4b3f 100644
--- a/mysql-test/r/join_outer.result
+++ b/mysql-test/r/join_outer.result
@@ -1126,7 +1126,7 @@ a b a b
7 8 7 5
EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 Using where
+1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1
EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b);
id select_type table type possible_keys key key_len ref rows Extra
diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result
index 28c1dc59540..7cdd5e1b152 100644
--- a/mysql-test/r/olap.result
+++ b/mysql-test/r/olap.result
@@ -611,7 +611,7 @@ C
NULL
EXPLAIN SELECT type FROM v1 GROUP BY type WITH ROLLUP;
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 ALL NULL NULL NULL NULL 10 Using filesort
+1 SIMPLE t1 ALL NULL NULL NULL NULL 10 Using filesort
DROP VIEW v1;
DROP TABLE t1;
CREATE TABLE t1 (a int(11) NOT NULL);
diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result
index 3edf56496fe..add95613d62 100644
--- a/mysql-test/r/range.result
+++ b/mysql-test/r/range.result
@@ -750,13 +750,13 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 4 Using where; Using index
EXPLAIN SELECT a,b FROM v1 WHERE a < 2 and b=3;
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 range PRIMARY PRIMARY 4 NULL 4 Using where; Using index
+1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 4 Using where; Using index
EXPLAIN SELECT a,b FROM t1 WHERE a < 2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 4 Using where; Using index
EXPLAIN SELECT a,b FROM v1 WHERE a < 2;
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 range PRIMARY PRIMARY 4 NULL 4 Using where; Using index
+1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 4 Using where; Using index
SELECT a,b FROM t1 WHERE a < 2 and b=3;
a b
1 3
@@ -799,13 +799,13 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range PRIMARY PRIMARY 8 NULL # Using where; Using index
explain select * from v1 where a in (3,4) and b in (1,2,3);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 range PRIMARY PRIMARY 8 NULL # Using where; Using index
+1 SIMPLE t1 range PRIMARY PRIMARY 8 NULL # Using where; Using index
explain select * from t1 where a between 3 and 4 and b between 1 and 2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range PRIMARY PRIMARY 8 NULL # Using where; Using index
explain select * from v1 where a between 3 and 4 and b between 1 and 2;
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 range PRIMARY PRIMARY 8 NULL # Using where; Using index
+1 SIMPLE t1 range PRIMARY PRIMARY 8 NULL # Using where; Using index
drop view v1;
drop table t1;
create table t3 (a int);
diff --git a/mysql-test/r/row.result b/mysql-test/r/row.result
index 1762587415d..5b5f8b7b954 100644
--- a/mysql-test/r/row.result
+++ b/mysql-test/r/row.result
@@ -181,3 +181,128 @@ SELECT ROW(1,1,1) = ROW(1,1,1) as `1`, ROW(1,1,1) = ROW(1,2,1) as `0`, ROW(1,NUL
select row(NULL,1)=(2,0);
row(NULL,1)=(2,0)
0
+CREATE TABLE t1 (a int, b int, PRIMARY KEY (a,b));
+INSERT INTO t1 VALUES (1,1), (2,1), (3,1), (1,2), (3,2), (3,3);
+EXPLAIN SELECT * FROM t1 WHERE a=3 AND b=2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 const PRIMARY PRIMARY 8 const,const 1 Using index
+EXPLAIN SELECT * FROM t1 WHERE (a,b)=(3,2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 const PRIMARY PRIMARY 8 const,const 1 Using index
+SELECT * FROM t1 WHERE a=3 and b=2;
+a b
+3 2
+SELECT * FROM t1 WHERE (a,b)=(3,2);
+a b
+3 2
+CREATE TABLE t2 (a int, b int, c int, PRIMARY KEY (a,b,c));
+INSERT INTO t2 VALUES
+(1,1,2), (3,1,3), (1,2,2), (4,4,2),
+(1,1,1), (3,1,1), (1,2,1);
+EXPLAIN SELECT * FROM t1,t2 WHERE t1.a=t2.a AND t1.b=t2.b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index PRIMARY PRIMARY 8 NULL 6 Using index
+1 SIMPLE t2 ref PRIMARY PRIMARY 8 test.t1.a,test.t1.b 1 Using index
+EXPLAIN SELECT * FROM t1,t2 WHERE (t1.a,t1.b)=(t2.a,t2.b);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index PRIMARY PRIMARY 8 NULL 6 Using index
+1 SIMPLE t2 ref PRIMARY PRIMARY 8 test.t1.a,test.t1.b 1 Using index
+SELECT * FROM t1,t2 WHERE t1.a=t2.a and t1.b=t2.b;
+a b a b c
+1 1 1 1 1
+1 1 1 1 2
+1 2 1 2 1
+1 2 1 2 2
+3 1 3 1 1
+3 1 3 1 3
+SELECT * FROM t1,t2 WHERE (t1.a,t1.b)=(t2.a,t2.b);
+a b a b c
+1 1 1 1 1
+1 1 1 1 2
+1 2 1 2 1
+1 2 1 2 2
+3 1 3 1 1
+3 1 3 1 3
+EXPLAIN SELECT * FROM t1,t2 WHERE t1.a=t2.a AND t1.b=2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index PRIMARY PRIMARY 8 NULL 5 Using where; Using index
+1 SIMPLE t2 ref PRIMARY PRIMARY 4 test.t1.a 1 Using index
+EXPLAIN SELECT * FROM t1,t2 WHERE (t1.a,t1.b)=(t2.a,2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index PRIMARY PRIMARY 8 NULL 5 Using where; Using index
+1 SIMPLE t2 ref PRIMARY PRIMARY 4 test.t1.a 1 Using index
+SELECT * FROM t1,t2 WHERE t1.a=1 and t1.b=t2.b;
+a b a b c
+1 1 1 1 2
+1 1 3 1 3
+1 2 1 2 2
+1 1 1 1 1
+1 1 3 1 1
+1 2 1 2 1
+SELECT * FROM t1,t2 WHERE (t1.a,t1.b)=(t2.a,2);
+a b a b c
+1 2 1 1 1
+1 2 1 1 2
+1 2 1 2 1
+1 2 1 2 2
+3 2 3 1 1
+3 2 3 1 3
+EXPLAIN EXTENDED SELECT * FROM t1,t2 WHERE (t1.a,t1.b)=(t2.a,t2.b+1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index PRIMARY PRIMARY 8 NULL 6 Using index
+1 SIMPLE t2 ref PRIMARY PRIMARY 4 test.t1.a 1 Using where; Using index
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t1` join `test`.`t2` where ((`test`.`t2`.`a` = `test`.`t1`.`a`) and (`test`.`t1`.`b` = (`test`.`t2`.`b` + 1)))
+SELECT * FROM t1,t2 WHERE (t1.a,t1.b)=(t2.a,t2.b+1);
+a b a b c
+1 2 1 1 1
+1 2 1 1 2
+3 2 3 1 1
+3 2 3 1 3
+EXPLAIN EXTENDED SELECT * FROM t1,t2 WHERE (t1.a-1,t1.b)=(t2.a-1,t2.b+1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL PRIMARY 8 NULL 6 Using index
+1 SIMPLE t2 index NULL PRIMARY 12 NULL 7 Using where; Using index
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t1` join `test`.`t2` where (((`test`.`t1`.`a` - 1) = (`test`.`t2`.`a` - 1)) and (`test`.`t1`.`b` = (`test`.`t2`.`b` + 1)))
+SELECT * FROM t1,t2 WHERE (t1.a-1,t1.b)=(t2.a-1,t2.b+1);
+a b a b c
+1 2 1 1 2
+3 2 3 1 3
+1 2 1 1 1
+3 2 3 1 1
+EXPLAIN SELECT * FROM t2 WHERE a=3 AND b=2;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ref PRIMARY PRIMARY 8 const,const 1 Using index
+EXPLAIN SELECT * FROM t2 WHERE (a,b)=(3,2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ref PRIMARY PRIMARY 8 const,const 1 Using index
+SELECT * FROM t2 WHERE a=3 and b=2;
+a b c
+SELECT * FROM t2 WHERE (a,b)=(3,2);
+a b c
+EXPLAIN SELECT * FROM t1,t2 WHERE t2.a=t1.a AND t2.b=2 AND t2.c=1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index PRIMARY PRIMARY 8 NULL 6 Using index
+1 SIMPLE t2 eq_ref PRIMARY PRIMARY 12 test.t1.a,const,const 1 Using index
+EXPLAIN EXTENDED SELECT * FROM t1,t2 WHERE (t2.a,(t2.b,t2.c))=(t1.a,(2,1));
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index PRIMARY PRIMARY 8 NULL 6 Using index
+1 SIMPLE t2 eq_ref PRIMARY PRIMARY 12 test.t1.a,const,const 1 Using index
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t1` join `test`.`t2` where ((`test`.`t2`.`c` = 1) and (`test`.`t2`.`b` = 2) and (`test`.`t2`.`a` = `test`.`t1`.`a`))
+SELECT * FROM t1,t2 WHERE (t2.a,(t2.b,t2.c))=(t1.a,(2,1));
+a b a b c
+1 1 1 2 1
+1 2 1 2 1
+EXPLAIN EXTENDED SELECT * FROM t1,t2 WHERE t2.a=t1.a AND (t2.b,t2.c)=(2,1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index PRIMARY PRIMARY 8 NULL 6 Using index
+1 SIMPLE t2 eq_ref PRIMARY PRIMARY 12 test.t1.a,const,const 1 Using index
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t1` join `test`.`t2` where ((`test`.`t2`.`c` = 1) and (`test`.`t2`.`b` = 2) and (`test`.`t2`.`a` = `test`.`t1`.`a`))
+SELECT * FROM t1,t2 WHERE t2.a=t1.a AND (t2.b,t2.c)=(2,1);
+a b a b c
+1 1 1 2 1
+1 2 1 2 1
+DROP TABLE t1,t2;
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result
index 4ee6d3088a5..2e3ca9b71f0 100644
--- a/mysql-test/r/subselect.result
+++ b/mysql-test/r/subselect.result
@@ -1011,7 +1011,7 @@ INSERT INTO t1 VALUES (1);
UPDATE t1 SET i=i+1 WHERE i=(SELECT MAX(i));
select * from t1;
i
-1
+2
drop table t1;
CREATE TABLE t1 (a int(1));
EXPLAIN EXTENDED SELECT (SELECT RAND() FROM t1) FROM t1;
@@ -1203,7 +1203,7 @@ UPDATE t1 SET t.i=i+(SELECT MAX(i) FROM (SELECT 1) t);
ERROR 42S22: Unknown column 't.i' in 'field list'
select * from t1;
i
-1
+3
drop table t1;
CREATE TABLE t1 (
id int(11) default NULL
@@ -3368,3 +3368,28 @@ ORDER BY t1.t DESC LIMIT 1);
i1 i2 t i1 i2 t
24 1 2005-05-27 12:40:30 24 1 2006-06-20 12:29:40
DROP TABLE t1, t2;
+CREATE TABLE t1 (i INT);
+(SELECT i FROM t1) UNION (SELECT i FROM t1);
+i
+SELECT sql_no_cache * FROM t1 WHERE NOT EXISTS
+(
+(SELECT i FROM t1) UNION
+(SELECT i FROM t1)
+);
+i
+SELECT * FROM t1
+WHERE NOT EXISTS (((SELECT i FROM t1) UNION (SELECT i FROM t1)));
+i
+explain select ((select t11.i from t1 t11) union (select t12.i from t1 t12))
+from t1;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'union (select t12.i from t1 t12))
+from t1' at line 1
+explain select * from t1 where not exists
+((select t11.i from t1 t11) union (select t12.i from t1 t12));
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 system NULL NULL NULL NULL 0 const row not found
+2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL No tables used
+3 SUBQUERY NULL NULL NULL NULL NULL NULL NULL no matching row in const table
+4 UNION t12 system NULL NULL NULL NULL 0 const row not found
+NULL UNION RESULT <union2,4> ALL NULL NULL NULL NULL NULL
+DROP TABLE t1;
diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result
index 42a3874db08..12463658bf9 100644
--- a/mysql-test/r/union.result
+++ b/mysql-test/r/union.result
@@ -1365,7 +1365,7 @@ drop table t1, t2;
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1));
avg(1)
-NULL
+1.0000
select _utf8'12' union select _latin1'12345';
12
12
diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result
index f70547cd4a8..72e84884b2e 100644
--- a/mysql-test/r/view.result
+++ b/mysql-test/r/view.result
@@ -49,7 +49,7 @@ select v1.b from v1;
ERROR 42S22: Unknown column 'v1.b' in 'field list'
explain extended select c from v1;
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 ALL NULL NULL NULL NULL 5
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5
Warnings:
Note 1003 select (`test`.`t1`.`b` + 1) AS `c` from `test`.`t1`
create algorithm=temptable view v2 (c) as select b+1 from t1;
@@ -83,7 +83,7 @@ c
12
explain extended select c from v3;
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 ALL NULL NULL NULL NULL 5
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5
Warnings:
Note 1003 select ((`test`.`t1`.`b` + 1) + 1) AS `c` from `test`.`t1`
create algorithm=temptable view v4 (c) as select c+1 from v2;
@@ -376,7 +376,7 @@ c
30
explain extended select * from v1;
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 ALL NULL NULL NULL NULL 5 Using where
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where
Warnings:
Note 1003 select `test`.`t1`.`b` AS `c` from `test`.`t1` where (`test`.`t1`.`a` < 3)
update v1 set c=c+1;
@@ -1391,9 +1391,9 @@ a a b
4 NULL NULL
explain extended select * from t3 left join v3 on (t3.a = v3.a);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t3 ALL NULL NULL NULL NULL 3
-1 PRIMARY t1 ALL NULL NULL NULL NULL 3
-1 PRIMARY t2 ALL NULL NULL NULL NULL 2
+1 SIMPLE t3 ALL NULL NULL NULL NULL 3
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 2
Warnings:
Note 1003 select `test`.`t3`.`a` AS `a`,`test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `b` from `test`.`t3` left join (`test`.`t1` left join `test`.`t2` on((`test`.`t1`.`a` = `test`.`t2`.`a`))) on((`test`.`t3`.`a` = `test`.`t1`.`a`)) where 1
create view v1 (a) as select a from t1;
@@ -1406,9 +1406,9 @@ a a b
4 NULL NULL
explain extended select * from t3 left join v4 on (t3.a = v4.a);
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t3 ALL NULL NULL NULL NULL 3
-1 PRIMARY t1 ALL NULL NULL NULL NULL 3
-1 PRIMARY t2 ALL NULL NULL NULL NULL 2
+1 SIMPLE t3 ALL NULL NULL NULL NULL 3
+1 SIMPLE t1 ALL NULL NULL NULL NULL 3
+1 SIMPLE t2 ALL NULL NULL NULL NULL 2
Warnings:
Note 1003 select `test`.`t3`.`a` AS `a`,`test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `b` from `test`.`t3` left join (`test`.`t1` left join (`test`.`t2`) on((`test`.`t1`.`a` = `test`.`t2`.`a`))) on((`test`.`t3`.`a` = `test`.`t1`.`a`)) where 1
prepare stmt1 from "select * from t3 left join v4 on (t3.a = v4.a);";
@@ -2321,12 +2321,12 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ref a a 10 const,test.t1.b 2 Using where; Using index
EXPLAIN SELECT * FROM v1 WHERE a=1;
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 ref a a 5 const 1 Using where; Using index
-1 PRIMARY t2 ref a a 10 const,test.t1.b 2 Using where; Using index
+1 SIMPLE t1 ref a a 5 const 1 Using where; Using index
+1 SIMPLE t2 ref a a 10 const,test.t1.b 2 Using where; Using index
EXPLAIN SELECT * FROM v2 WHERE a=1;
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 ref a a 5 const 1 Using where; Using index
-1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using where
+1 SIMPLE t1 ref a a 5 const 1 Using where; Using index
+1 SIMPLE t3 ALL NULL NULL NULL NULL 3 Using where
DROP VIEW v1,v2;
DROP TABLE t1,t2,t3;
create table t1 (f1 int);
@@ -2409,7 +2409,7 @@ insert into t1 values (1),(2);
create view v1 as select * from t1;
explain select id from v1 order by id;
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 index NULL PRIMARY 4 NULL 2 Using index
+1 SIMPLE t1 index NULL PRIMARY 4 NULL 2 Using index
drop view v1;
drop table t1;
create table t1(f1 int, f2 int);
@@ -2480,7 +2480,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
EXPLAIN SELECT MAX(a) FROM v1;
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
SELECT MIN(a) FROM t1;
MIN(a)
0
@@ -2492,7 +2492,7 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
EXPLAIN SELECT MIN(a) FROM v1;
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
DROP VIEW v1;
DROP TABLE t1;
CREATE TABLE t1 (x varchar(10));
@@ -2916,4 +2916,23 @@ DROP FUNCTION f1;
DROP FUNCTION f2;
DROP VIEW v1, v2;
DROP TABLE t1;
+CREATE TABLE t1 (s1 int);
+CREATE VIEW v1 AS SELECT * FROM t1;
+EXPLAIN SELECT * FROM t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 system NULL NULL NULL NULL 0 const row not found
+EXPLAIN SELECT * FROM v1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 system NULL NULL NULL NULL 0 const row not found
+INSERT INTO t1 VALUES (1), (3), (2);
+EXPLAIN SELECT * FROM t1 t WHERE t.s1+1 < (SELECT MAX(t1.s1) FROM t1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t ALL NULL NULL NULL NULL 3 Using where
+2 SUBQUERY t1 ALL NULL NULL NULL NULL 3
+EXPLAIN SELECT * FROM v1 t WHERE t.s1+1 < (SELECT MAX(t1.s1) FROM t1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where
+2 SUBQUERY t1 ALL NULL NULL NULL NULL 3
+DROP VIEW v1;
+DROP TABLE t1;
End of 5.0 tests.
diff --git a/mysql-test/r/view_grant.result b/mysql-test/r/view_grant.result
index 7f63d790fb8..35e7afc0a7b 100644
--- a/mysql-test/r/view_grant.result
+++ b/mysql-test/r/view_grant.result
@@ -103,7 +103,7 @@ ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for tabl
grant select on mysqltest.t1 to mysqltest_1@localhost;
explain select c from mysqltest.v1;
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 system NULL NULL NULL NULL 0 const row not found
+1 SIMPLE t1 system NULL NULL NULL NULL 0 const row not found
show create view mysqltest.v1;
ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for table 'v1'
explain select c from mysqltest.v2;
@@ -123,7 +123,7 @@ ERROR 42000: SHOW VIEW command denied to user 'mysqltest_1'@'localhost' for tabl
grant show view on mysqltest.* to mysqltest_1@localhost;
explain select c from mysqltest.v1;
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t1 system NULL NULL NULL NULL 0 const row not found
+1 SIMPLE t1 system NULL NULL NULL NULL 0 const row not found
show create view mysqltest.v1;
View Create View
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest`.`v1` AS select (`mysqltest`.`t1`.`a` + 1) AS `c`,(`mysqltest`.`t1`.`b` + 1) AS `d` from `mysqltest`.`t1`
@@ -136,7 +136,7 @@ View Create View
v2 CREATE ALGORITHM=TEMPTABLE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest`.`v2` AS select (`mysqltest`.`t1`.`a` + 1) AS `c`,(`mysqltest`.`t1`.`b` + 1) AS `d` from `mysqltest`.`t1`
explain select c from mysqltest.v3;
id select_type table type possible_keys key key_len ref rows Extra
-1 PRIMARY t2 system NULL NULL NULL NULL 0 const row not found
+1 SIMPLE t2 system NULL NULL NULL NULL 0 const row not found
show create view mysqltest.v3;
View Create View
v3 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest`.`v3` AS select (`mysqltest`.`t2`.`a` + 1) AS `c`,(`mysqltest`.`t2`.`b` + 1) AS `d` from `mysqltest`.`t2`
diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test
index 07edbf206fe..db73782fdbf 100644
--- a/mysql-test/t/create.test
+++ b/mysql-test/t/create.test
@@ -674,4 +674,10 @@ create table t1(f1 varchar(800) binary not null, key(f1)) engine = innodb
insert into t1 values('aaa');
drop table t1;
+#
+# Bug#21772: can not name a column 'upgrade' when create a table
+#
+create table t1 (upgrade int);
+drop table t1;
+
# End of 5.0 tests
diff --git a/mysql-test/t/delete.test b/mysql-test/t/delete.test
index 677ffaa2860..865e1746fd3 100644
--- a/mysql-test/t/delete.test
+++ b/mysql-test/t/delete.test
@@ -153,6 +153,16 @@ DELETE FROM t1 WHERE t1.a > 0 ORDER BY t1.a LIMIT 1;
SELECT * FROM t1;
DROP TABLE t1;
+#
+# Bug #21392: multi-table delete with alias table name fails with
+# 1003: Incorrect table name
+#
+
+create table t1 (a int);
+delete `4.t1` from t1 as `4.t1` where `4.t1`.a = 5;
+delete FROM `4.t1` USING t1 as `4.t1` where `4.t1`.a = 5;
+drop table t1;
+
# End of 4.1 tests
#
diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test
index c2dd77e662a..079d107fad8 100644
--- a/mysql-test/t/func_group.test
+++ b/mysql-test/t/func_group.test
@@ -566,6 +566,19 @@ INSERT INTO t1 VALUES
SELECT MAX(b) FROM t1;
EXPLAIN SELECT MAX(b) FROM t1;
DROP TABLE t1;
+#
+# Bug #16792 query with subselect, join, and group not returning proper values
+#
+CREATE TABLE t1 (a INT, b INT);
+INSERT INTO t1 VALUES (1,1),(1,2),(2,3);
+
+SELECT (SELECT COUNT(DISTINCT t1.b)) FROM t1 GROUP BY t1.a;
+SELECT (SELECT COUNT(DISTINCT 12)) FROM t1 GROUP BY t1.a;
+# an attempt to test all aggregate function with no table.
+SELECT AVG(2), BIT_AND(2), BIT_OR(2), BIT_XOR(2), COUNT(*), COUNT(12),
+ COUNT(DISTINCT 12), MIN(2),MAX(2),STD(2), VARIANCE(2),SUM(2),
+ GROUP_CONCAT(2),GROUP_CONCAT(DISTINCT 2);
+DROP TABLE t1;
# End of 4.1 tests
diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test
index 8753db0ebe1..45415882ac7 100644
--- a/mysql-test/t/func_str.test
+++ b/mysql-test/t/func_str.test
@@ -753,4 +753,31 @@ select cast(rtrim(ltrim(' 20.06 ')) as decimal(19,2));
select conv("18383815659218730760",10,10) + 0;
select "18383815659218730760" + 0;
+#
+# Bug #21698: substitution of a string field for a constant under a function
+#
+
+CREATE TABLE t1 (code varchar(10));
+INSERT INTO t1 VALUES ('a12'), ('A12'), ('a13');
+
+SELECT ASCII(code), code FROM t1 WHERE code='A12';
+SELECT ASCII(code), code FROM t1 WHERE code='A12' AND ASCII(code)=65;
+
+INSERT INTO t1 VALUES ('a12 '), ('A12 ');
+
+SELECT LENGTH(code), code FROM t1 WHERE code='A12';
+SELECT LENGTH(code), code FROM t1 WHERE code='A12' AND LENGTH(code)=5;
+
+ALTER TABLE t1 ADD INDEX (code);
+CREATE TABLE t2 (id varchar(10) PRIMARY KEY);
+INSERT INTO t2 VALUES ('a11'), ('a12'), ('a13'), ('a14');
+
+SELECT * FROM t1 INNER JOIN t2 ON t1.code=t2.id
+ WHERE t2.id='a12' AND (LENGTH(code)=5 OR code < 'a00');
+EXPLAIN EXTENDED
+SELECT * FROM t1 INNER JOIN t2 ON code=id
+ WHERE id='a12' AND (LENGTH(code)=5 OR code < 'a00');
+
+DROP TABLE t1,t2;
+
--echo End of 5.0 tests
diff --git a/mysql-test/t/row.test b/mysql-test/t/row.test
index 6301cc0f584..63c611e6be6 100644
--- a/mysql-test/t/row.test
+++ b/mysql-test/t/row.test
@@ -92,3 +92,50 @@ SELECT ROW(NULL,10) <=> ROW(3,NULL);
#
SELECT ROW(1,1,1) = ROW(1,1,1) as `1`, ROW(1,1,1) = ROW(1,2,1) as `0`, ROW(1,NULL,1) = ROW(2,2,1) as `0`, ROW(1,NULL,1) = ROW(1,2,2) as `0`, ROW(1,NULL,1) = ROW(1,2,1) as `null` ;
select row(NULL,1)=(2,0);
+
+#
+# Bug #16081: row equalities are to be used for query optimizations
+#
+
+CREATE TABLE t1 (a int, b int, PRIMARY KEY (a,b));
+INSERT INTO t1 VALUES (1,1), (2,1), (3,1), (1,2), (3,2), (3,3);
+
+EXPLAIN SELECT * FROM t1 WHERE a=3 AND b=2;
+EXPLAIN SELECT * FROM t1 WHERE (a,b)=(3,2);
+SELECT * FROM t1 WHERE a=3 and b=2;
+SELECT * FROM t1 WHERE (a,b)=(3,2);
+
+CREATE TABLE t2 (a int, b int, c int, PRIMARY KEY (a,b,c));
+INSERT INTO t2 VALUES
+ (1,1,2), (3,1,3), (1,2,2), (4,4,2),
+ (1,1,1), (3,1,1), (1,2,1);
+
+EXPLAIN SELECT * FROM t1,t2 WHERE t1.a=t2.a AND t1.b=t2.b;
+EXPLAIN SELECT * FROM t1,t2 WHERE (t1.a,t1.b)=(t2.a,t2.b);
+SELECT * FROM t1,t2 WHERE t1.a=t2.a and t1.b=t2.b;
+SELECT * FROM t1,t2 WHERE (t1.a,t1.b)=(t2.a,t2.b);
+
+EXPLAIN SELECT * FROM t1,t2 WHERE t1.a=t2.a AND t1.b=2;
+EXPLAIN SELECT * FROM t1,t2 WHERE (t1.a,t1.b)=(t2.a,2);
+SELECT * FROM t1,t2 WHERE t1.a=1 and t1.b=t2.b;
+SELECT * FROM t1,t2 WHERE (t1.a,t1.b)=(t2.a,2);
+
+EXPLAIN EXTENDED SELECT * FROM t1,t2 WHERE (t1.a,t1.b)=(t2.a,t2.b+1);
+SELECT * FROM t1,t2 WHERE (t1.a,t1.b)=(t2.a,t2.b+1);
+
+EXPLAIN EXTENDED SELECT * FROM t1,t2 WHERE (t1.a-1,t1.b)=(t2.a-1,t2.b+1);
+SELECT * FROM t1,t2 WHERE (t1.a-1,t1.b)=(t2.a-1,t2.b+1);
+
+EXPLAIN SELECT * FROM t2 WHERE a=3 AND b=2;
+EXPLAIN SELECT * FROM t2 WHERE (a,b)=(3,2);
+SELECT * FROM t2 WHERE a=3 and b=2;
+SELECT * FROM t2 WHERE (a,b)=(3,2);
+
+EXPLAIN SELECT * FROM t1,t2 WHERE t2.a=t1.a AND t2.b=2 AND t2.c=1;
+EXPLAIN EXTENDED SELECT * FROM t1,t2 WHERE (t2.a,(t2.b,t2.c))=(t1.a,(2,1));
+SELECT * FROM t1,t2 WHERE (t2.a,(t2.b,t2.c))=(t1.a,(2,1));
+
+EXPLAIN EXTENDED SELECT * FROM t1,t2 WHERE t2.a=t1.a AND (t2.b,t2.c)=(2,1);
+SELECT * FROM t1,t2 WHERE t2.a=t1.a AND (t2.b,t2.c)=(2,1);
+
+DROP TABLE t1,t2;
diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test
index ed122e9ff5a..740cb08c5bd 100644
--- a/mysql-test/t/subselect.test
+++ b/mysql-test/t/subselect.test
@@ -2280,3 +2280,29 @@ SELECT * FROM t1,t2
ORDER BY t1.t DESC LIMIT 1);
DROP TABLE t1, t2;
+
+#
+# Bug#14654 : Cannot select from the same table twice within a UNION
+# statement
+#
+CREATE TABLE t1 (i INT);
+
+(SELECT i FROM t1) UNION (SELECT i FROM t1);
+SELECT sql_no_cache * FROM t1 WHERE NOT EXISTS
+ (
+ (SELECT i FROM t1) UNION
+ (SELECT i FROM t1)
+ );
+
+SELECT * FROM t1
+WHERE NOT EXISTS (((SELECT i FROM t1) UNION (SELECT i FROM t1)));
+
+#TODO:not supported
+--error 1064
+explain select ((select t11.i from t1 t11) union (select t12.i from t1 t12))
+ from t1;
+#supported
+explain select * from t1 where not exists
+ ((select t11.i from t1 t11) union (select t12.i from t1 t12));
+
+DROP TABLE t1;
diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test
index edff38274c4..e299b86c4e6 100644
--- a/mysql-test/t/view.test
+++ b/mysql-test/t/view.test
@@ -2833,5 +2833,21 @@ DROP FUNCTION f2;
DROP VIEW v1, v2;
DROP TABLE t1;
+#
+# Bug #5500: wrong select_type in EXPLAIN output for queries over views
+#
+
+CREATE TABLE t1 (s1 int);
+CREATE VIEW v1 AS SELECT * FROM t1;
+
+EXPLAIN SELECT * FROM t1;
+EXPLAIN SELECT * FROM v1;
+INSERT INTO t1 VALUES (1), (3), (2);
+
+EXPLAIN SELECT * FROM t1 t WHERE t.s1+1 < (SELECT MAX(t1.s1) FROM t1);
+EXPLAIN SELECT * FROM v1 t WHERE t.s1+1 < (SELECT MAX(t1.s1) FROM t1);
+
+DROP VIEW v1;
+DROP TABLE t1;
--echo End of 5.0 tests.
diff --git a/sql/item.cc b/sql/item.cc
index 34e5e2da165..de78a2539a7 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -3789,13 +3789,48 @@ Item_equal *Item_field::find_item_equal(COND_EQUAL *cond_equal)
/*
+ Check whether a field can be substituted by an equal item
+
+ SYNOPSIS
+ equal_fields_propagator()
+ arg - *arg != NULL <-> the field is in the context where
+ substitution for an equal item is valid
+
+ DESCRIPTION
+ The function checks whether a substitution of the field
+ occurrence for an equal item is valid.
+
+ NOTES
+ The following statement is not always true:
+ x=y => F(x)=F(x/y).
+ This means substitution of an item for an equal item not always
+ yields an equavalent condition.
+ Here's an example:
+ 'a'='a '
+ (LENGTH('a')=1) != (LENGTH('a ')=2)
+ Such a substitution is surely valid if either the substituted
+ field is not of a STRING type or if it is an argument of
+ a comparison predicate.
+
+ RETURN
+ TRUE substitution is valid
+ FALSE otherwise
+*/
+
+bool Item_field::subst_argument_checker(byte **arg)
+{
+ return (result_type() != STRING_RESULT) || (*arg);
+}
+
+
+/*
Set a pointer to the multiple equality the field reference belongs to
(if any)
SYNOPSIS
equal_fields_propagator()
- arg - reference to list of multiple equalities where
- the field (this object) is to be looked for
+ arg - reference to list of multiple equalities where
+ the field (this object) is to be looked for
DESCRIPTION
The function looks for a multiple equality containing the field item
@@ -3807,7 +3842,7 @@ Item_equal *Item_field::find_item_equal(COND_EQUAL *cond_equal)
NOTES
This function is supposed to be called as a callback parameter in calls
- of the transform method.
+ of the compile method.
RETURN VALUES
pointer to the replacing constant item, if the field item was substituted
diff --git a/sql/item.h b/sql/item.h
index 58a3bfd0d75..f1fb2f6a04a 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -410,7 +410,19 @@ public:
};
-typedef bool (Item::*Item_processor)(byte *arg);
+typedef bool (Item::*Item_processor) (byte *arg);
+/*
+ Analyzer function
+ SYNOPSIS
+ argp in/out IN: Analysis parameter
+ OUT: Parameter to be passed to the transformer
+
+ RETURN
+ TRUE Invoke the transformer
+ FALSE Don't do it
+
+*/
+typedef bool (Item::*Item_analyzer) (byte **argp);
typedef Item* (Item::*Item_transformer) (byte *arg);
typedef void (*Cond_traverser) (const Item *item, void *arg);
@@ -736,6 +748,30 @@ public:
virtual Item* transform(Item_transformer transformer, byte *arg);
+ /*
+ This function performs a generic "compilation" of the Item tree.
+ The process of compilation is assumed to go as follows:
+
+ compile()
+ {
+ if (this->*some_analyzer(...))
+ {
+ compile children if any;
+ this->*some_transformer(...);
+ }
+ }
+
+ i.e. analysis is performed top-down while transformation is done
+ bottom-up.
+ */
+ virtual Item* compile(Item_analyzer analyzer, byte **arg_p,
+ Item_transformer transformer, byte *arg_t)
+ {
+ if ((this->*analyzer) (arg_p))
+ return ((this->*transformer) (arg_t));
+ return 0;
+ }
+
virtual void traverse_cond(Cond_traverser traverser,
void *arg, traverse_order order)
{
@@ -750,6 +786,12 @@ public:
virtual bool change_context_processor(byte *context) { return 0; }
virtual bool reset_query_id_processor(byte *query_id) { return 0; }
virtual bool is_expensive_processor(byte *arg) { return 0; }
+ virtual bool subst_argument_checker(byte **arg)
+ {
+ if (*arg)
+ *arg= NULL;
+ return TRUE;
+ }
virtual Item *equal_fields_propagator(byte * arg) { return this; }
virtual bool set_no_const_sub(byte *arg) { return FALSE; }
@@ -1251,6 +1293,7 @@ public:
return field->can_be_compared_as_longlong();
}
Item_equal *find_item_equal(COND_EQUAL *cond_equal);
+ bool subst_argument_checker(byte **arg);
Item *equal_fields_propagator(byte *arg);
bool set_no_const_sub(byte *arg);
Item *replace_equal_field(byte *arg);
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 919a23ed65d..db4574411d1 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -2747,16 +2747,16 @@ bool Item_cond::walk(Item_processor processor, byte *arg)
SYNOPSIS
transform()
- transformer the transformer callback function to be applied to the nodes
- of the tree of the object
- arg parameter to be passed to the transformer
+ transformer the transformer callback function to be applied to the nodes
+ of the tree of the object
+ arg parameter to be passed to the transformer
DESCRIPTION
- The function recursively applies the transform method with the
- same transformer to each member item of the condition list.
+ The function recursively applies the transform method to each
+ member item of the condition list.
If the call of the method for a member item returns a new item
the old item is substituted for a new one.
- After this the transform method is applied to the root node
+ After this the transformer is applied to the root node
of the Item_cond object.
RETURN VALUES
@@ -2787,6 +2787,55 @@ Item *Item_cond::transform(Item_transformer transformer, byte *arg)
return Item_func::transform(transformer, arg);
}
+
+/*
+ Compile Item_cond object with a processor and a transformer callback functions
+
+ SYNOPSIS
+ compile()
+ analyzer the analyzer callback function to be applied to the nodes
+ of the tree of the object
+ arg_p in/out parameter to be passed to the analyzer
+ transformer the transformer callback function to be applied to the nodes
+ of the tree of the object
+ arg_t parameter to be passed to the transformer
+
+ DESCRIPTION
+ First the function applies the analyzer to the root node of
+ the Item_func object. Then if the analyzer succeeeds (returns TRUE)
+ the function recursively applies the compile method to member
+ item of the condition list.
+ If the call of the method for a member item returns a new item
+ the old item is substituted for a new one.
+ After this the transformer is applied to the root node
+ of the Item_cond object.
+
+ RETURN VALUES
+ Item returned as the result of transformation of the root node
+*/
+
+Item *Item_cond::compile(Item_analyzer analyzer, byte **arg_p,
+ Item_transformer transformer, byte *arg_t)
+{
+ if (!(this->*analyzer)(arg_p))
+ return 0;
+
+ List_iterator<Item> li(list);
+ Item *item;
+ while ((item= li++))
+ {
+ /*
+ The same parameter value of arg_p must be passed
+ to analyze any argument of the condition formula.
+ */
+ byte *arg_v= *arg_p;
+ Item *new_item= item->compile(analyzer, &arg_v, transformer, arg_t);
+ if (new_item && new_item != item)
+ li.replace(new_item);
+ }
+ return Item_func::transform(transformer, arg_t);
+}
+
void Item_cond::traverse_cond(Cond_traverser traverser,
void *arg, traverse_order order)
{
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 47f9f2aa98f..f2c43833bd9 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -240,6 +240,7 @@ public:
}
Item *neg_transformer(THD *thd);
virtual Item *negated_item();
+ bool subst_argument_checker(byte **arg) { return TRUE; }
};
class Item_func_not :public Item_bool_func
@@ -1171,6 +1172,9 @@ public:
Item *transform(Item_transformer transformer, byte *arg);
void traverse_cond(Cond_traverser, void *arg, traverse_order order);
void neg_arguments(THD *thd);
+ bool subst_argument_checker(byte **arg) { return TRUE; }
+ Item *compile(Item_analyzer analyzer, byte **arg_p,
+ Item_transformer transformer, byte *arg_t);
};
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 579e7f88ee6..63a2279bb0d 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -234,22 +234,21 @@ void Item_func::traverse_cond(Cond_traverser traverser,
}
-
/*
Transform an Item_func object with a transformer callback function
SYNOPSIS
transform()
- transformer the transformer callback function to be applied to the nodes
- of the tree of the object
- argument parameter to be passed to the transformer
+ transformer the transformer callback function to be applied to the nodes
+ of the tree of the object
+ argument parameter to be passed to the transformer
DESCRIPTION
- The function recursively applies the transform method with the
- same transformer to each argument the function.
- If the call of the method for a member item returns a new item
+ The function recursively applies the transform method to each
+ argument of the Item_func node.
+ If the call of the method for an argument item returns a new item
the old item is substituted for a new one.
- After this the transform method is applied to the root node
+ After this the transformer is applied to the root node
of the Item_func object.
RETURN VALUES
@@ -283,6 +282,55 @@ Item *Item_func::transform(Item_transformer transformer, byte *argument)
}
+/*
+ Compile Item_func object with a processor and a transformer callback functions
+
+ SYNOPSIS
+ compile()
+ analyzer the analyzer callback function to be applied to the nodes
+ of the tree of the object
+ arg_p in/out parameter to be passed to the processor
+ transformer the transformer callback function to be applied to the nodes
+ of the tree of the object
+ arg_t parameter to be passed to the transformer
+
+ DESCRIPTION
+ First the function applies the analyzer to the root node of
+ the Item_func object. Then if the analizer succeeeds (returns TRUE)
+ the function recursively applies the compile method to each argument
+ of the Item_func node.
+ If the call of the method for an argument item returns a new item
+ the old item is substituted for a new one.
+ After this the transformer is applied to the root node
+ of the Item_func object.
+
+ RETURN VALUES
+ Item returned as the result of transformation of the root node
+*/
+
+Item *Item_func::compile(Item_analyzer analyzer, byte **arg_p,
+ Item_transformer transformer, byte *arg_t)
+{
+ if (!(this->*analyzer)(arg_p))
+ return 0;
+ if (arg_count)
+ {
+ Item **arg,**arg_end;
+ for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++)
+ {
+ /*
+ The same parameter value of arg_p must be passed
+ to analyze any argument of the condition formula.
+ */
+ byte *arg_v= *arg_p;
+ Item *new_item= (*arg)->compile(analyzer, &arg_v, transformer, arg_t);
+ if (new_item && *arg != new_item)
+ current_thd->change_item_tree(arg, new_item);
+ }
+ }
+ return (this->*transformer)(arg_t);
+}
+
/* See comments in Item_cmp_func::split_sum_func() */
void Item_func::split_sum_func(THD *thd, Item **ref_pointer_array,
diff --git a/sql/item_func.h b/sql/item_func.h
index c15b0b854b0..0d09bac4e86 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -187,6 +187,8 @@ public:
}
bool walk(Item_processor processor, byte *arg);
Item *transform(Item_transformer transformer, byte *arg);
+ Item* compile(Item_analyzer analyzer, byte **arg_p,
+ Item_transformer transformer, byte *arg_t);
void traverse_cond(Cond_traverser traverser,
void * arg, traverse_order order);
bool is_expensive_processor(byte *arg);
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index d73b1f1aac0..f293c769d75 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -425,6 +425,7 @@ void view_store_options(THD *thd, st_table_list *table, String *buff);
#define TL_OPTION_UPDATING 1
#define TL_OPTION_FORCE_INDEX 2
#define TL_OPTION_IGNORE_LEAVES 4
+#define TL_OPTION_ALIAS 8
/* Some portable defines */
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index 1f6190241a3..d17c42bca38 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -191,7 +191,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
Type of range for the key part for this field will be
returned in range_fl.
*/
- if ((outer_tables & table->map) ||
+ if (table->file->inited || (outer_tables & table->map) ||
!find_key_for_maxmin(0, &ref, item_field->field, conds,
&range_fl, &prefix_len))
{
@@ -278,7 +278,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
Type of range for the key part for this field will be
returned in range_fl.
*/
- if ((outer_tables & table->map) ||
+ if (table->file->inited || (outer_tables & table->map) ||
!find_key_for_maxmin(1, &ref, item_field->field, conds,
&range_fl, &prefix_len))
{
diff --git a/sql/sql_list.h b/sql/sql_list.h
index b2bcc4ea401..afad6d0f6ac 100644
--- a/sql/sql_list.h
+++ b/sql/sql_list.h
@@ -94,9 +94,9 @@ public:
inline base_list() { empty(); }
inline base_list(const base_list &tmp) :Sql_alloc()
{
- elements=tmp.elements;
- first=tmp.first;
- last=tmp.last;
+ elements= tmp.elements;
+ first= tmp.first;
+ last= elements ? tmp.last : &first;
}
inline base_list(bool error) { }
inline bool push_back(void *info)
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index d809c1b2cb0..42862084d62 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -6085,6 +6085,7 @@ bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc)
table_options A set of the following bits:
TL_OPTION_UPDATING Table will be updated
TL_OPTION_FORCE_INDEX Force usage of index
+ TL_OPTION_ALIAS an alias in multi table DELETE
lock_type How table should be locked
use_index List of indexed used in USE INDEX
ignore_index List of indexed used in IGNORE INDEX
@@ -6113,7 +6114,8 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
if (!table)
DBUG_RETURN(0); // End of memory
alias_str= alias ? alias->str : table->table.str;
- if (check_table_name(table->table.str, table->table.length))
+ if (!test(table_options & TL_OPTION_ALIAS) &&
+ check_table_name(table->table.str, table->table.length))
{
my_error(ER_WRONG_TABLE_NAME, MYF(0), table->table.str);
DBUG_RETURN(0);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index e9d0e003f6d..cd06a39c549 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1324,7 +1324,7 @@ JOIN::exec()
}
(void) result->prepare2(); // Currently, this cannot fail.
- if (!tables_list)
+ if (!tables_list && (tables || !select_lex->with_sum_func))
{ // Only test of functions
if (select_options & SELECT_DESCRIBE)
select_describe(this, FALSE, FALSE, FALSE,
@@ -1364,7 +1364,12 @@ JOIN::exec()
thd->examined_row_count= 0;
DBUG_VOID_RETURN;
}
- thd->limit_found_rows= thd->examined_row_count= 0;
+ /*
+ don't reset the found rows count if there're no tables
+ as FOUND_ROWS() may be called.
+ */
+ if (tables)
+ thd->limit_found_rows= thd->examined_row_count= 0;
if (zero_result_cause)
{
@@ -1403,7 +1408,8 @@ JOIN::exec()
having= tmp_having;
select_describe(this, need_tmp,
order != 0 && !skip_sort_order,
- select_distinct);
+ select_distinct,
+ !tables ? "No tables used" : NullS);
DBUG_VOID_RETURN;
}
@@ -6351,29 +6357,30 @@ finish:
/*
- Check whether an item is a simple equality predicate and if so
- create/find a multiple equality for this predicate
+ Check whether an equality can be used to build multiple equalities
SYNOPSIS
- check_equality()
- item item to check
- cond_equal multiple equalities that must hold together with the predicate
+ check_simple_equality()
+ left_item left term of the quality to be checked
+ right_item right term of the equality to be checked
+ item equality item if the equality originates from a condition
+ predicate, 0 if the equality is the result of row elimination
+ cond_equal multiple equalities that must hold together with the equality
DESCRIPTION
- This function first checks whether an item is a simple equality i.e.
- the one that equates a field with another field or a constant
- (item=constant_item or item=field_item).
- If this is the case the function looks a for a multiple equality
+ This function first checks whether the equality (left_item=right_item)
+ is a simple equality i.e. the one that equates a field with another field
+ or a constant (field=field_item or field=const_item).
+ If this is the case the function looks for a multiple equality
in the lists referenced directly or indirectly by cond_equal inferring
the given simple equality. If it doesn't find any, it builds a multiple
equality that covers the predicate, i.e. the predicate can be inferred
- from it.
+ from this multiple equality.
The built multiple equality could be obtained in such a way:
create a binary multiple equality equivalent to the predicate, then
merge it, if possible, with one of old multiple equalities.
This guarantees that the set of multiple equalities covering equality
- predicates will
- be minimal.
+ predicates will be minimal.
EXAMPLE
For the where condition
@@ -6391,7 +6398,7 @@ finish:
and will transform *cond_equal into (ptr(CE),[Item_equal(f,e)]).
NOTES
- Now only fields that have the same type defintions (verified by
+ Now only fields that have the same type definitions (verified by
the Field::eq_def method) are placed to the same multiple equalities.
Because of this some equality predicates are not eliminated and
can be used in the constant propagation procedure.
@@ -6424,177 +6431,289 @@ finish:
copying would be much more complicated.
RETURN
- TRUE - if the predicate is a simple equality predicate
- FALSE - otherwise
+ TRUE if the predicate is a simple equality predicate to be used
+ for building multiple equalities
+ FALSE otherwise
*/
-static bool check_equality(Item *item, COND_EQUAL *cond_equal)
+static bool check_simple_equality(Item *left_item, Item *right_item,
+ Item *item, COND_EQUAL *cond_equal)
{
- if (item->type() == Item::FUNC_ITEM &&
- ((Item_func*) item)->functype() == Item_func::EQ_FUNC)
+ if (left_item->type() == Item::REF_ITEM &&
+ ((Item_ref*)left_item)->ref_type() == Item_ref::VIEW_REF)
{
- Item *left_item= ((Item_func*) item)->arguments()[0];
- Item *right_item= ((Item_func*) item)->arguments()[1];
+ if (((Item_ref*)left_item)->depended_from)
+ return FALSE;
+ left_item= left_item->real_item();
+ }
+ if (right_item->type() == Item::REF_ITEM &&
+ ((Item_ref*)right_item)->ref_type() == Item_ref::VIEW_REF)
+ {
+ if (((Item_ref*)right_item)->depended_from)
+ return FALSE;
+ right_item= right_item->real_item();
+ }
+ if (left_item->type() == Item::FIELD_ITEM &&
+ right_item->type() == Item::FIELD_ITEM &&
+ !((Item_field*)left_item)->depended_from &&
+ !((Item_field*)right_item)->depended_from)
+ {
+ /* The predicate the form field1=field2 is processed */
+
+ Field *left_field= ((Item_field*) left_item)->field;
+ Field *right_field= ((Item_field*) right_item)->field;
+
+ if (!left_field->eq_def(right_field))
+ return FALSE;
+
+ /* Search for multiple equalities containing field1 and/or field2 */
+ bool left_copyfl, right_copyfl;
+ Item_equal *left_item_equal=
+ find_item_equal(cond_equal, left_field, &left_copyfl);
+ Item_equal *right_item_equal=
+ find_item_equal(cond_equal, right_field, &right_copyfl);
+
+ /* As (NULL=NULL) != TRUE we can't just remove the predicate f=f */
+ if (left_field->eq(right_field)) /* f = f */
+ return (!(left_field->maybe_null() && !left_item_equal));
- if (left_item->type() == Item::REF_ITEM &&
- ((Item_ref*)left_item)->ref_type() == Item_ref::VIEW_REF)
+ if (left_item_equal && left_item_equal == right_item_equal)
{
- if (((Item_ref*)left_item)->depended_from)
- return FALSE;
- left_item= left_item->real_item();
+ /*
+ The equality predicate is inference of one of the existing
+ multiple equalities, i.e the condition is already covered
+ by upper level equalities
+ */
+ return TRUE;
}
- if (right_item->type() == Item::REF_ITEM &&
- ((Item_ref*)right_item)->ref_type() == Item_ref::VIEW_REF)
+
+ /* Copy the found multiple equalities at the current level if needed */
+ if (left_copyfl)
{
- if (((Item_ref*)right_item)->depended_from)
- return FALSE;
- right_item= right_item->real_item();
+ /* left_item_equal of an upper level contains left_item */
+ left_item_equal= new Item_equal(left_item_equal);
+ cond_equal->current_level.push_back(left_item_equal);
}
- if (left_item->type() == Item::FIELD_ITEM &&
- right_item->type() == Item::FIELD_ITEM &&
- !((Item_field*)left_item)->depended_from &&
- !((Item_field*)right_item)->depended_from)
+ if (right_copyfl)
{
- /* The predicate the form field1=field2 is processed */
+ /* right_item_equal of an upper level contains right_item */
+ right_item_equal= new Item_equal(right_item_equal);
+ cond_equal->current_level.push_back(right_item_equal);
+ }
- Field *left_field= ((Item_field*) left_item)->field;
- Field *right_field= ((Item_field*) right_item)->field;
+ if (left_item_equal)
+ {
+ /* left item was found in the current or one of the upper levels */
+ if (! right_item_equal)
+ left_item_equal->add((Item_field *) right_item);
+ else
+ {
+ /* Merge two multiple equalities forming a new one */
+ left_item_equal->merge(right_item_equal);
+ /* Remove the merged multiple equality from the list */
+ List_iterator<Item_equal> li(cond_equal->current_level);
+ while ((li++) != right_item_equal);
+ li.remove();
+ }
+ }
+ else
+ {
+ /* left item was not found neither the current nor in upper levels */
+ if (right_item_equal)
+ right_item_equal->add((Item_field *) left_item);
+ else
+ {
+ /* None of the fields was found in multiple equalities */
+ Item_equal *item= new Item_equal((Item_field *) left_item,
+ (Item_field *) right_item);
+ cond_equal->current_level.push_back(item);
+ }
+ }
+ return TRUE;
+ }
- if (!left_field->eq_def(right_field))
- return FALSE;
+ {
+ /* The predicate of the form field=const/const=field is processed */
+ Item *const_item= 0;
+ Item_field *field_item= 0;
+ if (left_item->type() == Item::FIELD_ITEM &&
+ !((Item_field*)left_item)->depended_from &&
+ right_item->const_item())
+ {
+ field_item= (Item_field*) left_item;
+ const_item= right_item;
+ }
+ else if (right_item->type() == Item::FIELD_ITEM &&
+ !((Item_field*)right_item)->depended_from &&
+ left_item->const_item())
+ {
+ field_item= (Item_field*) right_item;
+ const_item= left_item;
+ }
- if (left_field->eq(right_field)) /* f = f */
- return TRUE;
-
- /* Search for multiple equalities containing field1 and/or field2 */
- bool left_copyfl, right_copyfl;
- Item_equal *left_item_equal=
- find_item_equal(cond_equal, left_field, &left_copyfl);
- Item_equal *right_item_equal=
- find_item_equal(cond_equal, right_field, &right_copyfl);
+ if (const_item &&
+ field_item->result_type() == const_item->result_type())
+ {
+ bool copyfl;
- if (left_item_equal && left_item_equal == right_item_equal)
+ if (field_item->result_type() == STRING_RESULT)
{
- /*
- The equality predicate is inference of one of the existing
- multiple equalities, i.e the condition is already covered
- by upper level equalities
- */
- return TRUE;
+ CHARSET_INFO *cs= ((Field_str*) field_item->field)->charset();
+ if (!item)
+ {
+ Item_func_eq *eq_item;
+ if ((eq_item= new Item_func_eq(left_item, right_item)))
+ return FALSE;
+ eq_item->set_cmp_func();
+ eq_item->quick_fix_field();
+ item= eq_item;
+ }
+ if ((cs != ((Item_func *) item)->compare_collation()) ||
+ !cs->coll->propagate(cs, 0, 0))
+ return FALSE;
}
-
- /* Copy the found multiple equalities at the current level if needed */
- if (left_copyfl)
+
+ Item_equal *item_equal = find_item_equal(cond_equal,
+ field_item->field, &copyfl);
+ if (copyfl)
{
- /* left_item_equal of an upper level contains left_item */
- left_item_equal= new Item_equal(left_item_equal);
- cond_equal->current_level.push_back(left_item_equal);
+ item_equal= new Item_equal(item_equal);
+ cond_equal->current_level.push_back(item_equal);
}
- if (right_copyfl)
+ if (item_equal)
{
- /* right_item_equal of an upper level contains right_item */
- right_item_equal= new Item_equal(right_item_equal);
- cond_equal->current_level.push_back(right_item_equal);
- }
-
- if (left_item_equal)
- {
- /* left item was found in the current or one of the upper levels */
- if (! right_item_equal)
- left_item_equal->add((Item_field *) right_item);
- else
- {
- /* Merge two multiple equalities forming a new one */
- left_item_equal->merge(right_item_equal);
- /* Remove the merged multiple equality from the list */
- List_iterator<Item_equal> li(cond_equal->current_level);
- while ((li++) != right_item_equal);
- li.remove();
- }
+ /*
+ The flag cond_false will be set to 1 after this, if item_equal
+ already contains a constant and its value is not equal to
+ the value of const_item.
+ */
+ item_equal->add(const_item);
}
else
- {
- /* left item was not found neither the current nor in upper levels */
- if (right_item_equal)
- right_item_equal->add((Item_field *) left_item);
- else
- {
- /* None of the fields was found in multiple equalities */
- Item_equal *item= new Item_equal((Item_field *) left_item,
- (Item_field *) right_item);
- cond_equal->current_level.push_back(item);
- }
+ {
+ item_equal= new Item_equal(const_item, field_item);
+ cond_equal->current_level.push_back(item_equal);
}
return TRUE;
}
+ }
+ return FALSE;
+}
- {
- /* The predicate of the form field=const/const=field is processed */
- Item *const_item= 0;
- Item_field *field_item= 0;
- if (left_item->type() == Item::FIELD_ITEM &&
- !((Item_field*)left_item)->depended_from &&
- right_item->const_item())
- {
- field_item= (Item_field*) left_item;
- const_item= right_item;
- }
- else if (right_item->type() == Item::FIELD_ITEM &&
- !((Item_field*)right_item)->depended_from &&
- left_item->const_item())
- {
- field_item= (Item_field*) right_item;
- const_item= left_item;
- }
- if (const_item &&
- field_item->result_type() == const_item->result_type())
- {
- bool copyfl;
+/*
+ Convert row equalities into a conjunction of regular equalities
- if (field_item->result_type() == STRING_RESULT)
- {
- CHARSET_INFO *cs= ((Field_str*) field_item->field)->charset();
- if ((cs != ((Item_cond *) item)->compare_collation()) ||
- !cs->coll->propagate(cs, 0, 0))
- return FALSE;
- }
+ SYNOPSIS
+ check_row_equality()
+ left_row left term of the row equality to be processed
+ right_row right term of the row equality to be processed
+ cond_equal multiple equalities that must hold together with the predicate
+ eq_list results of conversions of row equalities that are not simple
+ enough to form multiple equalities
- Item_equal *item_equal = find_item_equal(cond_equal,
- field_item->field, &copyfl);
- if (copyfl)
- {
- item_equal= new Item_equal(item_equal);
- cond_equal->current_level.push_back(item_equal);
- }
- if (item_equal)
- {
- /*
- The flag cond_false will be set to 1 after this, if item_equal
- already contains a constant and its value is not equal to
- the value of const_item.
- */
- item_equal->add(const_item);
- }
- else
- {
- item_equal= new Item_equal(const_item, field_item);
- cond_equal->current_level.push_back(item_equal);
- }
- return TRUE;
- }
+ DESCRIPTION
+ The function converts a row equality of the form (E1,...,En)=(E'1,...,E'n)
+ into a list of equalities E1=E'1,...,En=E'n. For each of these equalities
+ Ei=E'i the function checks whether it is a simple equality or a row equality.
+ If it is a simple equality it is used to expand multiple equalities of
+ cond_equal. If it is a row equality it converted to a sequence of equalities
+ between row elements. If Ei=E'i is neither a simple equality nor a row
+ equality the item for this predicate is added to eq_list.
+
+ RETURN
+ TRUE if conversion has succeeded (no fatal error)
+ FALSE otherwise
+*/
+
+static bool check_row_equality(Item *left_row, Item_row *right_row,
+ COND_EQUAL *cond_equal, List<Item>* eq_list)
+{
+ uint n= left_row->cols();
+ for (uint i= 0 ; i < n; i++)
+ {
+ bool is_converted;
+ Item *left_item= left_row->el(i);
+ Item *right_item= right_row->el(i);
+ if (left_item->type() == Item::ROW_ITEM &&
+ right_item->type() == Item::ROW_ITEM)
+ is_converted= check_row_equality((Item_row *) left_item,
+ (Item_row *) right_item,
+ cond_equal, eq_list);
+ else
+ is_converted= check_simple_equality(left_item, right_item, 0, cond_equal);
+
+ if (!is_converted)
+ {
+ Item_func_eq *eq_item;
+ if (!(eq_item= new Item_func_eq(left_item, right_item)))
+ return FALSE;
+ eq_item->set_cmp_func();
+ eq_item->quick_fix_field();
+ eq_list->push_back(eq_item);
}
}
+ return TRUE;
+}
+
+
+/*
+ Eliminate row equalities and form multiple equalities predicates
+
+ SYNOPSIS
+ check_equality()
+ item predicate to process
+ cond_equal multiple equalities that must hold together with the predicate
+ eq_list results of conversions of row equalities that are not simple
+ enough to form multiple equalities
+
+ DESCRIPTION
+ This function checks whether the item is a simple equality
+ i.e. the one that equates a field with another field or a constant
+ (field=field_item or field=constant_item), or, a row equality.
+ For a simple equality the function looks for a multiple equality
+ in the lists referenced directly or indirectly by cond_equal inferring
+ the given simple equality. If it doesn't find any, it builds/expands
+ multiple equality that covers the predicate.
+ Row equalities are eliminated substituted for conjunctive regular equalities
+ which are treated in the same way as original equality predicates.
+
+ RETURN
+ TRUE if re-writing rules have been applied
+ FALSE otherwise, i.e.
+ if the predicate is not an equality,
+ or, if the equality is neither a simple one nor a row equality,
+ or, if the procedure fails by a fatal error.
+*/
+
+static bool check_equality(Item *item, COND_EQUAL *cond_equal,
+ List<Item> *eq_list)
+{
+ if (item->type() == Item::FUNC_ITEM &&
+ ((Item_func*) item)->functype() == Item_func::EQ_FUNC)
+ {
+ Item *left_item= ((Item_func*) item)->arguments()[0];
+ Item *right_item= ((Item_func*) item)->arguments()[1];
+
+ if (left_item->type() == Item::ROW_ITEM &&
+ right_item->type() == Item::ROW_ITEM)
+ return check_row_equality((Item_row *) left_item,
+ (Item_row *) right_item,
+ cond_equal, eq_list);
+ else
+ return check_simple_equality(left_item, right_item, item, cond_equal);
+ }
return FALSE;
}
+
/*
Replace all equality predicates in a condition by multiple equality items
SYNOPSIS
build_equal_items_for_cond()
- cond condition(expression) where to make replacement
- inherited path to all inherited multiple equality items
+ cond condition(expression) where to make replacement
+ inherited path to all inherited multiple equality items
DESCRIPTION
At each 'and' level the function detects items for equality predicates
@@ -6608,7 +6727,9 @@ static bool check_equality(Item *item, COND_EQUAL *cond_equal)
The function also traverses the cond tree and and for each field reference
sets a pointer to the multiple equality item containing the field, if there
is any. If this multiple equality equates fields to a constant the
- function replace the field reference by the constant.
+ function replaces the field reference by the constant in the cases
+ when the field is not of a string type or when the field reference is
+ just an argument of a comparison predicate.
The function also determines the maximum number of members in
equality lists of each Item_cond_and object assigning it to
cond_equal->max_members of this object and updating accordingly
@@ -6659,10 +6780,12 @@ static COND *build_equal_items_for_cond(COND *cond,
Item_equal *item_equal;
uint members;
COND_EQUAL cond_equal;
+ COND *new_cond;
cond_equal.upper_levels= inherited;
if (cond->type() == Item::COND_ITEM)
{
+ List<Item> eq_list;
bool and_level= ((Item_cond*) cond)->functype() ==
Item_func::COND_AND_FUNC;
List<Item> *args= ((Item_cond*) cond)->argument_list();
@@ -6685,7 +6808,7 @@ static COND *build_equal_items_for_cond(COND *cond,
structure here because it's restored before each
re-execution of any prepared statement/stored procedure.
*/
- if (check_equality(item, &cond_equal))
+ if (check_equality(item, &cond_equal, &eq_list))
li.remove();
}
@@ -6732,10 +6855,14 @@ static COND *build_equal_items_for_cond(COND *cond,
}
}
if (and_level)
+ {
+ args->concat(&eq_list);
args->concat((List<Item> *)&cond_equal.current_level);
+ }
}
else if (cond->type() == Item::FUNC_ITEM)
{
+ List<Item> eq_list;
/*
If an equality predicate forms the whole and level,
we call it standalone equality and it's processed here.
@@ -6746,19 +6873,57 @@ static COND *build_equal_items_for_cond(COND *cond,
for WHERE a=b AND c=d AND (b=c OR d=5)
b=c is replaced by =(a,b,c,d).
*/
- if (check_equality(cond, &cond_equal) &&
- (item_equal= cond_equal.current_level.pop()))
+ if (check_equality(cond, &cond_equal, &eq_list))
{
- item_equal->fix_length_and_dec();
- item_equal->update_used_tables();
- return item_equal;
+ int n= cond_equal.current_level.elements + eq_list.elements;
+ if (n == 0)
+ return new Item_int((longlong) 1,1);
+ else if (n == 1)
+ {
+ if ((item_equal= cond_equal.current_level.pop()))
+ {
+ item_equal->fix_length_and_dec();
+ item_equal->update_used_tables();
+ return item_equal;
+ }
+ else
+ return eq_list.pop();
+ }
+ else
+ {
+ /*
+ Here a new AND level must be created. It can happen only
+ when a row equality is processed as a standalone predicate.
+ */
+ Item_cond_and *and_cond= new Item_cond_and(eq_list);
+ and_cond->quick_fix_field();
+ List<Item> *args= and_cond->argument_list();
+ List_iterator_fast<Item_equal> it(cond_equal.current_level);
+ while ((item_equal= it++))
+ {
+ item_equal->fix_length_and_dec();
+ item_equal->update_used_tables();
+ members= item_equal->members();
+ if (cond_equal.max_members < members)
+ cond_equal.max_members= members;
+ }
+ and_cond->cond_equal= cond_equal;
+ args->concat((List<Item> *)&cond_equal.current_level);
+
+ return and_cond;
+ }
}
/*
For each field reference in cond, not from equal item predicates,
set a pointer to the multiple equality it belongs to (if there is any)
+ as soon the field is not of a string type or the field reference is
+ an argument of a comparison predicate.
*/
- cond= cond->transform(&Item::equal_fields_propagator,
- (byte *) inherited);
+ byte *is_subst_valid= (byte *) 1;
+ cond= cond->compile(&Item::subst_argument_checker,
+ &is_subst_valid,
+ &Item::equal_fields_propagator,
+ (byte *) inherited);
cond->update_used_tables();
}
return cond;
@@ -7038,7 +7203,7 @@ static Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
/*
Substitute every field reference in a condition by the best equal field
- and eliminate all multiplle equality predicates
+ and eliminate all multiple equality predicates
SYNOPSIS
substitute_for_best_equal_field()
@@ -9587,9 +9752,13 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
table->file->ha_index_init(0);
}
/* Set up select_end */
- join->join_tab[join->tables-1].next_select= setup_end_select_func(join);
+ Next_select_func end_select= setup_end_select_func(join);
+ if (join->tables)
+ {
+ join->join_tab[join->tables-1].next_select= end_select;
- join_tab=join->join_tab+join->const_tables;
+ join_tab=join->join_tab+join->const_tables;
+ }
join->send_records=0;
if (join->tables == join->const_tables)
{
@@ -9599,7 +9768,6 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
*/
if (!join->conds || join->conds->val_int())
{
- Next_select_func end_select= join->join_tab[join->tables-1].next_select;
error= (*end_select)(join,join_tab,0);
if (error == NESTED_LOOP_OK || error == NESTED_LOOP_QUERY_LIMIT)
error= (*end_select)(join,join_tab,1);
@@ -9613,6 +9781,8 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
}
else
{
+ DBUG_ASSERT(join->tables);
+ DBUG_ASSERT(join_tab);
error= sub_select(join,join_tab,0);
if (error == NESTED_LOOP_OK || error == NESTED_LOOP_NO_MORE_ROWS)
error= sub_select(join,join_tab,1);
@@ -14232,9 +14402,12 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
item_list.push_back(new Item_string(table_name_buffer, len, cs));
}
else
- item_list.push_back(new Item_string(table->alias,
- strlen(table->alias),
+ {
+ TABLE_LIST *tab=table->pos_in_table_list;
+ item_list.push_back(new Item_string(tab->alias,
+ strlen(tab->alias),
cs));
+ }
/* type */
item_list.push_back(new Item_string(join_type_str[tab->type],
strlen(join_type_str[tab->type]),
@@ -14421,8 +14594,8 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
// drop UNCACHEABLE_EXPLAIN, because it is for internal usage only
uint8 uncacheable= (sl->uncacheable & ~UNCACHEABLE_EXPLAIN);
sl->type= (((&thd->lex->select_lex)==sl)?
- ((thd->lex->all_selects_list != sl) ?
- primary_key_name : "SIMPLE"):
+ (sl->first_inner_unit() || sl->next_select() ?
+ "PRIMARY" : "SIMPLE"):
((sl == first)?
((sl->linkage == DERIVED_TABLE_TYPE) ?
"DERIVED":
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 30c7da220a6..e39deadbf12 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -753,8 +753,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
predicate bit_expr bit_term bit_factor value_expr term factor
table_wild simple_expr udf_expr
expr_or_default set_expr_or_default interval_expr
- param_marker singlerow_subselect singlerow_subselect_init
- exists_subselect exists_subselect_init geometry_function
+ param_marker geometry_function
signed_literal now_or_signed_literal opt_escape
sp_opt_default
simple_ident_nospvar simple_ident_q
@@ -819,7 +818,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <variable> internal_variable_name
-%type <select_lex> in_subselect in_subselect_init
+%type <select_lex> subselect subselect_init
get_select_lex
%type <boolfunc2creator> comp_op
@@ -3942,12 +3941,14 @@ select_paren:
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
}
- if (sel->linkage == UNION_TYPE &&
- !sel->master_unit()->first_select()->braces)
- {
- yyerror(ER(ER_SYNTAX_ERROR));
- YYABORT;
- }
+ if (sel->linkage == UNION_TYPE &&
+ !sel->master_unit()->first_select()->braces &&
+ sel->master_unit()->first_select()->linkage ==
+ UNION_TYPE)
+ {
+ yyerror(ER(ER_SYNTAX_ERROR));
+ YYABORT;
+ }
/* select in braces, can't contain global parameters */
if (sel->master_unit()->fake_select_lex)
sel->master_unit()->global_parameters=
@@ -4205,37 +4206,37 @@ bool_pri:
| bool_pri EQUAL_SYM predicate { $$= new Item_func_equal($1,$3); }
| bool_pri comp_op predicate %prec EQ
{ $$= (*$2)(0)->create($1,$3); }
- | bool_pri comp_op all_or_any in_subselect %prec EQ
- { $$= all_any_subquery_creator($1, $2, $3, $4); }
+ | bool_pri comp_op all_or_any '(' subselect ')' %prec EQ
+ { $$= all_any_subquery_creator($1, $2, $3, $5); }
| predicate ;
predicate:
- bit_expr IN_SYM '(' expr_list ')'
+ bit_expr IN_SYM '(' subselect ')'
+ { $$= new Item_in_subselect($1, $4); }
+ | bit_expr not IN_SYM '(' subselect ')'
+ { $$= negate_expression(YYTHD, new Item_in_subselect($1, $5)); }
+ | bit_expr IN_SYM '(' expr ')'
+ {
+ $$= new Item_func_eq($1, $4);
+ }
+ | bit_expr IN_SYM '(' expr ',' expr_list ')'
{
- if ($4->elements == 1)
- $$= new Item_func_eq($1, $4->head());
- else
- {
- $4->push_front($1);
- $$= new Item_func_in(*$4);
- }
+ $6->push_front($4);
+ $6->push_front($1);
+ $$= new Item_func_in(*$6);
}
- | bit_expr not IN_SYM '(' expr_list ')'
+ | bit_expr not IN_SYM '(' expr ')'
{
- if ($5->elements == 1)
- $$= new Item_func_ne($1, $5->head());
- else
- {
- $5->push_front($1);
- Item_func_in *item = new Item_func_in(*$5);
+ $$= new Item_func_ne($1, $5);
+ }
+ | bit_expr not IN_SYM '(' expr ',' expr_list ')'
+ {
+ $7->push_front($5);
+ $7->push_front($1);
+ Item_func_in *item = new Item_func_in(*$7);
item->negate();
$$= item;
- }
}
- | bit_expr IN_SYM in_subselect
- { $$= new Item_in_subselect($1, $3); }
- | bit_expr not IN_SYM in_subselect
- { $$= negate_expression(YYTHD, new Item_in_subselect($1, $4)); }
| bit_expr BETWEEN_SYM bit_expr AND_SYM predicate
{ $$= new Item_func_between($1,$3,$5); }
| bit_expr not BETWEEN_SYM bit_expr AND_SYM predicate
@@ -4357,6 +4358,10 @@ simple_expr:
| '-' simple_expr %prec NEG { $$= new Item_func_neg($2); }
| '~' simple_expr %prec NEG { $$= new Item_func_bit_neg($2); }
| not2 simple_expr %prec NEG { $$= negate_expression(YYTHD, $2); }
+ | '(' subselect ')'
+ {
+ $$= new Item_singlerow_subselect($2);
+ }
| '(' expr ')' { $$= $2; }
| '(' expr ',' expr_list ')'
{
@@ -4368,8 +4373,10 @@ simple_expr:
$5->push_front($3);
$$= new Item_row(*$5);
}
- | EXISTS exists_subselect { $$= $2; }
- | singlerow_subselect { $$= $1; }
+ | EXISTS '(' subselect ')'
+ {
+ $$= new Item_exists_subselect($3);
+ }
| '{' ident expr '}' { $$= $3; }
| MATCH ident_list_arg AGAINST '(' bit_expr fulltext_options ')'
{ $2->push_front($5);
@@ -6347,14 +6354,17 @@ table_wild_one:
ident opt_wild opt_table_alias
{
if (!Select->add_table_to_list(YYTHD, new Table_ident($1), $3,
- TL_OPTION_UPDATING, Lex->lock_option))
+ TL_OPTION_UPDATING |
+ TL_OPTION_ALIAS, Lex->lock_option))
YYABORT;
}
| ident '.' ident opt_wild opt_table_alias
{
if (!Select->add_table_to_list(YYTHD,
new Table_ident(YYTHD, $1, $3, 0),
- $5, TL_OPTION_UPDATING,
+ $5,
+ TL_OPTION_UPDATING |
+ TL_OPTION_ALIAS,
Lex->lock_option))
YYABORT;
}
@@ -7574,6 +7584,7 @@ keyword:
| TRUNCATE_SYM {}
| UNICODE_SYM {}
| XA_SYM {}
+ | UPGRADE_SYM {}
;
/*
@@ -8896,49 +8907,38 @@ union_option:
| ALL { $$=0; }
;
-singlerow_subselect:
- subselect_start singlerow_subselect_init
- subselect_end
- {
- $$= $2;
- };
-
-singlerow_subselect_init:
- select_init2
- {
- $$= new Item_singlerow_subselect(Lex->current_select->
- master_unit()->first_select());
- };
-
-exists_subselect:
- subselect_start exists_subselect_init
- subselect_end
- {
- $$= $2;
- };
-
-exists_subselect_init:
- select_init2
- {
- $$= new Item_exists_subselect(Lex->current_select->master_unit()->
- first_select());
- };
-
-in_subselect:
- subselect_start in_subselect_init
- subselect_end
- {
- $$= $2;
- };
+subselect:
+ SELECT_SYM subselect_start subselect_init subselect_end
+ {
+ $$= $3;
+ }
+ | '(' subselect_start subselect ')'
+ {
+ LEX *lex= Lex;
+ THD *thd= YYTHD;
+ /*
+ note that a local variable can't be used for
+ $3 as it's used in local variable construction
+ and some compilers can't guarnatee the order
+ in which the local variables are initialized.
+ */
+ List_iterator<Item> it($3->item_list);
+ Item *item;
+ /*
+ we must fill the items list for the "derived table".
+ */
+ while ((item= it++))
+ add_item_to_list(thd, item);
+ }
+ union_clause subselect_end { $$= $3; };
-in_subselect_init:
+subselect_init:
select_init2
{
$$= Lex->current_select->master_unit()->first_select();
};
subselect_start:
- '(' SELECT_SYM
{
LEX *lex=Lex;
if (lex->sql_command == (int)SQLCOM_HA_READ ||
@@ -8947,12 +8947,18 @@ subselect_start:
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
}
+ /*
+ we are making a "derived table" for the parenthesis
+ as we need to have a lex level to fit the union
+ after the parenthesis, e.g.
+ (SELECT .. ) UNION ... becomes
+ SELECT * FROM ((SELECT ...) UNION ...)
+ */
if (mysql_new_select(Lex, 1))
YYABORT;
};
subselect_end:
- ')'
{
LEX *lex=Lex;
lex->pop_context();