diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index 89391563f72..15f884302a1 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -90,6 +90,7 @@ tonu@x153.internalnet tonu@x3.internalnet venu@myvenu.com venu@work.mysql.com +vva@eagle.mysql.r18.ru vva@genie.(none) walrus@mysql.com wax@mysql.com diff --git a/Docs/manual.texi b/Docs/manual.texi index 283ad00d80f..0892203bca6 100644 --- a/Docs/manual.texi +++ b/Docs/manual.texi @@ -32040,6 +32040,10 @@ a single backslash to be matched). @item expr NOT LIKE pat [ESCAPE 'escape-char'] Same as @code{NOT (expr LIKE pat [ESCAPE 'escape-char'])}. +@findex SOUNDS LIKE +@item expr SOUNDS LIKE expr +Same as @code{SOUNDEX(expr)=SOUNDEX(expr)}. + @cindex mSQL compatibility @cindex compatibility, with mSQL @findex REGEXP diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index c1f36283ab0..409fd110ab9 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -42,21 +42,21 @@ insert into t1 values (null,null,''); select count(distinct a),count(distinct grp) from t1; count(distinct a) count(distinct grp) 6 3 -select sum(a),count(a),avg(a),std(a),bit_or(a),bit_and(a),min(a),max(a),min(c),max(c) from t1; -sum(a) count(a) avg(a) std(a) bit_or(a) bit_and(a) min(a) max(a) min(c) max(c) -21 6 3.5000 1.7078 7 0 1 6 E -select grp, sum(a),count(a),avg(a),std(a),bit_or(a),bit_and(a),min(a),max(a),min(c),max(c) from t1 group by grp; -grp sum(a) count(a) avg(a) std(a) bit_or(a) bit_and(a) min(a) max(a) min(c) max(c) -NULL 0 0 NULL NULL 0 0 NULL NULL -1 1 1 1.0000 0.0000 1 1 1 1 a a -2 5 2 2.5000 0.5000 3 2 2 3 b c -3 15 3 5.0000 0.8165 7 4 4 6 C E -select grp, sum(a)+count(a)+avg(a)+std(a)+bit_or(a)+bit_and(a)+min(a)+max(a)+min(c)+max(c) as sum from t1 group by grp; +select sum(a),count(a),avg(a),std(a),variance(a),bit_or(a),bit_and(a),min(a),max(a),min(c),max(c) from t1; +sum(a) count(a) avg(a) std(a) variance(a) bit_or(a) bit_and(a) min(a) max(a) min(c) max(c) +21 6 3.5000 1.7078 2.9167 7 0 1 6 E +select grp, sum(a),count(a),avg(a),std(a),variance(a),bit_or(a),bit_and(a),min(a),max(a),min(c),max(c) from t1 group by grp; +grp sum(a) count(a) avg(a) std(a) variance(a) bit_or(a) bit_and(a) min(a) max(a) min(c) max(c) +NULL 0 0 NULL NULL NULL 0 0 NULL NULL +1 1 1 1.0000 0.0000 0.0000 1 1 1 1 a a +2 5 2 2.5000 0.5000 0.2500 3 2 2 3 b c +3 15 3 5.0000 0.8165 0.6667 7 4 4 6 C E +select grp, sum(a)+count(a)+avg(a)+std(a)+variance(a)+bit_or(a)+bit_and(a)+min(a)+max(a)+min(c)+max(c) as sum from t1 group by grp; grp sum NULL NULL 1 7 -2 20 -3 44.816496580928 +2 20.25 +3 45.483163247594 create table t2 (grp int, a bigint unsigned, c char(10)); insert into t2 select grp,max(a)+max(grp),max(c) from t1 group by grp; replace into t2 select grp, a, c from t1 limit 2,1; @@ -72,14 +72,14 @@ CREATE TABLE t1 (id int(11),value1 float(10,2)); INSERT INTO t1 VALUES (1,0.00),(1,1.00), (1,2.00), (2,10.00), (2,11.00), (2,12.00); CREATE TABLE t2 (id int(11),name char(20)); INSERT INTO t2 VALUES (1,'Set One'),(2,'Set Two'); -select id, avg(value1), std(value1) from t1 group by id; -id avg(value1) std(value1) -1 1.000000 0.816497 -2 11.000000 0.816497 -select name, avg(value1), std(value1) from t1, t2 where t1.id = t2.id group by t1.id; -name avg(value1) std(value1) -Set One 1.000000 0.816497 -Set Two 11.000000 0.816497 +select id, avg(value1), std(value1), variance(value1) from t1 group by id; +id avg(value1) std(value1) variance(value1) +1 1.000000 0.816497 0.666667 +2 11.000000 0.816497 0.666667 +select name, avg(value1), std(value1), variance(value1) from t1, t2 where t1.id = t2.id group by t1.id; +name avg(value1) std(value1) variance(value1) +Set One 1.000000 0.816497 0.666667 +Set Two 11.000000 0.816497 0.666667 drop table t1,t2; create table t1 (id int not null); create table t2 (id int not null,rating int null); diff --git a/mysql-test/r/func_in.result b/mysql-test/r/func_in.result index ba33ee0831d..01d70c7c4c6 100644 --- a/mysql-test/r/func_in.result +++ b/mysql-test/r/func_in.result @@ -1,11 +1,95 @@ +select 1 in (1,2,3); +1 in (1,2,3) +1 +select 10 in (1,2,3); +10 in (1,2,3) +0 +select NULL in (1,2,3); +NULL in (1,2,3) +NULL +select 1 in (1,NULL,3); +1 in (1,NULL,3) +1 +select 3 in (1,NULL,3); +3 in (1,NULL,3) +1 +select 10 in (1,NULL,3); +10 in (1,NULL,3) +NULL +select 1.5 in (1.5,2.5,3.5); +1.5 in (1.5,2.5,3.5) +1 +select 10.5 in (1.5,2.5,3.5); +10.5 in (1.5,2.5,3.5) +0 +select NULL in (1.5,2.5,3.5); +NULL in (1.5,2.5,3.5) +NULL +select 1.5 in (1.5,NULL,3.5); +1.5 in (1.5,NULL,3.5) +1 +select 3.5 in (1.5,NULL,3.5); +3.5 in (1.5,NULL,3.5) +1 +select 10.5 in (1.5,NULL,3.5); +10.5 in (1.5,NULL,3.5) +NULL drop table if exists t1; +CREATE TABLE t1 (a int, b int, c int); +insert into t1 values (1,2,3), (1,NULL,3); +select 1 in (a,b,c) from t1; +1 in (a,b,c) +1 +1 +select 3 in (a,b,c) from t1; +3 in (a,b,c) +1 +1 +select 10 in (a,b,c) from t1; +10 in (a,b,c) +0 +NULL +select NULL in (a,b,c) from t1; +NULL in (a,b,c) +NULL +NULL +drop table t1; +CREATE TABLE t1 (a float, b float, c float); +insert into t1 values (1.5,2.5,3.5), (1.5,NULL,3.5); +select 1.5 in (a,b,c) from t1; +1.5 in (a,b,c) +1 +1 +select 3.5 in (a,b,c) from t1; +3.5 in (a,b,c) +1 +1 +select 10.5 in (a,b,c) from t1; +10.5 in (a,b,c) +0 +NULL +drop table t1; +CREATE TABLE t1 (a varchar(10), b varchar(10), c varchar(10)); +insert into t1 values ('A','BC','EFD'), ('A',NULL,'EFD'); +select 'A' in (a,b,c) from t1; +'A' in (a,b,c) +1 +1 +select 'EFD' in (a,b,c) from t1; +'EFD' in (a,b,c) +1 +1 +select 'XSFGGHF' in (a,b,c) from t1; +'XSFGGHF' in (a,b,c) +0 +NULL +drop table t1; CREATE TABLE t1 (field char(1)); INSERT INTO t1 VALUES ('A'),(NULL); SELECT * from t1 WHERE field IN (NULL); field SELECT * from t1 WHERE field NOT IN (NULL); field -A SELECT * from t1 where field = field; field A @@ -16,6 +100,7 @@ NULL DELETE FROM t1 WHERE field NOT IN (NULL); SELECT * FROM t1; field +A NULL drop table t1; create table t1 (id int(10) primary key); diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 69e37d7b911..cee1d91d64d 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -80,6 +80,21 @@ this is a REAL test select soundex(''),soundex('he'),soundex('hello all folks'); soundex('') soundex('he') soundex('hello all folks') H000 H4142 +select 'mood' sounds like 'mud'; +'mood' sounds like 'mud' +1 +select 'Glazgo' sounds like 'Liverpool'; +'Glazgo' sounds like 'Liverpool' +0 +select null sounds like 'null'; +null sounds like 'null' +NULL +select 'null' sounds like null; +'null' sounds like null +NULL +select null sounds like null; +null sounds like null +NULL select md5('hello'); md5('hello') 5d41402abc4b2a76b9719d911017c592 diff --git a/mysql-test/r/having.result b/mysql-test/r/having.result index a33ce457176..bd1bd523964 100644 --- a/mysql-test/r/having.result +++ b/mysql-test/r/having.result @@ -62,4 +62,8 @@ select Fld1, max(Fld2) from t1 group by Fld1 having std(Fld2) is not null; Fld1 max(Fld2) 1 20 3 50 +select Fld1, max(Fld2) from t1 group by Fld1 having variance(Fld2) is not null; +Fld1 max(Fld2) +1 20 +3 50 drop table t1; diff --git a/mysql-test/r/row.result b/mysql-test/r/row.result new file mode 100644 index 00000000000..1d606fc370c --- /dev/null +++ b/mysql-test/r/row.result @@ -0,0 +1,136 @@ +select row(1,2,3) IN (row(3,2,3), row(1,2,3), row(1,3,3)); +row(1,2,3) IN (row(3,2,3), row(1,2,3), row(1,3,3)) +1 +select row(10,2,3) IN (row(3,2,3), row(1,2,3), row(1,3,3)); +row(10,2,3) IN (row(3,2,3), row(1,2,3), row(1,3,3)) +0 +select row(1,2,3) IN (row(3,NULL,3), row(1,2,3), row(1,3,3)); +row(1,2,3) IN (row(3,NULL,3), row(1,2,3), row(1,3,3)) +1 +select row(10,2,3) IN (row(3,NULL,3), row(1,2,3), row(1,3,3)); +row(10,2,3) IN (row(3,NULL,3), row(1,2,3), row(1,3,3)) +0 +select row('a',1.5,3) IN (row(1,2,3), row('a',1.5,3), row('a','a','a')); +row('a',1.5,3) IN (row(1,2,3), row('a',1.5,3), row('a','a','a')) +1 +select row('a',0,3) IN (row(3,2,3), row('a','0','3'), row(1,3,3)); +row('a',0,3) IN (row(3,2,3), row('a','0','3'), row(1,3,3)) +1 +select row('a',0,3) IN (row(3,2,3), row('a','a','3'), row(1,3,3)); +row('a',0,3) IN (row(3,2,3), row('a','a','3'), row(1,3,3)) +1 +select row('a',1.5,3) IN (row(3,NULL,3), row('a',1.5,3), row(1,3,3)); +row('a',1.5,3) IN (row(3,NULL,3), row('a',1.5,3), row(1,3,3)) +1 +select row('b',1.5,3) IN (row(3,NULL,3), row('a',1.5,3), row(1,3,3)); +row('b',1.5,3) IN (row(3,NULL,3), row('a',1.5,3), row(1,3,3)) +0 +select row('b',1.5,3) IN (row('b',NULL,3), row('a',1.5,3), row(1,3,3)); +row('b',1.5,3) IN (row('b',NULL,3), row('a',1.5,3), row(1,3,3)) +NULL +select row('b',1.5,3) IN (row('b',NULL,4), row('a',1.5,3), row(1,3,3)); +row('b',1.5,3) IN (row('b',NULL,4), row('a',1.5,3), row(1,3,3)) +0 +select row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,row(3,4))); +row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,row(3,4))) +1 +select row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,4)); +Cardinality error (more/less than 2 columns) +select row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,row(3,NULL))); +row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,row(3,NULL))) +NULL +SELECT ROW(1,2,3)=ROW(1,2,3); +ROW(1,2,3)=ROW(1,2,3) +1 +SELECT ROW(2,2,3)=ROW(1+1,2,3); +ROW(2,2,3)=ROW(1+1,2,3) +1 +SELECT ROW(1,2,3)=ROW(1+1,2,3); +ROW(1,2,3)=ROW(1+1,2,3) +0 +SELECT ROW(1,2,3)ROW(1+1,2,3); +ROW(1,2,3)>ROW(1+1,2,3) +0 +SELECT ROW(1,2,3)<=ROW(1+1,2,3); +ROW(1,2,3)<=ROW(1+1,2,3) +1 +SELECT ROW(1,2,3)>=ROW(1+1,2,3); +ROW(1,2,3)>=ROW(1+1,2,3) +0 +SELECT ROW(1,2,3)<>ROW(1+1,2,3); +ROW(1,2,3)<>ROW(1+1,2,3) +1 +SELECT ROW(NULL,2,3)=ROW(NULL,2,3); +ROW(NULL,2,3)=ROW(NULL,2,3) +NULL +SELECT ROW(NULL,2,3)<=>ROW(NULL,2,3); +ROW(NULL,2,3)<=>ROW(NULL,2,3) +1 +SELECT ROW(1,2,ROW(3,4,5))=ROW(1,2,ROW(3,4,5)); +ROW(1,2,ROW(3,4,5))=ROW(1,2,ROW(3,4,5)) +1 +SELECT ROW('test',2,3.33)=ROW('test',2,3.33); +ROW('test',2,3.33)=ROW('test',2,3.33) +1 +SELECT ROW('test',2,3.33)=ROW('test',2,3.33,4); +Cardinality error (more/less than 3 columns) +SELECT ROW('test',2,ROW(3,33))=ROW('test',2,ROW(3,33)); +ROW('test',2,ROW(3,33))=ROW('test',2,ROW(3,33)) +1 +SELECT ROW('test',2,ROW(3,33))=ROW('test',2,ROW(3,3)); +ROW('test',2,ROW(3,33))=ROW('test',2,ROW(3,3)) +0 +SELECT ROW('test',2,ROW(3,33))=ROW('test',2,ROW(3,NULL)); +ROW('test',2,ROW(3,33))=ROW('test',2,ROW(3,NULL)) +NULL +SELECT ROW('test',2,ROW(3,33))=ROW('test',2,4); +Cardinality error (more/less than 2 columns) +drop table if exists t1; +create table t1 ( a int, b int, c int); +insert into t1 values (1,2,3), (2,3,1), (3,2,1), (1,2,NULL); +select * from t1 where ROW(1,2,3)=ROW(a,b,c); +a b c +1 2 3 +select * from t1 where ROW(0,2,3)=ROW(a,b,c); +a b c +select * from t1 where ROW(1,2,3)ROW(1+1,2,3); -ROW(1,2,3)>ROW(1+1,2,3) -0 -SELECT ROW(1,2,3)<=ROW(1+1,2,3); -ROW(1,2,3)<=ROW(1+1,2,3) -1 -SELECT ROW(1,2,3)>=ROW(1+1,2,3); -ROW(1,2,3)>=ROW(1+1,2,3) -0 -SELECT ROW(1,2,3)<>ROW(1+1,2,3); -ROW(1,2,3)<>ROW(1+1,2,3) -1 -SELECT ROW(NULL,2,3)=ROW(NULL,2,3); -ROW(NULL,2,3)=ROW(NULL,2,3) -NULL -SELECT ROW(NULL,2,3)<=>ROW(NULL,2,3); -ROW(NULL,2,3)<=>ROW(NULL,2,3) -1 -SELECT ROW(1,2,ROW(3,4,5))=ROW(1,2,ROW(3,4,5)); -ROW(1,2,ROW(3,4,5))=ROW(1,2,ROW(3,4,5)) -1 -SELECT ROW('test',2,3.33)=ROW('test',2,3.33); -ROW('test',2,3.33)=ROW('test',2,3.33) -1 -SELECT ROW('test',2,3.33)=ROW('test',2,3.33,4); -Cardinality error (more/less than 3 columns) -drop table if exists t1; -create table t1 ( a int, b int, c int); -insert into t1 values (1,2,3), (2,3,1), (3,2,1); -select * from t1 where ROW(1,2,3)=ROW(a,b,c); -a b c -1 2 3 -select * from t1 where ROW(0,2,3)=ROW(a,b,c); -a b c -select * from t1 where ROW(1,2,3)""; -count(*) min(fld4) max(fld4) sum(fld1) avg(fld1) std(fld1) -70 absentee vest 17788966 254128.0857 3272.5940 -select companynr,count(*),min(fld4),max(fld4),sum(fld1),avg(fld1),std(fld1) from t2 group by companynr limit 3; -companynr count(*) min(fld4) max(fld4) sum(fld1) avg(fld1) std(fld1) -00 82 Anthony windmills 10355753 126289.6707 115550.9757 -29 95 abut wetness 14473298 152350.5053 8368.5480 -34 70 absentee vest 17788966 254128.0857 3272.5940 +select count(*),min(fld4),max(fld4),sum(fld1),avg(fld1),std(fld1),variance(fld1) from t2 where companynr = 34 and fld4<>""; +count(*) min(fld4) max(fld4) sum(fld1) avg(fld1) std(fld1) variance(fld1) +70 absentee vest 17788966 254128.0857 3272.5940 10709871.3069 +select companynr,count(*),min(fld4),max(fld4),sum(fld1),avg(fld1),std(fld1),variance(fld1) from t2 group by companynr limit 3; +companynr count(*) min(fld4) max(fld4) sum(fld1) avg(fld1) std(fld1) variance(fld1) +00 82 Anthony windmills 10355753 126289.6707 115550.9757 13352027981.7087 +29 95 abut wetness 14473298 152350.5053 8368.5480 70032594.9026 +34 70 absentee vest 17788966 254128.0857 3272.5940 10709871.3069 select companynr,t2nr,count(price),sum(price),min(price),max(price),avg(price) from t3 where companynr = 37 group by companynr,t2nr limit 10; companynr t2nr count(price) sum(price) min(price) max(price) avg(price) 37 1 1 5987435 5987435 5987435 5987435.0000 diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index d442e4d97ce..8f3914fe493 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -598,3 +598,105 @@ INSERT INTO t1 values (1),(1); UPDATE t SET id=(SELECT * FROM t1); Subselect returns more than 1 record drop table t; +create table t (a int); +insert into t values (1),(2),(3); +select 1 IN (SELECT * from t); +1 IN (SELECT * from t) +1 +select 10 IN (SELECT * from t); +10 IN (SELECT * from t) +0 +select NULL IN (SELECT * from t); +NULL IN (SELECT * from t) +NULL +update t set a=NULL where a=2; +select 1 IN (SELECT * from t); +1 IN (SELECT * from t) +1 +select 3 IN (SELECT * from t); +3 IN (SELECT * from t) +1 +select 10 IN (SELECT * from t); +10 IN (SELECT * from t) +NULL +select 1 > ALL (SELECT * from t); +1 > ALL (SELECT * from t) +0 +select 10 > ALL (SELECT * from t); +10 > ALL (SELECT * from t) +NULL +select 1 > ANY (SELECT * from t); +1 > ANY (SELECT * from t) +NULL +select 10 > ANY (SELECT * from t); +10 > ANY (SELECT * from t) +1 +drop table t; +create table t (a varchar(20)); +insert into t values ('A'),('BC'),('DEF'); +select 'A' IN (SELECT * from t); +'A' IN (SELECT * from t) +1 +select 'XYZS' IN (SELECT * from t); +'XYZS' IN (SELECT * from t) +0 +select NULL IN (SELECT * from t); +NULL IN (SELECT * from t) +NULL +update t set a=NULL where a='BC'; +select 'A' IN (SELECT * from t); +'A' IN (SELECT * from t) +1 +select 'DEF' IN (SELECT * from t); +'DEF' IN (SELECT * from t) +1 +select 'XYZS' IN (SELECT * from t); +'XYZS' IN (SELECT * from t) +NULL +select 'A' > ALL (SELECT * from t); +'A' > ALL (SELECT * from t) +0 +select 'XYZS' > ALL (SELECT * from t); +'XYZS' > ALL (SELECT * from t) +NULL +select 'A' > ANY (SELECT * from t); +'A' > ANY (SELECT * from t) +NULL +select 'XYZS' > ANY (SELECT * from t); +'XYZS' > ANY (SELECT * from t) +1 +drop table t; +create table t (a float); +insert into t values (1.5),(2.5),(3.5); +select 1.5 IN (SELECT * from t); +1.5 IN (SELECT * from t) +1 +select 10.5 IN (SELECT * from t); +10.5 IN (SELECT * from t) +0 +select NULL IN (SELECT * from t); +NULL IN (SELECT * from t) +NULL +update t set a=NULL where a=2.5; +select 1.5 IN (SELECT * from t); +1.5 IN (SELECT * from t) +1 +select 3.5 IN (SELECT * from t); +3.5 IN (SELECT * from t) +1 +select 10.5 IN (SELECT * from t); +10.5 IN (SELECT * from t) +NULL +select 1.5 > ALL (SELECT * from t); +1.5 > ALL (SELECT * from t) +0 +select 10.5 > ALL (SELECT * from t); +10.5 > ALL (SELECT * from t) +NULL +select 1.5 > ANY (SELECT * from t); +1.5 > ANY (SELECT * from t) +NULL +select 10.5 > ANY (SELECT * from t); +10.5 > ANY (SELECT * from t) +1 +drop table t; diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index 57e9ae24e08..8a9a5655e1b 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -21,9 +21,9 @@ select count(distinct a),count(distinct grp) from t1; insert into t1 values (null,null,''); select count(distinct a),count(distinct grp) from t1; -select sum(a),count(a),avg(a),std(a),bit_or(a),bit_and(a),min(a),max(a),min(c),max(c) from t1; -select grp, sum(a),count(a),avg(a),std(a),bit_or(a),bit_and(a),min(a),max(a),min(c),max(c) from t1 group by grp; -select grp, sum(a)+count(a)+avg(a)+std(a)+bit_or(a)+bit_and(a)+min(a)+max(a)+min(c)+max(c) as sum from t1 group by grp; +select sum(a),count(a),avg(a),std(a),variance(a),bit_or(a),bit_and(a),min(a),max(a),min(c),max(c) from t1; +select grp, sum(a),count(a),avg(a),std(a),variance(a),bit_or(a),bit_and(a),min(a),max(a),min(c),max(c) from t1 group by grp; +select grp, sum(a)+count(a)+avg(a)+std(a)+variance(a)+bit_or(a)+bit_and(a)+min(a)+max(a)+min(c)+max(c) as sum from t1 group by grp; create table t2 (grp int, a bigint unsigned, c char(10)); insert into t2 select grp,max(a)+max(grp),max(c) from t1 group by grp; @@ -40,8 +40,8 @@ CREATE TABLE t1 (id int(11),value1 float(10,2)); INSERT INTO t1 VALUES (1,0.00),(1,1.00), (1,2.00), (2,10.00), (2,11.00), (2,12.00); CREATE TABLE t2 (id int(11),name char(20)); INSERT INTO t2 VALUES (1,'Set One'),(2,'Set Two'); -select id, avg(value1), std(value1) from t1 group by id; -select name, avg(value1), std(value1) from t1, t2 where t1.id = t2.id group by t1.id; +select id, avg(value1), std(value1), variance(value1) from t1 group by id; +select name, avg(value1), std(value1), variance(value1) from t1, t2 where t1.id = t2.id group by t1.id; drop table t1,t2; # diff --git a/mysql-test/t/func_in.test b/mysql-test/t/func_in.test index e5d42ec25c4..7bbc560276f 100644 --- a/mysql-test/t/func_in.test +++ b/mysql-test/t/func_in.test @@ -2,7 +2,39 @@ # test of IN (NULL) # +select 1 in (1,2,3); +select 10 in (1,2,3); +select NULL in (1,2,3); +select 1 in (1,NULL,3); +select 3 in (1,NULL,3); +select 10 in (1,NULL,3); +select 1.5 in (1.5,2.5,3.5); +select 10.5 in (1.5,2.5,3.5); +select NULL in (1.5,2.5,3.5); +select 1.5 in (1.5,NULL,3.5); +select 3.5 in (1.5,NULL,3.5); +select 10.5 in (1.5,NULL,3.5); drop table if exists t1; +CREATE TABLE t1 (a int, b int, c int); +insert into t1 values (1,2,3), (1,NULL,3); +select 1 in (a,b,c) from t1; +select 3 in (a,b,c) from t1; +select 10 in (a,b,c) from t1; +select NULL in (a,b,c) from t1; +drop table t1; +CREATE TABLE t1 (a float, b float, c float); +insert into t1 values (1.5,2.5,3.5), (1.5,NULL,3.5); +select 1.5 in (a,b,c) from t1; +select 3.5 in (a,b,c) from t1; +select 10.5 in (a,b,c) from t1; +drop table t1; +CREATE TABLE t1 (a varchar(10), b varchar(10), c varchar(10)); +insert into t1 values ('A','BC','EFD'), ('A',NULL,'EFD'); +select 'A' in (a,b,c) from t1; +select 'EFD' in (a,b,c) from t1; +select 'XSFGGHF' in (a,b,c) from t1; +drop table t1; + CREATE TABLE t1 (field char(1)); INSERT INTO t1 VALUES ('A'),(NULL); SELECT * from t1 WHERE field IN (NULL); diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 717b9c86a07..bd92182b101 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -36,6 +36,11 @@ select insert('txs',2,1,'hi'),insert('is ',4,0,'a'),insert('txxxxt',2,4,'es'); select replace('aaaa','a','b'),replace('aaaa','aa','b'),replace('aaaa','a','bb'),replace('aaaa','','b'),replace('bbbb','a','c'); select replace(concat(lcase(concat('THIS',' ','IS',' ','A',' ')),ucase('false'),' ','test'),'FALSE','REAL') ; select soundex(''),soundex('he'),soundex('hello all folks'); +select 'mood' sounds like 'mud'; +select 'Glazgo' sounds like 'Liverpool'; +select null sounds like 'null'; +select 'null' sounds like null; +select null sounds like null; select md5('hello'); select sha('abc'); select sha1('abc'); diff --git a/mysql-test/t/having.test b/mysql-test/t/having.test index 8dd7606d82b..7f0a1225bda 100644 --- a/mysql-test/t/having.test +++ b/mysql-test/t/having.test @@ -59,4 +59,5 @@ select Fld1, max(Fld2) as q from t1 group by Fld1 having q is not null; select Fld1, max(Fld2) from t1 group by Fld1 having max(Fld2) is not null; select Fld1, max(Fld2) from t1 group by Fld1 having avg(Fld2) is not null; select Fld1, max(Fld2) from t1 group by Fld1 having std(Fld2) is not null; +select Fld1, max(Fld2) from t1 group by Fld1 having variance(Fld2) is not null; drop table t1; diff --git a/mysql-test/t/row.test b/mysql-test/t/row.test new file mode 100644 index 00000000000..593e2342856 --- /dev/null +++ b/mysql-test/t/row.test @@ -0,0 +1,61 @@ +select row(1,2,3) IN (row(3,2,3), row(1,2,3), row(1,3,3)); +select row(10,2,3) IN (row(3,2,3), row(1,2,3), row(1,3,3)); +select row(1,2,3) IN (row(3,NULL,3), row(1,2,3), row(1,3,3)); +select row(10,2,3) IN (row(3,NULL,3), row(1,2,3), row(1,3,3)); +select row('a',1.5,3) IN (row(1,2,3), row('a',1.5,3), row('a','a','a')); +select row('a',0,3) IN (row(3,2,3), row('a','0','3'), row(1,3,3)); +select row('a',0,3) IN (row(3,2,3), row('a','a','3'), row(1,3,3)); +select row('a',1.5,3) IN (row(3,NULL,3), row('a',1.5,3), row(1,3,3)); +select row('b',1.5,3) IN (row(3,NULL,3), row('a',1.5,3), row(1,3,3)); +select row('b',1.5,3) IN (row('b',NULL,3), row('a',1.5,3), row(1,3,3)); +select row('b',1.5,3) IN (row('b',NULL,4), row('a',1.5,3), row(1,3,3)); +select row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,row(3,4))); +-- error 1239 +select row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,4)); +select row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,row(3,NULL))); + +SELECT ROW(1,2,3)=ROW(1,2,3); +SELECT ROW(2,2,3)=ROW(1+1,2,3); +SELECT ROW(1,2,3)=ROW(1+1,2,3); +SELECT ROW(1,2,3)ROW(1+1,2,3); +SELECT ROW(1,2,3)<=ROW(1+1,2,3); +SELECT ROW(1,2,3)>=ROW(1+1,2,3); +SELECT ROW(1,2,3)<>ROW(1+1,2,3); +SELECT ROW(NULL,2,3)=ROW(NULL,2,3); +SELECT ROW(NULL,2,3)<=>ROW(NULL,2,3); +SELECT ROW(1,2,ROW(3,4,5))=ROW(1,2,ROW(3,4,5)); +SELECT ROW('test',2,3.33)=ROW('test',2,3.33); +-- error 1239 +SELECT ROW('test',2,3.33)=ROW('test',2,3.33,4); +SELECT ROW('test',2,ROW(3,33))=ROW('test',2,ROW(3,33)); +SELECT ROW('test',2,ROW(3,33))=ROW('test',2,ROW(3,3)); +SELECT ROW('test',2,ROW(3,33))=ROW('test',2,ROW(3,NULL)); +-- error 1239 +SELECT ROW('test',2,ROW(3,33))=ROW('test',2,4); +drop table if exists t1; +create table t1 ( a int, b int, c int); +insert into t1 values (1,2,3), (2,3,1), (3,2,1), (1,2,NULL); +select * from t1 where ROW(1,2,3)=ROW(a,b,c); +select * from t1 where ROW(0,2,3)=ROW(a,b,c); +select * from t1 where ROW(1,2,3)ROW(1+1,2,3); -SELECT ROW(1,2,3)<=ROW(1+1,2,3); -SELECT ROW(1,2,3)>=ROW(1+1,2,3); -SELECT ROW(1,2,3)<>ROW(1+1,2,3); -SELECT ROW(NULL,2,3)=ROW(NULL,2,3); -SELECT ROW(NULL,2,3)<=>ROW(NULL,2,3); -SELECT ROW(1,2,ROW(3,4,5))=ROW(1,2,ROW(3,4,5)); -SELECT ROW('test',2,3.33)=ROW('test',2,3.33); --- error 1239 -SELECT ROW('test',2,3.33)=ROW('test',2,3.33,4); -drop table if exists t1; -create table t1 ( a int, b int, c int); -insert into t1 values (1,2,3), (2,3,1), (3,2,1); -select * from t1 where ROW(1,2,3)=ROW(a,b,c); -select * from t1 where ROW(0,2,3)=ROW(a,b,c); -select * from t1 where ROW(1,2,3)""; -select companynr,count(*),min(fld4),max(fld4),sum(fld1),avg(fld1),std(fld1) from t2 group by companynr limit 3; +select count(*),min(fld4),max(fld4),sum(fld1),avg(fld1),std(fld1),variance(fld1) from t2 where companynr = 34 and fld4<>""; +select companynr,count(*),min(fld4),max(fld4),sum(fld1),avg(fld1),std(fld1),variance(fld1) from t2 group by companynr limit 3; select companynr,t2nr,count(price),sum(price),min(price),max(price),avg(price) from t3 where companynr = 37 group by companynr,t2nr limit 10; select /*! SQL_SMALL_RESULT */ companynr,t2nr,count(price),sum(price),min(price),max(price),avg(price) from t3 where companynr = 37 group by companynr,t2nr limit 10; select companynr,count(price),sum(price),min(price),max(price),avg(price) from t3 group by companynr ; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 8b174882bc6..6a212c38255 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -362,3 +362,48 @@ INSERT INTO t1 values (1),(1); -- error 1240 UPDATE t SET id=(SELECT * FROM t1); drop table t; + + +#NULL test +create table t (a int); +insert into t values (1),(2),(3); +select 1 IN (SELECT * from t); +select 10 IN (SELECT * from t); +select NULL IN (SELECT * from t); +update t set a=NULL where a=2; +select 1 IN (SELECT * from t); +select 3 IN (SELECT * from t); +select 10 IN (SELECT * from t); +select 1 > ALL (SELECT * from t); +select 10 > ALL (SELECT * from t); +select 1 > ANY (SELECT * from t); +select 10 > ANY (SELECT * from t); +drop table t; +create table t (a varchar(20)); +insert into t values ('A'),('BC'),('DEF'); +select 'A' IN (SELECT * from t); +select 'XYZS' IN (SELECT * from t); +select NULL IN (SELECT * from t); +update t set a=NULL where a='BC'; +select 'A' IN (SELECT * from t); +select 'DEF' IN (SELECT * from t); +select 'XYZS' IN (SELECT * from t); +select 'A' > ALL (SELECT * from t); +select 'XYZS' > ALL (SELECT * from t); +select 'A' > ANY (SELECT * from t); +select 'XYZS' > ANY (SELECT * from t); +drop table t; +create table t (a float); +insert into t values (1.5),(2.5),(3.5); +select 1.5 IN (SELECT * from t); +select 10.5 IN (SELECT * from t); +select NULL IN (SELECT * from t); +update t set a=NULL where a=2.5; +select 1.5 IN (SELECT * from t); +select 3.5 IN (SELECT * from t); +select 10.5 IN (SELECT * from t); +select 1.5 > ALL (SELECT * from t); +select 10.5 > ALL (SELECT * from t); +select 1.5 > ANY (SELECT * from t); +select 10.5 > ANY (SELECT * from t); +drop table t; diff --git a/sql/item.cc b/sql/item.cc index 5e74820a3f8..4fbbfdd4772 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -46,6 +46,12 @@ Item::Item(): loop_id= 0; } +Item_ref_in_optimizer::Item_ref_in_optimizer(Item_in_optimizer *master, + char *table_name_par, + char *field_name_par): + Item_ref(master->args, table_name_par, field_name_par), owner(master) {} + + bool Item::check_loop(uint id) { DBUG_ENTER("Item::check_loop"); @@ -436,6 +442,20 @@ String *Item_copy_string::val_str(String *str) return &str_value; } +double Item_ref_in_optimizer::val() +{ + return owner->get_cache(); +} +longlong Item_ref_in_optimizer::val_int() +{ + return owner->get_cache_int(); +} +String* Item_ref_in_optimizer::val_str(String* s) +{ + return owner->get_cache_str(s); +} + + /* Functions to convert item to field (for send_fields) */ @@ -511,10 +531,31 @@ bool Item_asterisk_remover::fix_fields(THD *thd, res= item->fix_fields(thd, list, &item); else thd->fatal_error= 1; // no item given => out of memory - *ref= item; DBUG_RETURN(res); } +double Item_ref_null_helper::val() +{ + double tmp= (*ref)->val_result(); + owner->was_null|= null_value= (*ref)->null_value; + return tmp; +} +longlong Item_ref_null_helper::val_int() +{ + longlong tmp= (*ref)->val_int_result(); + owner->was_null|= null_value= (*ref)->null_value; + return tmp; +} +String* Item_ref_null_helper::val_str(String* s) +{ + String* tmp= (*ref)->str_result(s); + owner->was_null|= null_value= (*ref)->null_value; + return tmp; +} +bool Item_ref_null_helper::get_date(TIME *ltime, bool fuzzydate) +{ + return (owner->was_null|= null_value= (*ref)->get_date(ltime, fuzzydate)); +} bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { @@ -686,7 +727,7 @@ void Item_avg_field::make_field(Send_field *tmp_field) init_make_field(tmp_field,FIELD_TYPE_DOUBLE); } -void Item_std_field::make_field(Send_field *tmp_field) +void Item_variance_field::make_field(Send_field *tmp_field) { init_make_field(tmp_field,FIELD_TYPE_DOUBLE); } diff --git a/sql/item.h b/sql/item.h index 4dff0591c09..c4cf534e16c 100644 --- a/sql/item.h +++ b/sql/item.h @@ -33,7 +33,8 @@ public: enum Type {FIELD_ITEM,FUNC_ITEM,SUM_FUNC_ITEM,STRING_ITEM, INT_ITEM,REAL_ITEM,NULL_ITEM,VARBIN_ITEM, COPY_STR_ITEM,FIELD_AVG_ITEM, DEFAULT_ITEM, - PROC_ITEM,COND_ITEM,REF_ITEM,FIELD_STD_ITEM, CONST_ITEM, + PROC_ITEM,COND_ITEM,REF_ITEM,FIELD_STD_ITEM, + FIELD_VARIANCE_ITEM,CONST_ITEM, SUBSELECT_ITEM, ROW_ITEM}; enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE }; @@ -72,7 +73,6 @@ public: virtual double val_result() { return val(); } virtual longlong val_int_result() { return val_int(); } virtual String *str_result(String* tmp) { return val_str(tmp); } - virtual bool is_null_result() { return is_null(); } virtual table_map used_tables() const { return (table_map) 0L; } virtual bool basic_const_item() const { return 0; } virtual Item *new_item() { return 0; } /* Only for const items */ @@ -100,6 +100,8 @@ public: virtual Item* el(uint i) { return this; } virtual Item** addr(uint i) { return 0; } virtual bool check_cols(uint c); + // It is not row => null inside is impossible + virtual bool null_inside() { return 0; }; }; @@ -122,6 +124,25 @@ public: String* val_str(String* s) { return item->val_str(s); } void make_field(Send_field* f) { item->make_field(f); } bool check_cols(uint col) { return item->check_cols(col); } + bool eq(const Item *item, bool binary_cmp) const + { return item->eq(item, binary_cmp); } + bool is_null() + { + item->val_int(); + return item->null_value; + } + bool get_date(TIME *ltime, bool fuzzydate) + { + return (null_value=item->get_date(ltime, fuzzydate)); + } + bool send(THD *thd, String *tmp) { return item->send(thd, tmp); } + int save_in_field(Field *field, bool no_conversions) + { + return item->save_in_field(field, no_conversions); + } + void save_org_in_field(Field *field) { item->save_org_in_field(field); } + enum Item_result result_type () const { return item->result_type(); } + table_map used_tables() const { return item->used_tables(); } }; @@ -138,19 +159,6 @@ public: bool fix_fields(THD *, struct st_table_list *, Item ** ref); }; -/* - To resolve '*' field moved to condition -*/ -class Item_asterisk_remover :public Item_wrapper -{ -public: - Item_asterisk_remover(Item *it) - { - item= it; - } - bool fix_fields(THD *, struct st_table_list *, Item ** ref); -}; - class st_select_lex; class Item_ident :public Item { @@ -188,7 +196,6 @@ public: double val_result(); longlong val_int_result(); String *str_result(String* tmp); - bool is_null_result() { return result_field->is_null(); } bool send(THD *thd, String *str_arg) { return result_field->send(thd,str_arg); @@ -384,9 +391,13 @@ public: enum Item_result result_type () const { return STRING_RESULT; } bool basic_const_item() const { return 1; } bool eq(const Item *item, bool binary_cmp) const; - Item *new_item() { return new Item_string(name,str_value.ptr(),max_length,default_charset_info); } + Item *new_item() + { + return new Item_string(name, str_value.ptr(), max_length, + default_charset_info); + } String *const_string() { return &str_value; } - inline void append(char *str,uint length) { str_value.append(str,length); } + inline void append(char *str, uint length) { str_value.append(str, length); } void print(String *str); }; @@ -470,25 +481,25 @@ public: double val() { double tmp=(*ref)->val_result(); - null_value=(*ref)->is_null_result(); + null_value=(*ref)->null_value; return tmp; } longlong val_int() { longlong tmp=(*ref)->val_int_result(); - null_value=(*ref)->is_null_result(); + null_value=(*ref)->null_value; return tmp; } String *val_str(String* tmp) { tmp=(*ref)->str_result(tmp); - null_value=(*ref)->is_null_result(); + null_value=(*ref)->null_value; return tmp; } bool is_null() { (void) (*ref)->val_int_result(); - return (*ref)->is_null_result(); + return (*ref)->null_value; } bool get_date(TIME *ltime,bool fuzzydate) { @@ -505,6 +516,54 @@ public: bool check_loop(uint id); }; +class Item_in_subselect; +class Item_ref_null_helper: public Item_ref +{ +protected: + Item_in_subselect* owner; +public: + Item_ref_null_helper(Item_in_subselect* master, Item **item, + char *table_name_par,char *field_name_par): + Item_ref(item, table_name_par, field_name_par), owner(master) {} + double val(); + longlong val_int(); + String* val_str(String* s); + bool get_date(TIME *ltime, bool fuzzydate); +}; + +/* + To resolve '*' field moved to condition + and register NULL values +*/ +class Item_asterisk_remover :public Item_ref_null_helper +{ + Item *item; +public: + Item_asterisk_remover(Item_in_subselect *master, Item *it, + char *table, char *field): + Item_ref_null_helper(master, &item, table, field), + item(it) + {} + bool fix_fields(THD *, struct st_table_list *, Item ** ref); +}; + +class Item_in_optimizer; +class Item_ref_in_optimizer: public Item_ref +{ +protected: + Item_in_optimizer* owner; +public: + Item_ref_in_optimizer(Item_in_optimizer* master, + char *table_name_par,char *field_name_par); + double val(); + longlong val_int(); + String* val_str(String* s); + bool fix_fields(THD *, struct st_table_list *, Item ** ref) + { + fixed= 1; + return 0; + } +}; /* The following class is used to optimize comparing of date columns diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index dd8d1aeff02..a30faae9a01 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -90,7 +90,7 @@ static bool convert_constant_item(Field *field, Item **item) void Item_bool_func2::fix_length_and_dec() { - max_length=1; // Function returns 0 or 1 + max_length= 1; // Function returns 0 or 1 /* As some compare functions are generated after sql_yacc, @@ -144,7 +144,14 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) } if ((comparators= (Arg_comparator *) sql_alloc(sizeof(Arg_comparator)*n))) for (uint i=0; i < n; i++) + { + if ((*a)->el(i)->cols() != (*b)->el(i)->cols()) + { + my_error(ER_CARDINALITY_COL, MYF(0), (*a)->el(i)->cols()); + return 1; + } comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i)); + } else { my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); @@ -263,6 +270,61 @@ int Arg_comparator::compare_e_row() return 1; } +longlong Item_in_optimizer::val_int() +{ + int_cache_ok= 1; + flt_cache_ok= 0; + str_cache_ok= 0; + int_cache= args[0]->val_int_result(); + if (args[0]->null_value) + { + null_value= 1; + return 0; + } + longlong tmp= args[1]->val_int_result(); + null_value= args[1]->null_value; + return tmp; +} + +longlong Item_in_optimizer::get_cache_int() +{ + if (!int_cache_ok) + { + int_cache_ok= 1; + flt_cache_ok= 0; + str_cache_ok= 0; + int_cache= args[0]->val_int_result(); + null_value= args[0]->null_value; + } + return int_cache; +} + +double Item_in_optimizer::get_cache() +{ + if (!flt_cache_ok) + { + flt_cache_ok= 1; + int_cache_ok= 0; + str_cache_ok= 0; + flt_cache= args[0]->val_result(); + null_value= args[0]->null_value; + } + return flt_cache; +} + +String *Item_in_optimizer::get_cache_str(String *s) +{ + if (!str_cache_ok) + { + str_cache_ok= 1; + int_cache_ok= 0; + flt_cache_ok= 0; + str_value.set(buffer, sizeof(buffer), s->charset()); + str_cache= args[0]->str_result(&str_value); + null_value= args[0]->null_value; + } + return str_cache; +} longlong Item_func_eq::val_int() { @@ -356,7 +418,8 @@ void Item_func_interval::fix_length_and_dec() intervals[i]=args[i]->val(); } } - maybe_null=0; max_length=2; + maybe_null= 0; + max_length= 2; used_tables_cache|=item->used_tables(); } @@ -415,7 +478,7 @@ bool Item_func_interval::check_loop(uint id) void Item_func_between::fix_length_and_dec() { - max_length=1; + max_length= 1; /* As some compare functions are generated after sql_yacc, @@ -968,8 +1031,8 @@ double Item_func_coalesce::val() void Item_func_coalesce::fix_length_and_dec() { - max_length=0; - decimals=0; + max_length= 0; + decimals= 0; cached_result_type = args[0]->result_type(); for (uint i=0 ; i < arg_count ; i++) { @@ -992,6 +1055,11 @@ static int cmp_double(double *a,double *b) return *a < *b ? -1 : *a == *b ? 0 : 1; } +static int cmp_row(cmp_item_row* a, cmp_item_row* b) +{ + return a->compare(b); +} + int in_vector::find(Item *item) { byte *result=get_value(item); @@ -1014,7 +1082,6 @@ int in_vector::find(Item *item) return (int) ((*compare)(base+start*size,result) == 0); } - in_string::in_string(uint elements,qsort_cmp cmp_func) :in_vector(elements,sizeof(String),cmp_func),tmp(buff,sizeof(buff),default_charset_info) {} @@ -1041,6 +1108,29 @@ byte *in_string::get_value(Item *item) return (byte*) item->val_str(&tmp); } +in_row::in_row(uint elements, Item * item) +{ + DBUG_ENTER("in_row::in_row"); + base= (char*) new cmp_item_row[elements]; + size= sizeof(cmp_item_row); + compare= (qsort_cmp) cmp_row; + tmp.store_value(item); + DBUG_VOID_RETURN; +} + +byte *in_row::get_value(Item *item) +{ + tmp.store_value(item); + return (byte *)&tmp; +} + +void in_row::set(uint pos, Item *item) +{ + DBUG_ENTER("in_row::set"); + DBUG_PRINT("enter", ("pos %u item 0x%lx", pos, (ulong) item)); + ((cmp_item_row*) base)[pos].store_value_by_template(&tmp, item); + DBUG_VOID_RETURN; +} in_longlong::in_longlong(uint elements) :in_vector(elements,sizeof(longlong),(qsort_cmp) cmp_longlong) @@ -1053,13 +1143,12 @@ void in_longlong::set(uint pos,Item *item) byte *in_longlong::get_value(Item *item) { - tmp=item->val_int(); + tmp= item->val_int(); if (item->null_value) - return 0; /* purecov: inspected */ + return 0; return (byte*) &tmp; } - in_double::in_double(uint elements) :in_vector(elements,sizeof(double),(qsort_cmp) cmp_double) {} @@ -1071,21 +1160,173 @@ void in_double::set(uint pos,Item *item) byte *in_double::get_value(Item *item) { - tmp=item->val(); + tmp= item->val(); if (item->null_value) return 0; /* purecov: inspected */ return (byte*) &tmp; } +cmp_item* cmp_item::get_comparator (Item *item) +{ + switch (item->result_type()) { + case STRING_RESULT: + if (item->binary()) + return new cmp_item_binary_string; + else + return new cmp_item_sort_string; + break; + case INT_RESULT: + return new cmp_item_int; + break; + case REAL_RESULT: + return new cmp_item_real; + break; + case ROW_RESULT: + return new cmp_item_row; + break; + } + return 0; // to satisfy compiler :) +} + +cmp_item* cmp_item_sort_string::make_same() +{ + return new cmp_item_sort_string_in_static(); +} + +cmp_item* cmp_item_binary_string::make_same() +{ + return new cmp_item_binary_string_in_static(); +} + +cmp_item* cmp_item_int::make_same() +{ + return new cmp_item_int(); +} + +cmp_item* cmp_item_real::make_same() +{ + return new cmp_item_real(); +} + +cmp_item* cmp_item_row::make_same() +{ + return new cmp_item_row(); +} + +void cmp_item_row::store_value(Item *item) +{ + THD *thd= current_thd; + n= item->cols(); + if ((comparators= (cmp_item **) thd->alloc(sizeof(cmp_item *)*n))) + { + item->null_value= 0; + for (uint i=0; i < n; i++) + if ((comparators[i]= cmp_item::get_comparator(item->el(i)))) + { + comparators[i]->store_value(item->el(i)); + item->null_value|= item->el(i)->null_value; + } + else + { + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); + thd->fatal_error= 1; + return; + } + } + else + { + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); + thd->fatal_error= 1; + return; + } +} + +void cmp_item_row::store_value_by_template(cmp_item *t, Item *item) +{ + cmp_item_row *tmpl= (cmp_item_row*) t; + if (tmpl->n != item->cols()) + { + my_error(ER_CARDINALITY_COL, MYF(0), tmpl->n); + return; + } + n= tmpl->n; + if ((comparators= (cmp_item **) sql_alloc(sizeof(cmp_item *)*n))) + { + item->null_value= 0; + for (uint i=0; i < n; i++) + if ((comparators[i]= tmpl->comparators[i]->make_same())) + { + comparators[i]->store_value_by_template(tmpl->comparators[i], + item->el(i)); + item->null_value|= item->el(i)->null_value; + } + else + { + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); + current_thd->fatal_error= 1; + return; + } + } + else + { + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); + current_thd->fatal_error= 1; + return; + } +} + +int cmp_item_row::cmp(Item *arg) +{ + arg->null_value= 0; + if (arg->cols() != n) + { + my_error(ER_CARDINALITY_COL, MYF(0), n); + return 1; + } + bool was_null= 0; + for (uint i=0; i < n; i++) + if (comparators[i]->cmp(arg->el(i))) + { + if (!arg->el(i)->null_value) + return 1; + was_null= 1; + } + return (arg->null_value= was_null); +} + +int cmp_item_row::compare(cmp_item *c) +{ + int res; + cmp_item_row *cmp= (cmp_item_row *) c; + for (uint i=0; i < n; i++) + if ((res= comparators[i]->compare(cmp->comparators[i]))) + return res; + return 0; +} + +bool Item_func_in::nulls_in_row() +{ + Item **arg,**arg_end; + for (arg= args, arg_end= args+arg_count; arg != arg_end ; arg++) + { + if ((*arg)->null_inside()) + return 1; + } + return 0; +} void Item_func_in::fix_length_and_dec() { - if (const_item()) + /* + Row item with NULLs inside can return NULL or FALSE => + they can't be processed as static + */ + if (const_item() && !nulls_in_row()) { switch (item->result_type()) { case STRING_RESULT: if (item->binary()) - array=new in_string(arg_count,(qsort_cmp) stringcmp); /* purecov: inspected */ + array=new in_string(arg_count,(qsort_cmp) stringcmp); else array=new in_string(arg_count,(qsort_cmp) sortcmp); break; @@ -1096,8 +1337,7 @@ void Item_func_in::fix_length_and_dec() array= new in_double(arg_count); break; case ROW_RESULT: - // This case should never be choosen - DBUG_ASSERT(0); + array= new in_row(arg_count, item); break; } uint j=0; @@ -1106,33 +1346,18 @@ void Item_func_in::fix_length_and_dec() array->set(j,args[i]); if (!args[i]->null_value) // Skip NULL values j++; + else + have_null= 1; } if ((array->used_count=j)) array->sort(); } else { - switch (item->result_type()) { - case STRING_RESULT: - if (item->binary()) - in_item= new cmp_item_binary_string; - else - in_item= new cmp_item_sort_string; - break; - case INT_RESULT: - in_item= new cmp_item_int; - break; - case REAL_RESULT: - in_item= new cmp_item_real; - break; - case ROW_RESULT: - // This case should never be choosen - DBUG_ASSERT(0); - break; - } + in_item= cmp_item:: get_comparator(item); } maybe_null= item->maybe_null; - max_length=2; + max_length= 1; used_tables_cache|=item->used_tables(); const_item_cache&=item->const_item(); } @@ -1152,17 +1377,20 @@ longlong Item_func_in::val_int() if (array) { int tmp=array->find(item); - null_value=item->null_value; + null_value=item->null_value || (!tmp && have_null); return tmp; } in_item->store_value(item); if ((null_value=item->null_value)) return 0; + have_null= 0; for (uint i=0 ; i < arg_count ; i++) { if (!in_item->cmp(args[i]) && !args[i]->null_value) return 1; // Would maybe be nice with i ? + have_null|= args[i]->null_value; } + null_value= have_null; return 0; } @@ -1452,7 +1680,8 @@ longlong Item_func_isnotnull::val_int() void Item_func_like::fix_length_and_dec() { - decimals=0; max_length=1; + decimals= 0; + max_length= 1; // cmp_type=STRING_RESULT; // For quick select } @@ -1559,7 +1788,8 @@ Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) args[1]->fix_fields(thd,tables, args + 1)) return 1; /* purecov: inspected */ with_sum_func=args[0]->with_sum_func || args[1]->with_sum_func; - max_length=1; decimals=0; + max_length= 1; + decimals= 0; if (args[0]->binary() || args[1]->binary()) set_charset(my_charset_bin); diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index b4f4872bd95..994e51ef89f 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -17,6 +17,8 @@ /* compare and test functions */ +#include "assert.h" + #ifdef __GNUC__ #pragma interface /* gcc class implementation */ #endif @@ -38,16 +40,12 @@ public: Arg_comparator() {}; Arg_comparator(Item **a1, Item **a2): a(a1), b(a2) {}; - inline void seta(Item **item) { a= item; } - inline void setb(Item **item) { b= item; } - int set_compare_func(Item_bool_func2 *owner, Item_result type); inline int set_compare_func(Item_bool_func2 *owner) { return set_compare_func(owner, item_cmp_type((*a)->result_type(), (*b)->result_type())); } - inline int set_cmp_func(Item_bool_func2 *owner, Item **a1, Item **a2, Item_result type) @@ -87,6 +85,27 @@ public: void fix_length_and_dec() { decimals=0; max_length=1; } }; +class Item_in_optimizer: public Item_bool_func +{ +protected: + char buffer[80]; + longlong int_cache; + double flt_cache; + String *str_cache; + bool int_cache_ok, flt_cache_ok, str_cache_ok; +public: + Item_in_optimizer(Item *a,Item *b): + Item_bool_func(a,b), int_cache_ok(0), flt_cache_ok(0), str_cache_ok(0) {} + bool is_null() { return test(args[0]->is_null() || args[1]->is_null()); } + longlong val_int(); + + double get_cache(); + longlong get_cache_int(); + String *get_cache_str(String *s); + + friend class Item_ref_in_optimizer; +}; + class Item_bool_func2 :public Item_int_func { /* Bool with 2 string args */ protected: @@ -358,6 +377,7 @@ class in_vector :public Sql_alloc uint count; public: uint used_count; + in_vector() {} in_vector(uint elements,uint element_length,qsort_cmp cmp_func) :base((char*) sql_calloc(elements*element_length)), size(element_length), compare(cmp_func), count(elements), @@ -372,7 +392,6 @@ public: int find(Item *item); }; - class in_string :public in_vector { char buff[80]; @@ -384,7 +403,6 @@ public: byte *get_value(Item *item); }; - class in_longlong :public in_vector { longlong tmp; @@ -394,7 +412,6 @@ public: byte *get_value(Item *item); }; - class in_double :public in_vector { double tmp; @@ -404,7 +421,6 @@ public: byte *get_value(Item *item); }; - /* ** Classes for easy comparing of non const items */ @@ -414,88 +430,201 @@ class cmp_item :public Sql_alloc public: cmp_item() {} virtual ~cmp_item() {} - virtual void store_value(Item *item)=0; - virtual int cmp(Item *item)=0; + virtual void store_value(Item *item)= 0; + virtual int cmp(Item *item)= 0; + // for optimized IN with row + virtual int compare(cmp_item *item)= 0; + static cmp_item* get_comparator(Item *); + virtual cmp_item *make_same()= 0; + virtual void store_value_by_template(cmp_item *tmpl, Item *item) + { + store_value(item); + } }; - -class cmp_item_sort_string :public cmp_item { - protected: - char value_buff[80]; - String value,*value_res; +typedef int (*str_cmp_func_pointer)(const String *, const String *); +class cmp_item_string :public cmp_item +{ +protected: + str_cmp_func_pointer str_cmp_func; + String *value_res; public: - cmp_item_sort_string() :value(value_buff,sizeof(value_buff),default_charset_info) {} + cmp_item_string (str_cmp_func_pointer cmp): str_cmp_func(cmp) {} + friend class cmp_item_sort_string; + friend class cmp_item_binary_string; + friend class cmp_item_sort_string_in_static; + friend class cmp_item_binary_string_in_static; +}; + +class cmp_item_sort_string :public cmp_item_string +{ +protected: + char value_buff[80]; + String value; +public: + cmp_item_sort_string(str_cmp_func_pointer cmp): + cmp_item_string(cmp), + value(value_buff, sizeof(value_buff), default_charset_info) {} + cmp_item_sort_string(): + cmp_item_string(&sortcmp), + value(value_buff, sizeof(value_buff), default_charset_info) {} void store_value(Item *item) - { - value_res=item->val_str(&value); - } + { + value_res= item->val_str(&value); + } int cmp(Item *arg) - { - char buff[80]; - String tmp(buff,sizeof(buff),default_charset_info),*res; - if (!(res=arg->val_str(&tmp))) - return 1; /* Can't be right */ - return sortcmp(value_res,res); - } + { + char buff[80]; + String tmp(buff, sizeof(buff), default_charset_info), *res; + if (!(res= arg->val_str(&tmp))) + return 1; /* Can't be right */ + return (*str_cmp_func)(value_res, res); + } + int compare(cmp_item *c) + { + cmp_item_string *cmp= (cmp_item_string *)c; + return (*str_cmp_func)(value_res, cmp->value_res); + } + cmp_item *make_same(); }; class cmp_item_binary_string :public cmp_item_sort_string { public: - cmp_item_binary_string() {} - int cmp(Item *arg) - { - char buff[80]; - String tmp(buff,sizeof(buff),default_charset_info),*res; - if (!(res=arg->val_str(&tmp))) - return 1; /* Can't be right */ - return stringcmp(value_res,res); - } + cmp_item_binary_string(): cmp_item_sort_string(&stringcmp) {} + cmp_item *make_same(); }; - class cmp_item_int :public cmp_item { longlong value; public: void store_value(Item *item) - { - value=item->val_int(); - } + { + value= item->val_int(); + } int cmp(Item *arg) - { - return value != arg->val_int(); - } + { + return value != arg->val_int(); + } + int compare(cmp_item *c) + { + cmp_item_int *cmp= (cmp_item_int *)c; + return (value < cmp->value) ? -1 : ((value == cmp->value) ? 0 : 1); + } + cmp_item *make_same(); }; - class cmp_item_real :public cmp_item { double value; public: void store_value(Item *item) - { - value= item->val(); - } + { + value= item->val(); + } int cmp(Item *arg) - { - return value != arg->val(); - } + { + return value != arg->val(); + } + int compare(cmp_item *c) + { + cmp_item_real *cmp= (cmp_item_real *)c; + return (value < cmp->value)? -1 : ((value == cmp->value) ? 0 : 1); + } + cmp_item *make_same(); }; +class cmp_item_row :public cmp_item +{ + cmp_item **comparators; + uint n; +public: + cmp_item_row(): comparators(0), n(0) {} + ~cmp_item_row() + { + if(comparators) + for(uint i= 0; i < n; i++) + if (comparators[i]) + delete comparators[i]; + } + void store_value(Item *item); + int cmp(Item *arg); + int compare(cmp_item *arg); + cmp_item *make_same(); + void store_value_by_template(cmp_item *tmpl, Item *); +}; + + +class in_row :public in_vector +{ + cmp_item_row tmp; +public: + in_row(uint elements, Item *); + void set(uint pos,Item *item); + byte *get_value(Item *item); +}; + +/* + cmp_item for optimized IN with row (right part string, which never + be changed) +*/ + +class cmp_item_sort_string_in_static :public cmp_item_string +{ + protected: + String value; +public: + cmp_item_sort_string_in_static(str_cmp_func_pointer cmp): + cmp_item_string(cmp) {} + cmp_item_sort_string_in_static(): cmp_item_string(&sortcmp) {} + void store_value(Item *item) + { + value_res= item->val_str(&value); + } + int cmp(Item *item) + { + // Should never be called + DBUG_ASSERT(0); + return 1; + } + int compare(cmp_item *c) + { + cmp_item_string *cmp= (cmp_item_string *)c; + return (*str_cmp_func)(value_res, cmp->value_res); + } + cmp_item * make_same() + { + return new cmp_item_sort_string_in_static(); + } +}; + +class cmp_item_binary_string_in_static :public cmp_item_sort_string_in_static { +public: + cmp_item_binary_string_in_static(): + cmp_item_sort_string_in_static(&stringcmp) {} + cmp_item * make_same() + { + return new cmp_item_binary_string_in_static(); + } +}; class Item_func_in :public Item_int_func { Item *item; in_vector *array; cmp_item *in_item; + bool have_null; public: Item_func_in(Item *a,List &list) - :Item_int_func(list),item(a),array(0),in_item(0) {} + :Item_int_func(list), item(a), array(0), in_item(0), have_null(0) + { + allowed_arg_cols= item->cols(); + } longlong val_int(); bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref) { - bool res=(item->check_cols(1) || - item->fix_fields(thd, tlist, &item) || + // We do not check item->cols(), because allowed_arg_cols assigned from it + bool res=(item->fix_fields(thd, tlist, &item) || Item_func::fix_fields(thd, tlist, ref)); with_sum_func= with_sum_func || item->with_sum_func; return res; @@ -517,10 +646,9 @@ class Item_func_in :public Item_int_func DBUG_RETURN(1); DBUG_RETURN(item->check_loop(id)); } + bool nulls_in_row(); }; - - /* Functions used by where clause */ class Item_func_isnull :public Item_bool_func diff --git a/sql/item_row.cc b/sql/item_row.cc index 464a8fd0ec5..85a81a50256 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -18,8 +18,10 @@ #include "assert.h" Item_row::Item_row(List &arg): - Item(), array_holder(1) + Item(), array_holder(1), used_tables_cache(0), const_item_cache(1) { + + //TODO: think placing 2-3 component items in item (as it done for function) if ((arg_count= arg.elements)) items= (Item**) sql_alloc(sizeof(Item*)*arg_count); else @@ -45,16 +47,31 @@ void Item_row::illegal_method_call(const char *method) bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref) { - tables= 0; + null_value= 0; + maybe_null= 0; for (uint i= 0; i < arg_count; i++) { if (items[i]->fix_fields(thd, tabl, items+i)) return 1; - tables |= items[i]->used_tables(); + used_tables_cache |= items[i]->used_tables(); + const_item_cache&= items[i]->const_item(); + maybe_null|= items[i]->maybe_null; } return 0; } +void Item_row::update_used_tables() +{ + used_tables_cache= 0; + const_item_cache= 1; + for (uint i= 0; i < arg_count; i++) + { + items[i]->update_used_tables(); + used_tables_cache|= items[i]->used_tables(); + const_item_cache&= items[i]->const_item(); + } +} + bool Item_row::check_cols(uint c) { if (c != arg_count) @@ -64,3 +81,22 @@ bool Item_row::check_cols(uint c) } return 0; } + +bool Item_row::null_inside() +{ + for (uint i= 0; i < arg_count; i++) + { + if (items[i]->cols() > 1) + { + if (items[i]->null_inside()) + return 1; + } + else + { + items[i]->val_int(); + if (items[i]->null_value) + return 1; + } + } + return 0; +} diff --git a/sql/item_row.h b/sql/item_row.h index 5580250b4fb..4767d19d08f 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -17,13 +17,17 @@ class Item_row: public Item { bool array_holder; - table_map tables; + table_map used_tables_cache; + bool const_item_cache; uint arg_count; Item **items; public: Item_row(List &); Item_row(Item_row *item): - Item(), array_holder(0), tables(item->tables), arg_count(item->arg_count), + Item(), array_holder(0), + used_tables_cache(item->used_tables_cache), + const_item_cache(item->const_item_cache), + arg_count(item->arg_count), items(item->items) {} @@ -56,11 +60,14 @@ public: return 0; }; bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref); - table_map used_tables() const { return tables; }; + table_map used_tables() const { return used_tables_cache; }; + bool const_item() const { return const_item_cache; }; enum Item_result result_type() const { return ROW_RESULT; } + void update_used_tables(); - virtual uint cols() { return arg_count; } - virtual Item* el(uint i) { return items[i]; } - virtual Item** addr(uint i) { return items + i; } - virtual bool check_cols(uint c); + uint cols() { return arg_count; } + Item* el(uint i) { return items[i]; } + Item** addr(uint i) { return items + i; } + bool check_cols(uint c); + bool null_inside(); }; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index e087664e060..7dd57ef228e 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -33,9 +33,10 @@ SUBSELECT TODO: #include "sql_select.h" Item_subselect::Item_subselect(): - Item_result_field(), engine_owner(1), value_assigned(0), substitution(0) + Item_result_field(), engine_owner(1), value_assigned(0), substitution(0), + have_to_be_excluded(0) { - assign_null(); + reset(); /* item value is NULL if select_subselect not changed this value (i.e. some rows will be found returned) @@ -93,8 +94,10 @@ bool Item_subselect::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { (*ref)= substitution; substitution->name= name; - engine->exclude(); - return substitution->fix_fields(thd, tables, ref); + if (have_to_be_excluded) + engine->exclude(); + substitution= 0; + return (*ref)->fix_fields(thd, tables, ref); } char const *save_where= thd->where; @@ -159,7 +162,7 @@ double Item_singleval_subselect::val () { if (engine->exec()) { - assign_null(); + reset(); return 0; } return real_value; @@ -169,7 +172,7 @@ longlong Item_singleval_subselect::val_int () { if (engine->exec()) { - assign_null(); + reset(); return 0; } return int_value; @@ -179,7 +182,7 @@ String *Item_singleval_subselect::val_str (String *str) { if (engine->exec() || null_value) { - assign_null(); + reset(); return 0; } return &string_value; @@ -208,9 +211,8 @@ Item_in_subselect::Item_in_subselect(THD *thd, Item * left_exp, left_expr= left_exp; init(thd, select_lex, new select_exists_subselect(this)); max_columns= UINT_MAX; - null_value= 0; //can't be NULL - maybe_null= 0; //can't be NULL - value= 0; + maybe_null= 1; + reset(); // We need only 1 row to determinate existence select_lex->master_unit()->global_parameters->select_limit= 1; DBUG_VOID_RETURN; @@ -226,9 +228,7 @@ Item_allany_subselect::Item_allany_subselect(THD *thd, Item * left_exp, func= f; init(thd, select_lex, new select_exists_subselect(this)); max_columns= UINT_MAX; - null_value= 0; //can't be NULL - maybe_null= 0; //can't be NULL - value= 0; + reset(); // We need only 1 row to determinate existence select_lex->master_unit()->global_parameters->select_limit= 1; DBUG_VOID_RETURN; @@ -237,14 +237,15 @@ Item_allany_subselect::Item_allany_subselect(THD *thd, Item * left_exp, void Item_exists_subselect::fix_length_and_dec() { - max_length= 1; + decimals=0; + max_length= 1; } double Item_exists_subselect::val () { if (engine->exec()) { - assign_null(); + reset(); return 0; } return (double) value; @@ -254,7 +255,7 @@ longlong Item_exists_subselect::val_int () { if (engine->exec()) { - assign_null(); + reset(); return 0; } return value; @@ -264,7 +265,50 @@ String *Item_exists_subselect::val_str(String *str) { if (engine->exec()) { - assign_null(); + reset(); + return 0; + } + str->set(value,thd_charset()); + return str; +} + +double Item_in_subselect::val () +{ + if (engine->exec()) + { + reset(); + null_value= 1; + return 0; + } + if (was_null && !value) + null_value= 1; + return (double) value; +} + +longlong Item_in_subselect::val_int () +{ + if (engine->exec()) + { + reset(); + null_value= 1; + return 0; + } + if (was_null && !value) + null_value= 1; + return value; +} + +String *Item_in_subselect::val_str(String *str) +{ + if (engine->exec()) + { + reset(); + null_value= 1; + return 0; + } + if (was_null && !value) + { + null_value= 1; return 0; } str->set(value,thd_charset()); @@ -288,8 +332,23 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex, compare_func_creator func) { DBUG_ENTER("Item_in_subselect::single_value_transformer"); + Item_in_optimizer *optimizer; + substitution= optimizer= new Item_in_optimizer(left_expr, this); + if (!optimizer) + { + current_thd->fatal_error= 1; + DBUG_VOID_RETURN; + } + /* + As far as Item_ref_in_optimizer do not substitude itself on fix_fields + we can use same item for all selects. + */ + Item *expr= new Item_ref_in_optimizer(optimizer, (char *)"", + (char*)""); + select_lex->master_unit()->dependent= 1; for (SELECT_LEX * sl= select_lex; sl; sl= sl->next_select()) { + select_lex->dependent= 1; Item *item; if (sl->item_list.elements > 1) { @@ -299,14 +358,14 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex, else item= (Item*) sl->item_list.pop(); - Item *expr= new Item_outer_select_context_saver(left_expr); - if (sl->having || sl->with_sum_func || sl->group_list.first || sl->order_list.first) { sl->item_list.push_back(item); - item= (*func)(expr, new Item_ref(sl->item_list.head_ref(), - 0, (char*)"")); + item= (*func)(expr, new Item_ref_null_helper(this, + sl->item_list.head_ref(), + (char *)"", + (char*)"")); if (sl->having || sl->with_sum_func || sl->group_list.first) if (sl->having) sl->having= new Item_cond_and(sl->having, item); @@ -324,7 +383,9 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex, sl->item_list.push_back(new Item_int(1)); if (sl->table_list.elements) { - item= (*func)(expr, new Item_asterisk_remover(item)); + item= (*func)(expr, new Item_asterisk_remover(this, item, + (char *)"", + (char*)"")); if (sl->where) sl->where= new Item_cond_and(sl->where, item); else @@ -340,14 +401,21 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex, } if (select_lex->next_select()) { - // it is in union => we should perform it - sl->having= (*func)(expr, item); + /* + It is in union => we should perform it. + Item_asterisk_remover used only as wrapper to receine NULL value + */ + sl->having= (*func)(expr, + new Item_asterisk_remover(this, item, + (char *)"", + (char*)"")); } else { // it is single select without tables => possible optimization item= (*func)(left_expr, item); substitution= item; + have_to_be_excluded= 1; THD *thd= current_thd; if (thd->lex.describe) { @@ -489,7 +557,7 @@ int subselect_single_select_engine::exec() join->thd->where= save_where; DBUG_RETURN(1); } - item->assign_null(); + item->reset(); item->assigned((executed= 0)); } if (!executed) diff --git a/sql/item_subselect.h b/sql/item_subselect.h index d323dab51f1..adae0831c22 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -42,6 +42,8 @@ protected: subselect_engine *engine; /* allowed number of columns (1 for single value subqueries) */ uint max_columns; + /* work with 'substitution' */ + bool have_to_be_excluded; public: Item_subselect(); @@ -65,7 +67,7 @@ public: select_subselect *result); ~Item_subselect(); - virtual void assign_null() + virtual void reset() { null_value= 1; } @@ -110,7 +112,7 @@ public: decimals= item->decimals; res_type= item->res_type; } - virtual void assign_null() + virtual void reset() { null_value= 1; int_value= 0; @@ -144,7 +146,7 @@ public: } Item_exists_subselect(): Item_subselect() {} - virtual void assign_null() + virtual void reset() { value= 0; } @@ -155,6 +157,7 @@ public: double val(); String *val_str(String*); void fix_length_and_dec(); + friend class select_exists_subselect; }; @@ -164,14 +167,26 @@ class Item_in_subselect :public Item_exists_subselect { protected: Item * left_expr; - + bool was_null; public: Item_in_subselect(THD *thd, Item * left_expr, st_select_lex *select_lex); Item_in_subselect(Item_in_subselect *item); Item_in_subselect(): Item_exists_subselect() {} + void reset() + { + value= 0; + null_value= 0; + was_null= 0; + } virtual void select_transformer(st_select_lex *select_lex); void single_value_transformer(st_select_lex *select_lex, Item *left_expr, compare_func_creator func); + longlong val_int(); + double val(); + String *val_str(String*); + + friend class Item_asterisk_remover; + friend class Item_ref_null_helper; }; /* ALL/ANY/SOME subselect */ diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 4a2d716c953..7bed3541777 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -253,12 +253,24 @@ double Item_sum_avg::val() ** Standard deviation */ -void Item_sum_std::reset() +double Item_sum_std::val() { - sum=sum_sqr=0.0; count=0; (void) Item_sum_std::add(); + double tmp= Item_sum_variance::val(); + return tmp <= 0.0 ? 0.0 : sqrt(tmp); } -bool Item_sum_std::add() +/* +** variance +*/ + +void Item_sum_variance::reset() +{ + sum=sum_sqr=0.0; + count=0; + (void) Item_sum_variance::add(); +} + +bool Item_sum_variance::add() { double nr=args[0]->val(); if (!args[0]->null_value) @@ -270,7 +282,7 @@ bool Item_sum_std::add() return 0; } -double Item_sum_std::val() +double Item_sum_variance::val() { if (!count) { @@ -281,11 +293,10 @@ double Item_sum_std::val() /* Avoid problems when the precision isn't good enough */ double tmp=ulonglong2double(count); double tmp2=(sum_sqr - sum*sum/tmp)/tmp; - return tmp2 <= 0.0 ? 0.0 : sqrt(tmp2); + return tmp2 <= 0.0 ? 0.0 : tmp2; } - -void Item_sum_std::reset_field() +void Item_sum_variance::reset_field() { double nr=args[0]->val(); char *res=result_field->ptr; @@ -302,7 +313,7 @@ void Item_sum_std::reset_field() } } -void Item_sum_std::update_field(int offset) +void Item_sum_variance::update_field(int offset) { double nr,old_nr,old_sqr; longlong field_count; @@ -836,6 +847,17 @@ String *Item_avg_field::val_str(String *str) } Item_std_field::Item_std_field(Item_sum_std *item) + : Item_variance_field(item) +{ +} + +double Item_std_field::val() +{ + double tmp= Item_variance_field::val(); + return tmp <= 0.0 ? 0.0 : sqrt(tmp); +} + +Item_variance_field::Item_variance_field(Item_sum_variance *item) { name=item->name; decimals=item->decimals; @@ -844,7 +866,7 @@ Item_std_field::Item_std_field(Item_sum_std *item) maybe_null=1; } -double Item_std_field::val() +double Item_variance_field::val() { double sum,sum_sqr; longlong count; @@ -860,10 +882,10 @@ double Item_std_field::val() null_value=0; double tmp= (double) count; double tmp2=(sum_sqr - sum*sum/tmp)/tmp; - return tmp2 <= 0.0 ? 0.0 : sqrt(tmp2); + return tmp2 <= 0.0 ? 0.0 : tmp2; } -String *Item_std_field::val_str(String *str) +String *Item_variance_field::val_str(String *str) { double nr=val(); if (null_value) diff --git a/sql/item_sum.h b/sql/item_sum.h index 23b8482d41a..b5665c3cf8c 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -27,7 +27,7 @@ class Item_sum :public Item_result_field { public: enum Sumfunctype {COUNT_FUNC,COUNT_DISTINCT_FUNC,SUM_FUNC,AVG_FUNC,MIN_FUNC, - MAX_FUNC, UNIQUE_USERS_FUNC,STD_FUNC,SUM_BIT_FUNC, + MAX_FUNC, UNIQUE_USERS_FUNC,STD_FUNC,VARIANCE_FUNC,SUM_BIT_FUNC, UDF_SUM_FUNC }; Item **args,*tmp_args[2]; @@ -235,14 +235,14 @@ class Item_sum_avg :public Item_sum_num const char *func_name() const { return "avg"; } }; -class Item_sum_std; +class Item_sum_variance; -class Item_std_field :public Item_result_field +class Item_variance_field :public Item_result_field { public: Field *field; - Item_std_field(Item_sum_std *item); - enum Type type() const { return FIELD_STD_ITEM; } + Item_variance_field(Item_sum_variance *item); + enum Type type() const {return FIELD_VARIANCE_ITEM; } double val(); longlong val_int() { return (longlong) val(); } String *val_str(String*); @@ -251,26 +251,63 @@ public: void fix_length_and_dec() {} }; -class Item_sum_std :public Item_sum_num +/* + +variance(a) = + += sum (ai - avg(a))^2 / count(a) ) += sum (ai^2 - 2*ai*avg(a) + avg(a)^2) / count(a) += (sum(ai^2) - sum(2*ai*avg(a)) + sum(avg(a)^2))/count(a) = += (sum(ai^2) - 2*avg(a)*sum(a) + count(a)*avg(a)^2)/count(a) = += (sum(ai^2) - 2*sum(a)*sum(a)/count(a) + count(a)*sum(a)^2/count(a)^2 )/count(a) = += (sum(ai^2) - 2*sum(a)^2/count(a) + sum(a)^2/count(a) )/count(a) = += (sum(ai^2) - sum(a)^2/count(a))/count(a) + +*/ + +class Item_sum_variance : public Item_sum_num { - double sum; - double sum_sqr; + double sum, sum_sqr; ulonglong count; void fix_length_and_dec() { decimals+=4; maybe_null=1; } public: - Item_sum_std(Item *item_par) :Item_sum_num(item_par),count(0) {} - enum Sumfunctype sum_func () const { return STD_FUNC; } + Item_sum_variance(Item *item_par) :Item_sum_num(item_par),count(0) {} + enum Sumfunctype sum_func () const { return VARIANCE_FUNC; } void reset(); bool add(); double val(); void reset_field(); void update_field(int offset); Item *result_item(Field *field) - { return new Item_std_field(this); } - const char *func_name() const { return "std"; } + { return new Item_variance_field(this); } + const char *func_name() const { return "variance"; } }; +class Item_sum_std; + +class Item_std_field :public Item_variance_field +{ +public: + Item_std_field(Item_sum_std *item); + enum Type type() const { return FIELD_STD_ITEM; } + double val(); +}; + +/* + standard_deviation(a) = sqrt(variance(a)) +*/ + +class Item_sum_std :public Item_sum_variance +{ + public: + Item_sum_std(Item *item_par) :Item_sum_variance(item_par){} + enum Sumfunctype sum_func () const { return STD_FUNC; } + double val(); + Item *result_item(Field *field) + { return new Item_std_field(this); } + const char *func_name() const { return "std"; } +}; // This class is a string or number function depending on num_func diff --git a/sql/lex.h b/sql/lex.h index eb03c0b36ec..421ac933f50 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -344,6 +344,7 @@ static SYMBOL symbols[] = { { "SQL_NO_CACHE", SYM(SQL_NO_CACHE_SYM), 0, 0}, { "SQL_SMALL_RESULT", SYM(SQL_SMALL_RESULT),0,0}, { "SQL_THREAD", SYM(SQL_THREAD),0,0}, + { "SOUNDS", SYM(SOUNDS_SYM),0,0}, { "SSL", SYM(SSL_SYM),0,0}, { "STRAIGHT_JOIN", SYM(STRAIGHT_JOIN),0,0}, { "START", SYM(START_SYM),0,0}, @@ -584,6 +585,7 @@ static SYMBOL sql_functions[] = { { "UNIX_TIMESTAMP", SYM(UNIX_TIMESTAMP),0,0}, { "UPPER", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ucase)}, { "USER", SYM(USER),0,0}, + { "VARIANCE", SYM(VARIANCE_SYM),0,0}, { "VERSION", SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_version)}, { "WEEK", SYM(WEEK_SYM),0,0}, { "WEEKDAY", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_weekday)}, diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 811713bec15..9de04ac3454 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -184,7 +184,6 @@ static uint handler_count; static bool opt_enable_named_pipe = 0; #endif #ifdef __WIN__ -static bool opt_console=0,start_mode=0; static pthread_cond_t COND_handler_count; static uint handler_count; static bool opt_console=0, start_mode=0, use_opt_args; @@ -2160,7 +2159,7 @@ The server will not act as a slave."); (void) thr_setconcurrency(concurrency); // 10 by default #if defined(__WIN__) && !defined(EMBEDDED_LIBRARY) //IRENA { - hEventShutdown=CreateEvent(0, FALSE, FALSE, event_name); + hEventShutdown=CreateEvent(0, FALSE, FALSE, shutdown_event_name); pthread_t hThread; if (pthread_create(&hThread,&connection_attrib,handle_shutdown,0)) sql_print_error("Warning: Can't create thread to handle shutdown requests"); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index ebd1d9d2b3c..ba6369b0022 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -933,9 +933,9 @@ bool select_singleval_subselect::send_data(List &items) calculate value on it & determinate "is it NULL?". */ it->real_value= val_item->val_result(); - if ((it->null_value= val_item->is_null_result())) + if ((it->null_value= val_item->null_value)) { - it->assign_null(); + it->reset(); } else { diff --git a/sql/sql_list.h b/sql/sql_list.h index 56e6528f214..1711a340cae 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -25,8 +25,16 @@ class Sql_alloc { public: - static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); } + static void *operator new(size_t size) + { + return (void*) sql_alloc((uint) size); + } + static void *operator new[](size_t size) + { + return (void*) sql_alloc((uint) size); + } static void operator delete(void *ptr, size_t size) {} /*lint -e715 */ + static void operator delete[](void *ptr, size_t size) {} #ifdef HAVE_purify bool dummy; inline Sql_alloc() :dummy(0) {} diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 2fba71cab47..fe0cd02d056 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -793,6 +793,16 @@ JOIN::exec() HA_POS_ERROR))) DBUG_VOID_RETURN; + /* + We don't have to store rows in temp table that doesn't match HAVING if: + - we are sorting the table and writing complete group rows to the + temp table. + - We are using DISTINCT without resolving the distinct as a GROUP BY + on all columns. + + If having is not handled here, it will be checked before the row + is sent to the client. + */ if (having_list && (sort_and_group || (exec_tmp_table->distinct && !group_list))) having=having_list; @@ -3775,13 +3785,14 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, else return new Field_double(item_sum->max_length,maybe_null, item->name, table, item_sum->decimals); - case Item_sum::STD_FUNC: /* Place for sum & count */ + case Item_sum::VARIANCE_FUNC: /* Place for sum & count */ + case Item_sum::STD_FUNC: if (group) return new Field_string(sizeof(double)*2+sizeof(longlong), maybe_null, item->name,table,my_charset_bin); else return new Field_double(item_sum->max_length, maybe_null, - item->name,table,item_sum->decimals); + item->name,table,item_sum->decimals); case Item_sum::UNIQUE_USERS_FUNC: return new Field_long(9,maybe_null,item->name,table,1); default: diff --git a/sql/sql_union.cc b/sql/sql_union.cc index d3143725878..10175bfe345 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -216,7 +216,7 @@ int st_select_lex_unit::exec() if (optimized && item && item->assigned()) { item->assigned(0); // We will reinit & rexecute unit - item->assign_null(); + item->reset(); table->file->delete_all_rows(); } for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c1057033bd4..8e947ec7587 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -100,6 +100,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token DIV_SYM %token EQ %token EQUAL_SYM +%token SOUNDS_SYM %token GE %token GT_SYM %token LE @@ -158,6 +159,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token SQL_THREAD %token START_SYM %token STD_SYM +%token VARIANCE_SYM %token STOP_SYM %token SUM_SYM %token SUPER_SYM @@ -1833,6 +1835,7 @@ expr_expr: | expr OR expr { $$= new Item_cond_or($1,$3); } | expr XOR expr { $$= new Item_cond_xor($1,$3); } | expr AND expr { $$= new Item_cond_and($1,$3); } + | expr SOUNDS_SYM LIKE expr { $$= Item_bool_func2::eq_creator(new Item_func_soundex($1), new Item_func_soundex($4));} | expr LIKE simple_expr opt_escape { $$= new Item_func_like($1,$3,$4); } | expr NOT LIKE simple_expr opt_escape { $$= new Item_func_not(new Item_func_like($1,$4,$5));} | expr REGEXP expr { $$= new Item_func_regex($1,$3); } @@ -1879,6 +1882,7 @@ no_in_expr: | no_in_expr OR expr { $$= new Item_cond_or($1,$3); } | no_in_expr XOR expr { $$= new Item_cond_xor($1,$3); } | no_in_expr AND expr { $$= new Item_cond_and($1,$3); } + | no_in_expr SOUNDS_SYM LIKE expr { $$= Item_bool_func2::eq_creator(new Item_func_soundex($1), new Item_func_soundex($4));} | no_in_expr LIKE simple_expr opt_escape { $$= new Item_func_like($1,$3,$4); } | no_in_expr NOT LIKE simple_expr opt_escape { $$= new Item_func_not(new Item_func_like($1,$4,$5)); } | no_in_expr REGEXP expr { $$= new Item_func_regex($1,$3); } @@ -1933,6 +1937,7 @@ no_and_expr: | no_and_expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); } | no_and_expr OR expr { $$= new Item_cond_or($1,$3); } | no_and_expr XOR expr { $$= new Item_cond_xor($1,$3); } + | no_and_expr SOUNDS_SYM LIKE expr { $$= Item_bool_func2::eq_creator(new Item_func_soundex($1), new Item_func_soundex($4));} | no_and_expr LIKE simple_expr opt_escape { $$= new Item_func_like($1,$3,$4); } | no_and_expr NOT LIKE simple_expr opt_escape { $$= new Item_func_not(new Item_func_like($1,$4,$5)); } | no_and_expr REGEXP expr { $$= new Item_func_regex($1,$3); } @@ -2335,6 +2340,8 @@ sum_expr: { $$=new Item_sum_max($3); } | STD_SYM '(' in_sum_expr ')' { $$=new Item_sum_std($3); } + | VARIANCE_SYM '(' in_sum_expr ')' + { $$=new Item_sum_variance($3); } | SUM_SYM '(' in_sum_expr ')' { $$=new Item_sum_sum($3); }; @@ -3870,6 +3877,7 @@ keyword: | VALUE_SYM {} | WORK_SYM {} | YEAR_SYM {} + | SOUNDS_SYM {} ; /* Option functions */