From 7b797fe66d7167a8f5cbb071a06a640a627f2186 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Wed, 4 May 2011 18:08:58 +0300 Subject: [PATCH 1/2] Moving max/min optimization from prepare to optimization phase. MWL#148 mysql-test/r/explain.result: fixed results (new item) mysql-test/r/subselect.result: fixed results (new item) mysql-test/r/subselect_no_mat.result: fixed results (new item) mysql-test/r/subselect_no_opts.result: fixed results (new item) mysql-test/r/subselect_no_semijoin.result: Fixed results (new item) mysql-test/suite/pbxt/r/subselect.result: Fixed results (new item) mysql-test/t/explain.test: Fixed results (correct behaviour) sql/item_cmpfunc.cc: Pass through for max/min sql/item_subselect.cc: moving max/min sql/item_subselect.h: moving max/min sql/mysql_priv.h: new uncacheble flags added sql/opt_subselect.cc: maxmin moved. sql/opt_subselect.h: New function for maxmin. sql/sql_class.h: debug code sql/sql_lex.cc: Fixed flags. Limit setting fixed. sql/sql_lex.h: 2 new flags. sql/sql_select.cc: Prepare divided on 2 function to be able recollect some info after transformation. sql/sql_select.h: Prepare divided on 2 functions. --- mysql-test/r/explain.result | 18 +- mysql-test/r/subselect.result | 22 +- mysql-test/r/subselect_no_mat.result | 22 +- mysql-test/r/subselect_no_opts.result | 22 +- mysql-test/r/subselect_no_semijoin.result | 22 +- mysql-test/suite/pbxt/r/subselect.result | 22 +- mysql-test/t/explain.test | 5 +- sql/item_cmpfunc.cc | 57 +++-- sql/item_subselect.cc | 291 +++++++++++++--------- sql/item_subselect.h | 34 ++- sql/mysql_priv.h | 16 +- sql/opt_subselect.cc | 45 +++- sql/opt_subselect.h | 1 + sql/sql_class.h | 7 +- sql/sql_lex.cc | 20 +- sql/sql_lex.h | 3 +- sql/sql_select.cc | 43 +++- sql/sql_select.h | 1 + 18 files changed, 415 insertions(+), 236 deletions(-) diff --git a/mysql-test/r/explain.result b/mysql-test/r/explain.result index 75f05478c82..c990d33635a 100644 --- a/mysql-test/r/explain.result +++ b/mysql-test/r/explain.result @@ -176,11 +176,15 @@ SELECT @@session.sql_mode INTO @old_sql_mode; SET SESSION sql_mode='ONLY_FULL_GROUP_BY'; EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE f1 > ALL( SELECT t.f1 FROM t1,t1 AS t ); -ERROR 42000: Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +2 SUBQUERY t1 system NULL NULL NULL NULL 0 0.00 const row not found +2 SUBQUERY t system NULL NULL NULL NULL 0 0.00 const row not found +Warnings: +Note 1003 select 1 AS `1` from `test`.`t1` where 0 SHOW WARNINGS; Level Code Message -Error 1140 Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause -Note 1003 select 1 AS `1` from `test`.`t1` where ((...)) +Note 1003 select 1 AS `1` from `test`.`t1` where 0 SET SESSION sql_mode=@old_sql_mode; DROP TABLE t1; End of 5.0 tests. @@ -272,12 +276,12 @@ PREPARE stmt FROM EXECUTE stmt; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 -2 SUBQUERY a system NULL NULL NULL NULL 1 Using filesort +2 SUBQUERY a system NULL NULL NULL NULL 1 2 SUBQUERY t1 fulltext f1 f1 0 1 Using where EXECUTE stmt; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 -2 SUBQUERY a system NULL NULL NULL NULL 1 Using filesort +2 SUBQUERY a system NULL NULL NULL NULL 1 2 SUBQUERY t1 fulltext f1 f1 0 1 Using where DEALLOCATE PREPARE stmt; PREPARE stmt FROM @@ -288,12 +292,12 @@ PREPARE stmt FROM EXECUTE stmt; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 -2 SUBQUERY a system NULL NULL NULL NULL 1 Using filesort +2 SUBQUERY a system NULL NULL NULL NULL 1 2 SUBQUERY t1 fulltext f1 f1 0 1 Using where EXECUTE stmt; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 system NULL NULL NULL NULL 1 -2 SUBQUERY a system NULL NULL NULL NULL 1 Using filesort +2 SUBQUERY a system NULL NULL NULL NULL 1 2 SUBQUERY t1 fulltext f1 f1 0 1 Using where DEALLOCATE PREPARE stmt; DROP TABLE t1; diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index b57cdb16562..539382aa092 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -273,7 +273,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00 Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` >= (select min(`test`.`t2`.`b`) from `test`.`t2`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` >= (select min(`test`.`t2`.`b`) from `test`.`t2`)))) select * from t3 where a >= all (select b from t2); a 7 @@ -1503,7 +1503,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` < (select max(NULL) from `test`.`t2`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` < (select max(NULL) from `test`.`t2`)))) select * from t3 where a >= some (select b from t2); a explain extended select * from t3 where a >= some (select b from t2); @@ -1511,7 +1511,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` >= (select min(NULL) from `test`.`t2`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` >= (select min(NULL) from `test`.`t2`)))) select * from t3 where a >= all (select b from t2 group by 1); a 6 @@ -1522,7 +1522,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` < (select NULL from `test`.`t2` group by 1))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` < (select NULL from `test`.`t2` group by 1)))) select * from t3 where a >= some (select b from t2 group by 1); a explain extended select * from t3 where a >= some (select b from t2 group by 1); @@ -1530,7 +1530,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` >= (select NULL from `test`.`t2` group by 1))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` >= (select NULL from `test`.`t2` group by 1)))) select * from t3 where NULL >= any (select b from t2); a explain extended select * from t3 where NULL >= any (select b from t2); @@ -1538,7 +1538,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL >= (select min(NULL) from `test`.`t2`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,(NULL >= (select min(NULL) from `test`.`t2`)))) select * from t3 where NULL >= any (select b from t2 group by 1); a explain extended select * from t3 where NULL >= any (select b from t2 group by 1); @@ -1546,7 +1546,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL >= (select NULL from `test`.`t2` group by 1))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,(NULL >= (select NULL from `test`.`t2` group by 1)))) select * from t3 where NULL >= some (select b from t2); a explain extended select * from t3 where NULL >= some (select b from t2); @@ -1554,7 +1554,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL >= (select min(NULL) from `test`.`t2`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,(NULL >= (select min(NULL) from `test`.`t2`)))) select * from t3 where NULL >= some (select b from t2 group by 1); a explain extended select * from t3 where NULL >= some (select b from t2 group by 1); @@ -1562,7 +1562,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL >= (select NULL from `test`.`t2` group by 1))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,(NULL >= (select NULL from `test`.`t2` group by 1)))) insert into t2 values (2,2), (2,1), (3,3), (3,1); select * from t3 where a > all (select max(b) from t2 group by a); a @@ -1573,7 +1573,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 ALL NULL NULL NULL NULL 4 100.00 Using temporary Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` <= (select max(`test`.`t2`.`b`) from `test`.`t2` group by `test`.`t2`.`a`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` <= (select max(`test`.`t2`.`b`) from `test`.`t2` group by `test`.`t2`.`a`)))) drop table t2, t3; CREATE TABLE `t1` ( `id` mediumint(9) NOT NULL auto_increment, `taskid` bigint(20) NOT NULL default '0', `dbid` int(11) NOT NULL default '0', `create_date` datetime NOT NULL default '0000-00-00 00:00:00', `last_update` datetime NOT NULL default '0000-00-00 00:00:00', PRIMARY KEY (`id`)) ENGINE=MyISAM CHARSET=latin1 AUTO_INCREMENT=3 ; INSERT INTO `t1` (`id`, `taskid`, `dbid`, `create_date`,`last_update`) VALUES (1, 1, 15, '2003-09-29 10:31:36', '2003-09-29 10:31:36'), (2, 1, 21, now(), now()); @@ -1624,7 +1624,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 3 UNION t1 system NULL NULL NULL NULL 1 100.00 NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL Warnings: -Note 1003 select 'e' AS `s1` from `test`.`t1` where (('f' > (select 'e' from `test`.`t1` union select 'e' from `test`.`t1`))) +Note 1003 select 'e' AS `s1` from `test`.`t1` where (('f',('f' > (select 'e' from `test`.`t1` union select 'e' from `test`.`t1`)))) drop table t1; CREATE TABLE t1 (number char(11) NOT NULL default '') ENGINE=MyISAM CHARSET=latin1; INSERT INTO t1 VALUES ('69294728265'),('18621828126'),('89356874041'),('95895001874'); diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result index c693f21798c..97674ef3a0f 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -277,7 +277,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00 Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` >= (select min(`test`.`t2`.`b`) from `test`.`t2`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` >= (select min(`test`.`t2`.`b`) from `test`.`t2`)))) select * from t3 where a >= all (select b from t2); a 7 @@ -1507,7 +1507,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` < (select max(NULL) from `test`.`t2`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` < (select max(NULL) from `test`.`t2`)))) select * from t3 where a >= some (select b from t2); a explain extended select * from t3 where a >= some (select b from t2); @@ -1515,7 +1515,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` >= (select min(NULL) from `test`.`t2`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` >= (select min(NULL) from `test`.`t2`)))) select * from t3 where a >= all (select b from t2 group by 1); a 6 @@ -1526,7 +1526,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` < (select NULL from `test`.`t2` group by 1))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` < (select NULL from `test`.`t2` group by 1)))) select * from t3 where a >= some (select b from t2 group by 1); a explain extended select * from t3 where a >= some (select b from t2 group by 1); @@ -1534,7 +1534,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` >= (select NULL from `test`.`t2` group by 1))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` >= (select NULL from `test`.`t2` group by 1)))) select * from t3 where NULL >= any (select b from t2); a explain extended select * from t3 where NULL >= any (select b from t2); @@ -1542,7 +1542,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL >= (select min(NULL) from `test`.`t2`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,(NULL >= (select min(NULL) from `test`.`t2`)))) select * from t3 where NULL >= any (select b from t2 group by 1); a explain extended select * from t3 where NULL >= any (select b from t2 group by 1); @@ -1550,7 +1550,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL >= (select NULL from `test`.`t2` group by 1))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,(NULL >= (select NULL from `test`.`t2` group by 1)))) select * from t3 where NULL >= some (select b from t2); a explain extended select * from t3 where NULL >= some (select b from t2); @@ -1558,7 +1558,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL >= (select min(NULL) from `test`.`t2`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,(NULL >= (select min(NULL) from `test`.`t2`)))) select * from t3 where NULL >= some (select b from t2 group by 1); a explain extended select * from t3 where NULL >= some (select b from t2 group by 1); @@ -1566,7 +1566,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL >= (select NULL from `test`.`t2` group by 1))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,(NULL >= (select NULL from `test`.`t2` group by 1)))) insert into t2 values (2,2), (2,1), (3,3), (3,1); select * from t3 where a > all (select max(b) from t2 group by a); a @@ -1577,7 +1577,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 ALL NULL NULL NULL NULL 4 100.00 Using temporary Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` <= (select max(`test`.`t2`.`b`) from `test`.`t2` group by `test`.`t2`.`a`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` <= (select max(`test`.`t2`.`b`) from `test`.`t2` group by `test`.`t2`.`a`)))) drop table t2, t3; CREATE TABLE `t1` ( `id` mediumint(9) NOT NULL auto_increment, `taskid` bigint(20) NOT NULL default '0', `dbid` int(11) NOT NULL default '0', `create_date` datetime NOT NULL default '0000-00-00 00:00:00', `last_update` datetime NOT NULL default '0000-00-00 00:00:00', PRIMARY KEY (`id`)) ENGINE=MyISAM CHARSET=latin1 AUTO_INCREMENT=3 ; INSERT INTO `t1` (`id`, `taskid`, `dbid`, `create_date`,`last_update`) VALUES (1, 1, 15, '2003-09-29 10:31:36', '2003-09-29 10:31:36'), (2, 1, 21, now(), now()); @@ -1628,7 +1628,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 3 UNION t1 system NULL NULL NULL NULL 1 100.00 NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL Warnings: -Note 1003 select 'e' AS `s1` from `test`.`t1` where (('f' > (select 'e' from `test`.`t1` union select 'e' from `test`.`t1`))) +Note 1003 select 'e' AS `s1` from `test`.`t1` where (('f',('f' > (select 'e' from `test`.`t1` union select 'e' from `test`.`t1`)))) drop table t1; CREATE TABLE t1 (number char(11) NOT NULL default '') ENGINE=MyISAM CHARSET=latin1; INSERT INTO t1 VALUES ('69294728265'),('18621828126'),('89356874041'),('95895001874'); diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result index 07b5d5d72ac..a2721c2b7f3 100644 --- a/mysql-test/r/subselect_no_opts.result +++ b/mysql-test/r/subselect_no_opts.result @@ -274,7 +274,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00 Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` >= (select min(`test`.`t2`.`b`) from `test`.`t2`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` >= (select min(`test`.`t2`.`b`) from `test`.`t2`)))) select * from t3 where a >= all (select b from t2); a 7 @@ -1504,7 +1504,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` < (select max(NULL) from `test`.`t2`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` < (select max(NULL) from `test`.`t2`)))) select * from t3 where a >= some (select b from t2); a explain extended select * from t3 where a >= some (select b from t2); @@ -1512,7 +1512,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` >= (select min(NULL) from `test`.`t2`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` >= (select min(NULL) from `test`.`t2`)))) select * from t3 where a >= all (select b from t2 group by 1); a 6 @@ -1523,7 +1523,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` < (select NULL from `test`.`t2` group by 1))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` < (select NULL from `test`.`t2` group by 1)))) select * from t3 where a >= some (select b from t2 group by 1); a explain extended select * from t3 where a >= some (select b from t2 group by 1); @@ -1531,7 +1531,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` >= (select NULL from `test`.`t2` group by 1))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` >= (select NULL from `test`.`t2` group by 1)))) select * from t3 where NULL >= any (select b from t2); a explain extended select * from t3 where NULL >= any (select b from t2); @@ -1539,7 +1539,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL >= (select min(NULL) from `test`.`t2`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,(NULL >= (select min(NULL) from `test`.`t2`)))) select * from t3 where NULL >= any (select b from t2 group by 1); a explain extended select * from t3 where NULL >= any (select b from t2 group by 1); @@ -1547,7 +1547,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL >= (select NULL from `test`.`t2` group by 1))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,(NULL >= (select NULL from `test`.`t2` group by 1)))) select * from t3 where NULL >= some (select b from t2); a explain extended select * from t3 where NULL >= some (select b from t2); @@ -1555,7 +1555,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL >= (select min(NULL) from `test`.`t2`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,(NULL >= (select min(NULL) from `test`.`t2`)))) select * from t3 where NULL >= some (select b from t2 group by 1); a explain extended select * from t3 where NULL >= some (select b from t2 group by 1); @@ -1563,7 +1563,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL >= (select NULL from `test`.`t2` group by 1))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,(NULL >= (select NULL from `test`.`t2` group by 1)))) insert into t2 values (2,2), (2,1), (3,3), (3,1); select * from t3 where a > all (select max(b) from t2 group by a); a @@ -1574,7 +1574,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 ALL NULL NULL NULL NULL 4 100.00 Using temporary Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` <= (select max(`test`.`t2`.`b`) from `test`.`t2` group by `test`.`t2`.`a`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` <= (select max(`test`.`t2`.`b`) from `test`.`t2` group by `test`.`t2`.`a`)))) drop table t2, t3; CREATE TABLE `t1` ( `id` mediumint(9) NOT NULL auto_increment, `taskid` bigint(20) NOT NULL default '0', `dbid` int(11) NOT NULL default '0', `create_date` datetime NOT NULL default '0000-00-00 00:00:00', `last_update` datetime NOT NULL default '0000-00-00 00:00:00', PRIMARY KEY (`id`)) ENGINE=MyISAM CHARSET=latin1 AUTO_INCREMENT=3 ; INSERT INTO `t1` (`id`, `taskid`, `dbid`, `create_date`,`last_update`) VALUES (1, 1, 15, '2003-09-29 10:31:36', '2003-09-29 10:31:36'), (2, 1, 21, now(), now()); @@ -1625,7 +1625,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 3 UNION t1 system NULL NULL NULL NULL 1 100.00 NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL Warnings: -Note 1003 select 'e' AS `s1` from `test`.`t1` where (('f' > (select 'e' from `test`.`t1` union select 'e' from `test`.`t1`))) +Note 1003 select 'e' AS `s1` from `test`.`t1` where (('f',('f' > (select 'e' from `test`.`t1` union select 'e' from `test`.`t1`)))) drop table t1; CREATE TABLE t1 (number char(11) NOT NULL default '') ENGINE=MyISAM CHARSET=latin1; INSERT INTO t1 VALUES ('69294728265'),('18621828126'),('89356874041'),('95895001874'); diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result index 63b12e4df5f..f8580b525d7 100644 --- a/mysql-test/r/subselect_no_semijoin.result +++ b/mysql-test/r/subselect_no_semijoin.result @@ -274,7 +274,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00 Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` >= (select min(`test`.`t2`.`b`) from `test`.`t2`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` >= (select min(`test`.`t2`.`b`) from `test`.`t2`)))) select * from t3 where a >= all (select b from t2); a 7 @@ -1504,7 +1504,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` < (select max(NULL) from `test`.`t2`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` < (select max(NULL) from `test`.`t2`)))) select * from t3 where a >= some (select b from t2); a explain extended select * from t3 where a >= some (select b from t2); @@ -1512,7 +1512,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` >= (select min(NULL) from `test`.`t2`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` >= (select min(NULL) from `test`.`t2`)))) select * from t3 where a >= all (select b from t2 group by 1); a 6 @@ -1523,7 +1523,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` < (select NULL from `test`.`t2` group by 1))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` < (select NULL from `test`.`t2` group by 1)))) select * from t3 where a >= some (select b from t2 group by 1); a explain extended select * from t3 where a >= some (select b from t2 group by 1); @@ -1531,7 +1531,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` >= (select NULL from `test`.`t2` group by 1))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` >= (select NULL from `test`.`t2` group by 1)))) select * from t3 where NULL >= any (select b from t2); a explain extended select * from t3 where NULL >= any (select b from t2); @@ -1539,7 +1539,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL >= (select min(NULL) from `test`.`t2`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,(NULL >= (select min(NULL) from `test`.`t2`)))) select * from t3 where NULL >= any (select b from t2 group by 1); a explain extended select * from t3 where NULL >= any (select b from t2 group by 1); @@ -1547,7 +1547,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL >= (select NULL from `test`.`t2` group by 1))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,(NULL >= (select NULL from `test`.`t2` group by 1)))) select * from t3 where NULL >= some (select b from t2); a explain extended select * from t3 where NULL >= some (select b from t2); @@ -1555,7 +1555,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL >= (select min(NULL) from `test`.`t2`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,(NULL >= (select min(NULL) from `test`.`t2`)))) select * from t3 where NULL >= some (select b from t2 group by 1); a explain extended select * from t3 where NULL >= some (select b from t2 group by 1); @@ -1563,7 +1563,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 system NULL NULL NULL NULL 0 0.00 const row not found Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL >= (select NULL from `test`.`t2` group by 1))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,(NULL >= (select NULL from `test`.`t2` group by 1)))) insert into t2 values (2,2), (2,1), (3,3), (3,1); select * from t3 where a > all (select max(b) from t2 group by a); a @@ -1574,7 +1574,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 ALL NULL NULL NULL NULL 4 100.00 Using temporary Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` <= (select max(`test`.`t2`.`b`) from `test`.`t2` group by `test`.`t2`.`a`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` <= (select max(`test`.`t2`.`b`) from `test`.`t2` group by `test`.`t2`.`a`)))) drop table t2, t3; CREATE TABLE `t1` ( `id` mediumint(9) NOT NULL auto_increment, `taskid` bigint(20) NOT NULL default '0', `dbid` int(11) NOT NULL default '0', `create_date` datetime NOT NULL default '0000-00-00 00:00:00', `last_update` datetime NOT NULL default '0000-00-00 00:00:00', PRIMARY KEY (`id`)) ENGINE=MyISAM CHARSET=latin1 AUTO_INCREMENT=3 ; INSERT INTO `t1` (`id`, `taskid`, `dbid`, `create_date`,`last_update`) VALUES (1, 1, 15, '2003-09-29 10:31:36', '2003-09-29 10:31:36'), (2, 1, 21, now(), now()); @@ -1625,7 +1625,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 3 UNION t1 system NULL NULL NULL NULL 1 100.00 NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL Warnings: -Note 1003 select 'e' AS `s1` from `test`.`t1` where (('f' > (select 'e' from `test`.`t1` union select 'e' from `test`.`t1`))) +Note 1003 select 'e' AS `s1` from `test`.`t1` where (('f',('f' > (select 'e' from `test`.`t1` union select 'e' from `test`.`t1`)))) drop table t1; CREATE TABLE t1 (number char(11) NOT NULL default '') ENGINE=MyISAM CHARSET=latin1; INSERT INTO t1 VALUES ('69294728265'),('18621828126'),('89356874041'),('95895001874'); diff --git a/mysql-test/suite/pbxt/r/subselect.result b/mysql-test/suite/pbxt/r/subselect.result index 455411c6faf..daa13af72bc 100644 --- a/mysql-test/suite/pbxt/r/subselect.result +++ b/mysql-test/suite/pbxt/r/subselect.result @@ -270,7 +270,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 ALL NULL NULL NULL NULL 3 100.00 Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` >= (select min(`test`.`t2`.`b`) from `test`.`t2`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` >= (select min(`test`.`t2`.`b`) from `test`.`t2`)))) select * from t3 where a >= all (select b from t2); a 7 @@ -1498,7 +1498,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 ALL NULL NULL NULL NULL 0 0.00 Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` < (select max(`test`.`t2`.`b`) from `test`.`t2`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` < (select max(`test`.`t2`.`b`) from `test`.`t2`)))) select * from t3 where a >= some (select b from t2); a explain extended select * from t3 where a >= some (select b from t2); @@ -1506,7 +1506,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 ALL NULL NULL NULL NULL 0 0.00 Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` >= (select min(`test`.`t2`.`b`) from `test`.`t2`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` >= (select min(`test`.`t2`.`b`) from `test`.`t2`)))) select * from t3 where a >= all (select b from t2 group by 1); a 6 @@ -1517,7 +1517,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 ALL NULL NULL NULL NULL 0 0.00 Using temporary Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` < (select `test`.`t2`.`b` from `test`.`t2` group by 1))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` < (select `test`.`t2`.`b` from `test`.`t2` group by 1)))) select * from t3 where a >= some (select b from t2 group by 1); a explain extended select * from t3 where a >= some (select b from t2 group by 1); @@ -1525,7 +1525,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 ALL NULL NULL NULL NULL 0 0.00 Using temporary Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` >= (select `test`.`t2`.`b` from `test`.`t2` group by 1))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` >= (select `test`.`t2`.`b` from `test`.`t2` group by 1)))) select * from t3 where NULL >= any (select b from t2); a explain extended select * from t3 where NULL >= any (select b from t2); @@ -1533,7 +1533,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 ALL NULL NULL NULL NULL 0 0.00 Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL >= (select min(`test`.`t2`.`b`) from `test`.`t2`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,(NULL >= (select min(`test`.`t2`.`b`) from `test`.`t2`)))) select * from t3 where NULL >= any (select b from t2 group by 1); a explain extended select * from t3 where NULL >= any (select b from t2 group by 1); @@ -1541,7 +1541,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 ALL NULL NULL NULL NULL 0 0.00 Using temporary Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL >= (select `test`.`t2`.`b` from `test`.`t2` group by 1))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,(NULL >= (select `test`.`t2`.`b` from `test`.`t2` group by 1)))) select * from t3 where NULL >= some (select b from t2); a explain extended select * from t3 where NULL >= some (select b from t2); @@ -1549,7 +1549,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 ALL NULL NULL NULL NULL 0 0.00 Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL >= (select min(`test`.`t2`.`b`) from `test`.`t2`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,(NULL >= (select min(`test`.`t2`.`b`) from `test`.`t2`)))) select * from t3 where NULL >= some (select b from t2 group by 1); a explain extended select * from t3 where NULL >= some (select b from t2 group by 1); @@ -1557,7 +1557,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 2 SUBQUERY t2 ALL NULL NULL NULL NULL 0 0.00 Using temporary Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL >= (select `test`.`t2`.`b` from `test`.`t2` group by 1))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((NULL,(NULL >= (select `test`.`t2`.`b` from `test`.`t2` group by 1)))) insert into t2 values (2,2), (2,1), (3,3), (3,1); select * from t3 where a > all (select max(b) from t2 group by a); a @@ -1568,7 +1568,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 100.00 Using where 2 SUBQUERY t2 ALL NULL NULL NULL NULL 4 100.00 Using temporary Warnings: -Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a` <= (select max(`test`.`t2`.`b`) from `test`.`t2` group by `test`.`t2`.`a`))) +Note 1003 select `test`.`t3`.`a` AS `a` from `test`.`t3` where ((`test`.`t3`.`a`,(`test`.`t3`.`a` <= (select max(`test`.`t2`.`b`) from `test`.`t2` group by `test`.`t2`.`a`)))) drop table t2, t3; CREATE TABLE `t1` ( `id` mediumint(9) NOT NULL auto_increment, `taskid` bigint(20) NOT NULL default '0', `dbid` int(11) NOT NULL default '0', `create_date` datetime NOT NULL default '0000-00-00 00:00:00', `last_update` datetime NOT NULL default '0000-00-00 00:00:00', PRIMARY KEY (`id`)) ENGINE=MyISAM CHARSET=latin1 AUTO_INCREMENT=3 ; INSERT INTO `t1` (`id`, `taskid`, `dbid`, `create_date`,`last_update`) VALUES (1, 1, 15, '2003-09-29 10:31:36', '2003-09-29 10:31:36'), (2, 1, 21, now(), now()); @@ -1619,7 +1619,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 3 UNION t1 ALL NULL NULL NULL NULL 1 100.00 NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL Warnings: -Note 1003 select `test`.`t1`.`s1` AS `s1` from `test`.`t1` where (('f' > (select `test`.`t1`.`s1` from `test`.`t1` union select `test`.`t1`.`s1` from `test`.`t1`))) +Note 1003 select `test`.`t1`.`s1` AS `s1` from `test`.`t1` where (('f',('f' > (select `test`.`t1`.`s1` from `test`.`t1` union select `test`.`t1`.`s1` from `test`.`t1`)))) drop table t1; CREATE TABLE t1 (number char(11) NOT NULL default '') ENGINE=MyISAM CHARSET=latin1; INSERT INTO t1 VALUES ('69294728265'),('18621828126'),('89356874041'),('95895001874'); diff --git a/mysql-test/t/explain.test b/mysql-test/t/explain.test index c6c30b58341..38d33d44ed2 100644 --- a/mysql-test/t/explain.test +++ b/mysql-test/t/explain.test @@ -158,7 +158,10 @@ SELECT @@session.sql_mode INTO @old_sql_mode; SET SESSION sql_mode='ONLY_FULL_GROUP_BY'; # EXPLAIN EXTENDED (with subselect). used to crash. should give NOTICE. ---error ER_MIX_OF_GROUP_FUNC_AND_FIELDS +# Before moving max/min optimization to optimize phase this statement +# generated error, but as far as original query do not contain aggregate +# function user should not see error +# --error ER_MIX_OF_GROUP_FUNC_AND_FIELDS EXPLAIN EXTENDED SELECT 1 FROM t1 WHERE f1 > ALL( SELECT t.f1 FROM t1,t1 AS t ); SHOW WARNINGS; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 9d8f1397bd7..79eb473cb75 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1798,6 +1798,8 @@ Item *Item_in_optimizer::expr_cache_insert_transformer(uchar *thd_arg) { THD *thd= (THD*) thd_arg; DBUG_ENTER("Item_in_optimizer::expr_cache_insert_transformer"); + if (args[1]->type() != Item::SUBSELECT_ITEM) + DBUG_RETURN(this); // MAX/MIN transformed => do nothing List &depends_on= ((Item_subselect *)args[1])->depends_on; if (expr_cache) @@ -1901,7 +1903,15 @@ longlong Item_in_optimizer::val_int() DBUG_ASSERT(fixed == 1); cache->store(args[0]); cache->cache_value(); - + + if (args[1]->type() != Item::SUBSELECT_ITEM) + { + /* MAX/MIN transformed => pass through */ + longlong res= args[1]->val_int(); + null_value= args[1]->null_value; + return (res); + } + if (cache->null_value) { /* @@ -2050,24 +2060,35 @@ Item *Item_in_optimizer::transform(Item_transformer transformer, uchar *argument if ((*args) != new_item) current_thd->change_item_tree(args, new_item); - /* - Transform the right IN operand which should be an Item_in_subselect or a - subclass of it. The left operand of the IN must be the same as the left - operand of this Item_in_optimizer, so in this case there is no further - transformation, we only make both operands the same. - TODO: is it the way it should be? - */ - DBUG_ASSERT((args[1])->type() == Item::SUBSELECT_ITEM && - (((Item_subselect*)(args[1]))->substype() == - Item_subselect::IN_SUBS || - ((Item_subselect*)(args[1]))->substype() == - Item_subselect::ALL_SUBS || - ((Item_subselect*)(args[1]))->substype() == - Item_subselect::ANY_SUBS)); - - Item_in_subselect *in_arg= (Item_in_subselect*)args[1]; - in_arg->left_expr= args[0]; + if (args[1]->type() != Item::SUBSELECT_ITEM) + { + /* MAX/MIN transformed => pass through */ + new_item= args[1]->transform(transformer, argument); + if (!new_item) + return 0; + if (args[1] != new_item) + current_thd->change_item_tree(args, new_item); + } + else + { + /* + Transform the right IN operand which should be an Item_in_subselect or a + subclass of it. The left operand of the IN must be the same as the left + operand of this Item_in_optimizer, so in this case there is no further + transformation, we only make both operands the same. + TODO: is it the way it should be? + */ + DBUG_ASSERT((args[1])->type() == Item::SUBSELECT_ITEM && + (((Item_subselect*)(args[1]))->substype() == + Item_subselect::IN_SUBS || + ((Item_subselect*)(args[1]))->substype() == + Item_subselect::ALL_SUBS || + ((Item_subselect*)(args[1]))->substype() == + Item_subselect::ANY_SUBS)); + Item_in_subselect *in_arg= (Item_in_subselect*)args[1]; + in_arg->left_expr= args[0]; + } return (this->*transformer)(argument); } diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 459b025870a..c8336bbabce 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -33,12 +33,14 @@ Item_subselect::Item_subselect(): - Item_result_field(), value_assigned(0), thd(0), substitution(0), + Item_result_field(), value_assigned(0), thd(0), substitution(0), expr_cache(0), engine(0), old_engine(0), used_tables_cache(0), have_to_be_excluded(0), const_item_cache(1), inside_first_fix_fields(0), done_first_fix_fields(FALSE), forced_const(FALSE), eliminated(FALSE), engine_changed(0), changed(0), is_correlated(FALSE) { + DBUG_ENTER("Item_subselect::Item_subselect"); + DBUG_PRINT("enter", ("this: 0x%lx", (ulong) this)); with_subselect= 1; reset(); /* @@ -46,6 +48,7 @@ Item_subselect::Item_subselect(): (i.e. some rows will be found returned) */ null_value= TRUE; + DBUG_VOID_RETURN; } @@ -58,7 +61,8 @@ void Item_subselect::init(st_select_lex *select_lex, */ DBUG_ENTER("Item_subselect::init"); - DBUG_PRINT("enter", ("select_lex: 0x%lx", (long) select_lex)); + DBUG_PRINT("enter", ("select_lex: 0x%lx this: 0x%lx", + (ulong) select_lex, (ulong) this)); unit= select_lex->master_unit(); thd= unit->thd; @@ -69,10 +73,12 @@ void Item_subselect::init(st_select_lex *select_lex, => we do not copy old_engine here */ engine= unit->item->engine; + borrowed_engine= TRUE; parsing_place= unit->item->parsing_place; - unit->item->engine= 0; - unit->item= this; - engine->change_result(this, result); + //unit->item->engine= 0; + thd->change_item_tree((Item**)&unit->item, this); + //unit->item= this; + engine->change_result(this, result, TRUE); } else { @@ -97,6 +103,7 @@ void Item_subselect::init(st_select_lex *select_lex, /* The subquery is an expression cache candidate */ upper->expr_cache_may_be_used[upper->parsing_place]= TRUE; } + DBUG_PRINT("info", ("engine: 0x%lx", (ulong)engine)); DBUG_VOID_RETURN; } @@ -156,8 +163,14 @@ void Item_in_subselect::cleanup() Item_subselect::~Item_subselect() { - delete engine; + DBUG_ENTER("Item_subselect::~Item_subselect"); + DBUG_PRINT("enter", ("this: 0x%lx", (ulong) this)); + if (!borrowed_engine) + delete engine; + else + engine->cleanup(); engine= NULL; + DBUG_VOID_RETURN; } bool @@ -1119,11 +1132,23 @@ Item_allany_subselect::Item_allany_subselect(Item * left_exp, void Item_exists_subselect::fix_length_and_dec() { - decimals= 0; - max_length= 1; - max_columns= engine->cols(); + DBUG_ENTER("Item_exists_subselect::fix_length_and_dec"); + decimals= 0; + max_length= 1; + max_columns= engine->cols(); /* We need only 1 row to determine existence */ unit->global_parameters->select_limit= new Item_int((int32) 1); + DBUG_PRINT("info", ("Set limit to 1")); + DBUG_VOID_RETURN; +} + +void Item_in_subselect::fix_length_and_dec() +{ + DBUG_ENTER("Item_in_subselect::fix_length_and_dec"); + decimals= 0; + max_length= 1; + max_columns= engine->cols(); + DBUG_VOID_RETURN; } @@ -1388,88 +1413,6 @@ Item_in_subselect::single_value_transformer(JOIN *join) DBUG_RETURN(true); } - /* - If this is an ALL/ANY single-value subselect, try to rewrite it with - a MIN/MAX subselect. We can do that if a possible NULL result of the - subselect can be ignored. - E.g. SELECT * FROM t1 WHERE b > ANY (SELECT a FROM t2) can be rewritten - with SELECT * FROM t1 WHERE b > (SELECT MAX(a) FROM t2). - We can't check that this optimization is safe if it's not a top-level - item of the WHERE clause (e.g. because the WHERE clause can contain IS - NULL/IS NOT NULL functions). If so, we rewrite ALL/ANY with NOT EXISTS - later in this method. - */ - if ((abort_on_null || (upper_item && upper_item->top_level())) && - !select_lex->master_unit()->uncacheable && !func->eqne_op()) - { - if (substitution) - { - /* It is second (third, ...) SELECT of UNION => All is done */ - DBUG_RETURN(false); - } - - Item *subs; - if (!select_lex->group_list.elements && - !select_lex->having && - !select_lex->with_sum_func && - !(select_lex->next_select()) && - select_lex->table_list.elements) - { - Item_sum_hybrid *item; - nesting_map save_allow_sum_func; - if (func->l_op()) - { - /* - (ALL && (> || =>)) || (ANY && (< || =<)) - for ALL condition is inverted - */ - item= new Item_sum_max(*select_lex->ref_pointer_array); - } - else - { - /* - (ALL && (< || =<)) || (ANY && (> || =>)) - for ALL condition is inverted - */ - item= new Item_sum_min(*select_lex->ref_pointer_array); - } - if (upper_item) - upper_item->set_sum_test(item); - *select_lex->ref_pointer_array= item; - { - List_iterator it(select_lex->item_list); - it++; - it.replace(item); - } - - save_allow_sum_func= thd->lex->allow_sum_func; - thd->lex->allow_sum_func|= 1 << thd->lex->current_select->nest_level; - /* - Item_sum_(max|min) can't substitute other item => we can use 0 as - reference, also Item_sum_(max|min) can't be fixed after creation, so - we do not check item->fixed - */ - if (item->fix_fields(thd, 0)) - DBUG_RETURN(true); - thd->lex->allow_sum_func= save_allow_sum_func; - /* we added aggregate function => we have to change statistic */ - count_field_types(select_lex, &join->tmp_table_param, join->all_fields, - 0); - - subs= new Item_singlerow_subselect(select_lex); - } - else - { - Item_maxmin_subselect *item; - subs= item= new Item_maxmin_subselect(thd, this, select_lex, func->l_op()); - if (upper_item) - upper_item->set_sub_test(item); - } - /* fix fields is already called for left expression */ - substitution= func->create(left_expr, subs); - DBUG_RETURN(false); - } - Item* join_having= join->having ? join->having : join->tmp_having; if (!(join_having || select_lex->with_sum_func || select_lex->group_list.elements) && @@ -1503,7 +1446,6 @@ Item_in_subselect::single_value_transformer(JOIN *join) if (!substitution) { /* We're invoked for the 1st (or the only) SELECT in the subquery UNION */ - SELECT_LEX_UNIT *master_unit= select_lex->master_unit(); substitution= optimizer; SELECT_LEX *current= thd->lex->current_select; @@ -1529,20 +1471,106 @@ Item_in_subselect::single_value_transformer(JOIN *join) (char *)"", (char *)in_left_expr_name); - /* - The uncacheable property controls a number of actions, e.g. whether to - save/restore (via init_save_join_tab/restore_tmp) the original JOIN for - plans with a temp table where the original JOIN was overriden by - make_simple_join. The UNCACHEABLE_EXPLAIN is ignored by EXPLAIN, thus - non-correlated subqueries will not appear as such to EXPLAIN. - */ - master_unit->uncacheable|= UNCACHEABLE_EXPLAIN; - select_lex->uncacheable|= UNCACHEABLE_EXPLAIN; } DBUG_RETURN(false); } +bool Item_allany_subselect::transform_allany(JOIN *join) +{ + DBUG_ENTER("Item_allany_subselect::transform_allany"); + if (!(in_strategy & SUBS_MAXMIN)) + DBUG_RETURN(0); + Item **place= optimizer->arguments() + 1; + THD *thd= join->thd; + SELECT_LEX *select_lex= join->select_lex; + Item *subs; + + /* + If this is an ALL/ANY single-value subselect, try to rewrite it with + a MIN/MAX subselect. We can do that if a possible NULL result of the + subselect can be ignored. + E.g. SELECT * FROM t1 WHERE b > ANY (SELECT a FROM t2) can be rewritten + with SELECT * FROM t1 WHERE b > (SELECT MAX(a) FROM t2). + We can't check that this optimization is safe if it's not a top-level + item of the WHERE clause (e.g. because the WHERE clause can contain IS + NULL/IS NOT NULL functions). If so, we rewrite ALL/ANY with NOT EXISTS + later in this method. + */ + DBUG_ASSERT(!substitution); + + if (!select_lex->group_list.elements && + !select_lex->having && + !select_lex->with_sum_func && + !(select_lex->next_select()) && + select_lex->table_list.elements) + { + Item_sum_hybrid *item; + nesting_map save_allow_sum_func; + if (func->l_op()) + { + /* + (ALL && (> || =>)) || (ANY && (< || =<)) + for ALL condition is inverted + */ + item= new Item_sum_max(*select_lex->ref_pointer_array); + } + else + { + /* + (ALL && (< || =<)) || (ANY && (> || =>)) + for ALL condition is inverted + */ + item= new Item_sum_min(*select_lex->ref_pointer_array); + } + if (upper_item) + upper_item->set_sum_test(item); + thd->change_item_tree(select_lex->ref_pointer_array, item); + { + List_iterator it(select_lex->item_list); + it++; + thd->change_item_tree(it.ref(), item); + } + + save_allow_sum_func= thd->lex->allow_sum_func; + thd->lex->allow_sum_func|= 1 << thd->lex->current_select->nest_level; + /* + Item_sum_(max|min) can't substitute other item => we can use 0 as + reference, also Item_sum_(max|min) can't be fixed after creation, so + we do not check item->fixed + */ + if (item->fix_fields(thd, 0)) + DBUG_RETURN(true); + thd->lex->allow_sum_func= save_allow_sum_func; + /* we added aggregate function => we have to change statistic */ + count_field_types(select_lex, &join->tmp_table_param, join->all_fields, + 0); + if (join->prepare_stage2()) + DBUG_RETURN(true); + subs= new Item_singlerow_subselect(select_lex); + } + else + { + Item_maxmin_subselect *item; + subs= item= new Item_maxmin_subselect(thd, this, select_lex, func->l_op()); + if (upper_item) + upper_item->set_sub_test(item); + } + /* fix fields is already called for left expression */ + subs= func->create(left_expr, subs); + thd->change_item_tree(place, subs); + if (subs->fix_fields(thd, &subs)) + DBUG_RETURN(1); + DBUG_ASSERT(subs == (*place)); // There was no substitutions + + select_lex->master_unit()->uncacheable&= ~UNCACHEABLE_DEPENDENT_INJECTED; + select_lex->uncacheable&= ~UNCACHEABLE_DEPENDENT_INJECTED; + /* remove other strategies if there was (just to be safe) */ + in_strategy= SUBS_MAXMIN; + + DBUG_RETURN(false); +} + bool Item_in_subselect::fix_having(Item *having, SELECT_LEX *select_lex) { @@ -1556,6 +1584,16 @@ bool Item_in_subselect::fix_having(Item *having, SELECT_LEX *select_lex) return fix_res; } +bool Item_allany_subselect::is_maxmin_applicable(JOIN *join) +{ + /* + Check if max/min optimization applicable: It is top item of + WHERE condition. + */ + return (abort_on_null || (upper_item && upper_item->top_level())) && + !join->select_lex->master_unit()->uncacheable && !func->eqne_op(); +} + /** Create the predicates needed to transform a single-column IN/ALL/ANY @@ -2028,7 +2066,7 @@ bool Item_in_subselect::create_in_to_exists_cond(JOIN *join_arg) /* The IN=>EXISTS transformation makes non-correlated subqueries correlated. */ - join_arg->select_lex->uncacheable|= UNCACHEABLE_DEPENDENT; + join_arg->select_lex->uncacheable|= UNCACHEABLE_DEPENDENT_INJECTED; if (left_expr->cols() == 1) res= create_single_in_to_exists_cond(join_arg, &(join_arg->in_to_exists_where), @@ -2037,6 +2075,16 @@ bool Item_in_subselect::create_in_to_exists_cond(JOIN *join_arg) res= create_row_in_to_exists_cond(join_arg, &(join_arg->in_to_exists_where), &(join_arg->in_to_exists_having)); + + /* + The uncacheable property controls a number of actions, e.g. whether to + save/restore (via init_save_join_tab/restore_tmp) the original JOIN for + plans with a temp table where the original JOIN was overriden by + make_simple_join. The UNCACHEABLE_EXPLAIN is ignored by EXPLAIN, thus + non-correlated subqueries will not appear as such to EXPLAIN. + */ + join_arg->select_lex->master_unit()->uncacheable|= UNCACHEABLE_EXPLAIN; + join_arg->select_lex->uncacheable|= UNCACHEABLE_EXPLAIN; return (res); } @@ -2107,6 +2155,9 @@ bool Item_in_subselect::inject_in_to_exists_cond(JOIN *join_arg) select_lex->having->top_level_item(); join_arg->having= select_lex->having; } + join_arg->thd->change_item_tree(&unit->global_parameters->select_limit, + new Item_int((int32) 1)); + unit->select_limit_cnt= 1; DBUG_RETURN(false); } @@ -2407,7 +2458,8 @@ bool Item_allany_subselect::select_transformer(JOIN *join) { DBUG_ENTER("Item_allany_subselect::select_transformer"); - in_strategy= SUBS_IN_TO_EXISTS; + DBUG_ASSERT((in_strategy & ~(SUBS_MAXMIN | SUBS_IN_TO_EXISTS)) == 0); + in_strategy|= SUBS_IN_TO_EXISTS; if (upper_item) upper_item->show= 1; DBUG_RETURN(select_in_like_transformer(join)); @@ -2458,6 +2510,7 @@ void subselect_single_select_engine::cleanup() prepared= executed= 0; join= 0; result->cleanup(); + select_lex->uncacheable&= ~UNCACHEABLE_DEPENDENT_INJECTED; DBUG_VOID_RETURN; } @@ -2467,6 +2520,9 @@ void subselect_union_engine::cleanup() DBUG_ENTER("subselect_union_engine::cleanup"); unit->reinit_exec_mechanism(); result->cleanup(); + unit->uncacheable&= ~UNCACHEABLE_DEPENDENT_INJECTED; + for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select()) + sl->uncacheable&= ~UNCACHEABLE_DEPENDENT_INJECTED; DBUG_VOID_RETURN; } @@ -3466,11 +3522,16 @@ void subselect_indexsubquery_engine::print(String *str, TRUE error */ -bool subselect_single_select_engine::change_result(Item_subselect *si, - select_result_interceptor *res) +bool +subselect_single_select_engine::change_result(Item_subselect *si, + select_result_interceptor *res, + bool temp) { item= si; - result= res; + if (temp) + thd->change_item_tree((Item**) &result, (Item*)res); + else + result= res; return select_lex->join->change_result(result); } @@ -3488,11 +3549,15 @@ bool subselect_single_select_engine::change_result(Item_subselect *si, */ bool subselect_union_engine::change_result(Item_subselect *si, - select_result_interceptor *res) + select_result_interceptor *res, + bool temp) { item= si; int rc= unit->change_result(res, result); - result= res; + if (temp) + thd->change_item_tree((Item**) &result, (Item*)res); + else + result= res; return rc; } @@ -3509,8 +3574,11 @@ bool subselect_union_engine::change_result(Item_subselect *si, TRUE error */ -bool subselect_uniquesubquery_engine::change_result(Item_subselect *si, - select_result_interceptor *res) +bool +subselect_uniquesubquery_engine::change_result(Item_subselect *si, + select_result_interceptor *res, + bool temp + __attribute__((unused))) { DBUG_ASSERT(0); return TRUE; @@ -4301,7 +4369,8 @@ bool subselect_hash_sj_engine::no_tables() } bool subselect_hash_sj_engine::change_result(Item_subselect *si, - select_result_interceptor *res) + select_result_interceptor *res, + bool temp __attribute__((unused))) { DBUG_ASSERT(FALSE); return TRUE; diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 740daeecf13..0c02713938e 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -32,7 +32,8 @@ class Cached_item; class Item_subselect :public Item_result_field { - bool value_assigned; /* value already assigned to subselect */ + bool value_assigned; /* value already assigned to subselect */ + bool borrowed_engine; /* the engine was taken from other Item_subselect */ protected: /* thread handler, will be assigned in fix_fields only */ THD *thd; @@ -356,6 +357,9 @@ public: /* Partial matching substrategies of MATERIALIZATION. */ #define SUBS_PARTIAL_MATCH_ROWID_MERGE 8 #define SUBS_PARTIAL_MATCH_TABLE_SCAN 16 +/* ALL/ANY will be transformed with max/min optimization */ +#define SUBS_MAXMIN 32 + /** Representation of IN subquery predicates of the form @@ -486,6 +490,7 @@ public: bool test_limit(st_select_lex_unit *unit); virtual void print(String *str, enum_query_type query_type); bool fix_fields(THD *thd, Item **ref); + void fix_length_and_dec(); void fix_after_pullout(st_select_lex *new_parent, Item **ref); void update_used_tables(); bool setup_mat_engine(); @@ -523,6 +528,8 @@ public: bool select_transformer(JOIN *join); void create_comp_func(bool invert) { func= func_creator(invert); } virtual void print(String *str, enum_query_type query_type); + bool is_maxmin_applicable(JOIN *join); + bool transform_allany(JOIN *join); }; @@ -594,7 +601,8 @@ public: static table_map calc_const_tables(TABLE_LIST *); virtual void print(String *str, enum_query_type query_type)= 0; virtual bool change_result(Item_subselect *si, - select_result_interceptor *result)= 0; + select_result_interceptor *result, + bool temp= FALSE)= 0; virtual bool no_tables()= 0; virtual bool is_executed() const { return FALSE; } /* Check if subquery produced any rows during last query execution */ @@ -626,7 +634,9 @@ public: void exclude(); table_map upper_select_const_tables(); virtual void print (String *str, enum_query_type query_type); - bool change_result(Item_subselect *si, select_result_interceptor *result); + bool change_result(Item_subselect *si, + select_result_interceptor *result, + bool temp); bool no_tables(); bool may_be_null(); bool is_executed() const { return executed; } @@ -655,7 +665,9 @@ public: void exclude(); table_map upper_select_const_tables(); virtual void print (String *str, enum_query_type query_type); - bool change_result(Item_subselect *si, select_result_interceptor *result); + bool change_result(Item_subselect *si, + select_result_interceptor *result, + bool temp= FALSE); bool no_tables(); bool is_executed() const; bool no_rows(); @@ -707,11 +719,13 @@ public: void fix_length_and_dec(Item_cache** row); int exec(); uint cols() { return 1; } - uint8 uncacheable() { return UNCACHEABLE_DEPENDENT; } + uint8 uncacheable() { return UNCACHEABLE_DEPENDENT_INJECTED; } void exclude(); table_map upper_select_const_tables() { return 0; } virtual void print (String *str, enum_query_type query_type); - bool change_result(Item_subselect *si, select_result_interceptor *result); + bool change_result(Item_subselect *si, + select_result_interceptor *result, + bool temp= FALSE); bool no_tables(); int index_lookup(); /* TIMOUR: this method needs refactoring. */ int scan_table(); @@ -879,7 +893,9 @@ public: void fix_length_and_dec(Item_cache** row);//=>base class void exclude(); //=>base class //=>base class - bool change_result(Item_subselect *si, select_result_interceptor *result); + bool change_result(Item_subselect *si, + select_result_interceptor *result, + bool temp= FALSE); bool no_tables();//=>base class }; @@ -1106,7 +1122,9 @@ public: uint8 uncacheable() { return UNCACHEABLE_DEPENDENT; } void exclude() {} table_map upper_select_const_tables() { return 0; } - bool change_result(Item_subselect*, select_result_interceptor*) + bool change_result(Item_subselect*, + select_result_interceptor*, + bool temp= FALSE) { DBUG_ASSERT(FALSE); return false; } bool no_tables() { return false; } bool no_rows() diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index a0184a82f48..f8dec1cf957 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -679,14 +679,18 @@ enabled by default, add OPTIMIZER_SWITCH_MATERIALIZATION #define CONTEXT_ANALYSIS_ONLY_DERIVED 4 // uncachable cause -#define UNCACHEABLE_DEPENDENT 1 -#define UNCACHEABLE_RAND 2 -#define UNCACHEABLE_SIDEEFFECT 4 +#define UNCACHEABLE_DEPENDENT_GENERATED 1 +#define UNCACHEABLE_RAND 2 +#define UNCACHEABLE_SIDEEFFECT 4 /// forcing to save JOIN for explain -#define UNCACHEABLE_EXPLAIN 8 +#define UNCACHEABLE_EXPLAIN 8 /* For uncorrelated SELECT in an UNION with some correlated SELECTs */ -#define UNCACHEABLE_UNITED 16 -#define UNCACHEABLE_CHECKOPTION 32 +#define UNCACHEABLE_UNITED 16 +#define UNCACHEABLE_CHECKOPTION 32 +#define UNCACHEABLE_DEPENDENT_INJECTED 64 + +#define UNCACHEABLE_DEPENDENT (UNCACHEABLE_DEPENDENT_GENERATED | \ + UNCACHEABLE_DEPENDENT_INJECTED) /* Used to check GROUP BY list in the MODE_ONLY_FULL_GROUP_BY mode */ #define UNDEF_POS (-1) diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 9469f35e21c..d3fdda04520 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -93,8 +93,19 @@ int check_and_do_in_subquery_rewrites(JOIN *join) (subselect= parent_unit->item)) // (2) { Item_in_subselect *in_subs= NULL; - if (subselect->substype() == Item_subselect::IN_SUBS) - in_subs= (Item_in_subselect*)subselect; + Item_allany_subselect *allany_subs= NULL; + switch (subselect->substype()) { + case Item_subselect::IN_SUBS: + in_subs= (Item_in_subselect *)subselect; + break; + case Item_subselect::ALL_SUBS: + case Item_subselect::ANY_SUBS: + allany_subs= (Item_allany_subselect *)subselect; + break; + default: + break; + } + /* Resolve expressions and perform semantic analysis for IN query */ if (in_subs != NULL) @@ -257,12 +268,18 @@ int check_and_do_in_subquery_rewrites(JOIN *join) } } + /* Check if max/min optimization applicable */ + if (allany_subs) + allany_subs->in_strategy|= (allany_subs->is_maxmin_applicable(join) ? + SUBS_MAXMIN : + SUBS_IN_TO_EXISTS); + /* Transform each subquery predicate according to its overloaded transformer. */ if (subselect->select_transformer(join)) - DBUG_RETURN(-11); + DBUG_RETURN(-1); } } DBUG_RETURN(0); @@ -369,6 +386,21 @@ bool subquery_types_allow_materialization(Item_in_subselect *in_subs) } +/** + Apply max min optimization of all/any subselect +*/ + +bool convert_max_min_subquery(JOIN *join) +{ + DBUG_ENTER("convert_max_min_subquery"); + Item_subselect *subselect= join->unit->item; + if (!subselect || (subselect->substype() != Item_subselect::ALL_SUBS && + subselect->substype() != Item_subselect::ANY_SUBS)) + DBUG_RETURN(0); + DBUG_RETURN(((Item_allany_subselect *) subselect)->transform_allany(join)); +} + + /* Convert semi-join subquery predicates into semi-join join nests @@ -3843,8 +3875,8 @@ bool JOIN::choose_subquery_plan(table_map join_tables) restore_query_plan(&save_qep); /* TODO: should we set/unset this flag for both select_lex and its unit? */ - in_subs->unit->uncacheable&= ~UNCACHEABLE_DEPENDENT; - select_lex->uncacheable&= ~UNCACHEABLE_DEPENDENT; + in_subs->unit->uncacheable&= ~UNCACHEABLE_DEPENDENT_INJECTED; + select_lex->uncacheable&= ~UNCACHEABLE_DEPENDENT_INJECTED; /* Reset the "LIMIT 1" set in Item_exists_subselect::fix_length_and_dec. @@ -3884,6 +3916,9 @@ bool JOIN::choose_subquery_plan(table_map join_tables) if (in_subs->inject_in_to_exists_cond(this)) return TRUE; + in_subs->unit->uncacheable|= UNCACHEABLE_DEPENDENT_INJECTED; + select_lex->uncacheable|= UNCACHEABLE_DEPENDENT_INJECTED; + select_limit= 1; } else DBUG_ASSERT(FALSE); diff --git a/sql/opt_subselect.h b/sql/opt_subselect.h index 47d85d5c38d..25707322649 100644 --- a/sql/opt_subselect.h +++ b/sql/opt_subselect.h @@ -6,6 +6,7 @@ int check_and_do_in_subquery_rewrites(JOIN *join); bool convert_join_subqueries_to_semijoins(JOIN *join); +bool convert_max_min_subquery(JOIN *join); int pull_out_semijoin_tables(JOIN *join); bool optimize_semijoin_nests(JOIN *join, table_map all_table_map); diff --git a/sql/sql_class.h b/sql/sql_class.h index c6f277f7bc7..91b4ddfc184 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2727,7 +2727,12 @@ public: class select_result_interceptor: public select_result { public: - select_result_interceptor() {} /* Remove gcc warning */ + select_result_interceptor() + { + DBUG_ENTER("select_result_interceptor::select_result_interceptor"); + DBUG_PRINT("enter", ("this 0x%lx", (ulong) this)); + DBUG_VOID_RETURN; + } /* Remove gcc warning */ uint field_count(List &fields) const { return 0; } bool send_fields(List &fields, uint flag) { return FALSE; } }; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 29455c1b405..f2e862b6c36 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1942,18 +1942,19 @@ bool st_select_lex::mark_as_dependent(THD *thd, st_select_lex *last, Item *depen SELECT_LEX *s= this; do { - if (!(s->uncacheable & UNCACHEABLE_DEPENDENT)) + if (!(s->uncacheable & UNCACHEABLE_DEPENDENT_GENERATED)) { // Select is dependent of outer select s->uncacheable= (s->uncacheable & ~UNCACHEABLE_UNITED) | - UNCACHEABLE_DEPENDENT; + UNCACHEABLE_DEPENDENT_GENERATED; SELECT_LEX_UNIT *munit= s->master_unit(); munit->uncacheable= (munit->uncacheable & ~UNCACHEABLE_UNITED) | - UNCACHEABLE_DEPENDENT; + UNCACHEABLE_DEPENDENT_GENERATED; for (SELECT_LEX *sl= munit->first_select(); sl ; sl= sl->next_select()) { if (sl != s && - !(sl->uncacheable & (UNCACHEABLE_DEPENDENT | UNCACHEABLE_UNITED))) + !(sl->uncacheable & (UNCACHEABLE_DEPENDENT_GENERATED | + UNCACHEABLE_UNITED))) sl->uncacheable|= UNCACHEABLE_UNITED; } } @@ -2178,17 +2179,6 @@ void st_select_lex::print_limit(THD *thd, subs_type == Item_subselect::IN_SUBS || subs_type == Item_subselect::ALL_SUBS) { - DBUG_ASSERT(!item->fixed || - /* - If not using materialization both: - select_limit == 1, and there should be no offset_limit. - */ - (((subs_type == Item_subselect::IN_SUBS) && - ((Item_in_subselect*)item)->in_strategy & - SUBS_MATERIALIZATION) ? - TRUE : - (select_limit->val_int() == 1LL) && - offset_limit == 0)); return; } } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index f0e99fdc289..6fc1167235c 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -417,7 +417,8 @@ public: /* result of this query can't be cached, bit field, can be : - UNCACHEABLE_DEPENDENT + UNCACHEABLE_DEPENDENT_GENERATED + UNCACHEABLE_DEPENDENT_INJECTED UNCACHEABLE_RAND UNCACHEABLE_SIDEEFFECT UNCACHEABLE_EXPLAIN diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 4055b97cbed..5b88436b4cf 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -736,11 +736,28 @@ JOIN::prepare(Item ***rref_pointer_array, if (!procedure && result && result->prepare(fields_list, unit_arg)) goto err; /* purecov: inspected */ + unit= unit_arg; + if (prepare_stage2()) + goto err; + + DBUG_RETURN(0); // All OK + +err: + delete procedure; /* purecov: inspected */ + procedure= 0; + DBUG_RETURN(-1); /* purecov: inspected */ +} + + +bool JOIN::prepare_stage2() +{ + bool res= TRUE; + DBUG_ENTER("JOIN::prepare_stage2"); + /* Init join struct */ count_field_types(select_lex, &tmp_table_param, all_fields, 0); ref_pointer_array_size= all_fields.elements*sizeof(Item*); this->group= group_list != 0; - unit= unit_arg; if (tmp_table_param.sum_func_count && !group_list) implicit_grouping= TRUE; @@ -757,12 +774,9 @@ JOIN::prepare(Item ***rref_pointer_array, if (alloc_func_list()) goto err; - DBUG_RETURN(0); // All OK - + res= FALSE; err: - delete procedure; /* purecov: inspected */ - procedure= 0; - DBUG_RETURN(-1); /* purecov: inspected */ + DBUG_RETURN(res); /* purecov: inspected */ } @@ -795,7 +809,8 @@ JOIN::optimize() set_allowed_join_cache_types(); /* dump_TABLE_LIST_graph(select_lex, select_lex->leaf_tables); */ - if (convert_join_subqueries_to_semijoins(this)) + if (convert_max_min_subquery(this) || + convert_join_subqueries_to_semijoins(this)) DBUG_RETURN(1); /* purecov: inspected */ /* dump_TABLE_LIST_graph(select_lex, select_lex->leaf_tables); */ @@ -8599,6 +8614,10 @@ bool error_if_full_join(JOIN *join) void JOIN_TAB::cleanup() { + DBUG_ENTER("JOIN_TAB::cleanup"); + DBUG_PRINT("enter", ("table %s.%s", + (table ? table->s->db.str : "?"), + (table ? table->s->table_name.str : "?"))); delete select; select= 0; delete quick; @@ -8620,6 +8639,7 @@ void JOIN_TAB::cleanup() table->reginfo.join_tab= 0; } end_read_record(&read_record); + DBUG_VOID_RETURN; } @@ -8740,7 +8760,8 @@ void JOIN::join_free() Optimization: if not EXPLAIN and we are done with the JOIN, free all tables. */ - bool full= (!select_lex->uncacheable && !thd->lex->describe); + bool full= (!(select_lex->uncacheable) && + !thd->lex->describe); bool can_unlock= full; DBUG_ENTER("JOIN::join_free"); @@ -8804,6 +8825,7 @@ void JOIN::join_free() void JOIN::cleanup(bool full) { DBUG_ENTER("JOIN::cleanup"); + DBUG_PRINT("enter", ("full %u", (uint) full)); if (table) { @@ -8829,7 +8851,11 @@ void JOIN::cleanup(bool full) for (tab= join_tab, end= tab+tables; tab != end; tab++) { if (tab->table) + { + DBUG_PRINT("info", ("close index: %s.%s", tab->table->s->db.str, + tab->table->s->table_name.str)); tab->table->file->ha_index_or_rnd_end(); + } } } } @@ -20304,6 +20330,7 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) change select_result object of JOIN. @param res new select_result object + @param temp temporary assignment @retval FALSE OK diff --git a/sql/sql_select.h b/sql/sql_select.h index 5de7620c7d8..1df07e002b5 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -999,6 +999,7 @@ public: COND *conds, uint og_num, ORDER *order, ORDER *group, Item *having, ORDER *proc_param, SELECT_LEX *select, SELECT_LEX_UNIT *unit); + bool prepare_stage2(); int optimize(); int reinit(); int init_execution(); From 18d08eeacc8010e04b81b6d890456fd90c47bf75 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 12 May 2011 00:14:15 +0300 Subject: [PATCH 2/2] Post review fixes of MWL#148 (moving max/min optimization in optimize phase). sql/item_subselect.cc: Cleanup. Comments added. sql/item_subselect.h: Cleanup. sql/mysql_priv.h: Comments added. sql/opt_subselect.cc: The function renamed and turned to method. Comments added. sql/opt_subselect.h: The function turned to method of JOIN. sql/sql_select.cc: Comment added. The function turned to method. sql/sql_select.h: The function turned to method. --- sql/item_subselect.cc | 121 ++++++++++++++++++++++++++---------------- sql/item_subselect.h | 6 ++- sql/mysql_priv.h | 15 +++++- sql/opt_subselect.cc | 14 +++-- sql/opt_subselect.h | 1 - sql/sql_select.cc | 11 +++- sql/sql_select.h | 2 + 7 files changed, 113 insertions(+), 57 deletions(-) diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index c8336bbabce..52d9407a7ac 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -33,7 +33,8 @@ Item_subselect::Item_subselect(): - Item_result_field(), value_assigned(0), thd(0), substitution(0), + Item_result_field(), value_assigned(0), own_engine(TRUE), + thd(0), substitution(0), expr_cache(0), engine(0), old_engine(0), used_tables_cache(0), have_to_be_excluded(0), const_item_cache(1), inside_first_fix_fields(0), done_first_fix_fields(FALSE), forced_const(FALSE), eliminated(FALSE), @@ -73,11 +74,9 @@ void Item_subselect::init(st_select_lex *select_lex, => we do not copy old_engine here */ engine= unit->item->engine; - borrowed_engine= TRUE; + own_engine= FALSE; parsing_place= unit->item->parsing_place; - //unit->item->engine= 0; thd->change_item_tree((Item**)&unit->item, this); - //unit->item= this; engine->change_result(this, result, TRUE); } else @@ -165,7 +164,7 @@ Item_subselect::~Item_subselect() { DBUG_ENTER("Item_subselect::~Item_subselect"); DBUG_PRINT("enter", ("this: 0x%lx", (ulong) this)); - if (!borrowed_engine) + if (own_engine) delete engine; else engine->cleanup(); @@ -1130,24 +1129,41 @@ Item_allany_subselect::Item_allany_subselect(Item * left_exp, } -void Item_exists_subselect::fix_length_and_dec() +/** + Initialize length and decimals for EXISTS and inherited (IN/ALL/ANY) + subqueries +*/ + +void Item_exists_subselect::init_length_and_dec() { - DBUG_ENTER("Item_exists_subselect::fix_length_and_dec"); decimals= 0; max_length= 1; max_columns= engine->cols(); - /* We need only 1 row to determine existence */ +} + + +void Item_exists_subselect::fix_length_and_dec() +{ + DBUG_ENTER("Item_exists_subselect::fix_length_and_dec"); + init_length_and_dec(); + /* + We need only 1 row to determine existence (i.e. any EXISTS that is not + an IN always requires LIMIT 1) + */ unit->global_parameters->select_limit= new Item_int((int32) 1); DBUG_PRINT("info", ("Set limit to 1")); DBUG_VOID_RETURN; } + void Item_in_subselect::fix_length_and_dec() { DBUG_ENTER("Item_in_subselect::fix_length_and_dec"); - decimals= 0; - max_length= 1; - max_columns= engine->cols(); + init_length_and_dec(); + /* + Unlike Item_exists_subselect, LIMIT 1 is set later for + Item_in_subselect, depending on the chosen strategy. + */ DBUG_VOID_RETURN; } @@ -1368,29 +1384,19 @@ my_decimal *Item_in_subselect::val_decimal(my_decimal *decimal_value) /** - Rewrite a single-column IN/ALL/ANY subselect. + Prepare a single-column IN/ALL/ANY subselect for rewriting. @param join Join object of the subquery (i.e. 'child' join). @details - Rewrite a single-column subquery using rule-based approach. Given the subquery - oe $cmp$ (SELECT ie FROM ... WHERE subq_where ... HAVING subq_having) + Prepare a single-column subquery to be rewritten. Given the subquery. - First, try to convert the subquery to a scalar-result subquery in one of - the forms: - - - oe $cmp$ (SELECT MAX(...) ) // handled by Item_singlerow_subselect - - oe $cmp$ (SELECT ...) // handled by Item_maxmin_subselect + If the subquery has no tables it will be turned to an expression between + left part and SELECT list. - If that fails, check if the subquery is a single select without tables, - and substitute the subquery predicate with "oe $cmp$ ie". - - If that fails, the subquery predicate is wrapped into an Item_in_optimizer. - Later the query optimization phase chooses whether the subquery under the - Item_in_optimizer will be further transformed into an equivalent correlated - EXISTS by injecting additional predicates, or will be executed via subquery - materialization in its unmodified form. + In other cases the subquery will be wrapped with Item_in_optimizer which + allow later to turn it to EXISTS or MAX/MIN. @retval false The subquery was transformed @retval true Error @@ -1476,26 +1482,40 @@ Item_in_subselect::single_value_transformer(JOIN *join) DBUG_RETURN(false); } -bool Item_allany_subselect::transform_allany(JOIN *join) + +/** + Apply transformation max/min transwormation to ALL/ANY subquery if it is + possible. + + @param join Join object of the subquery (i.e. 'child' join). + + @details + + If this is an ALL/ANY single-value subselect, try to rewrite it with + a MIN/MAX subselect. We can do that if a possible NULL result of the + subselect can be ignored. + E.g. SELECT * FROM t1 WHERE b > ANY (SELECT a FROM t2) can be rewritten + with SELECT * FROM t1 WHERE b > (SELECT MAX(a) FROM t2). + We can't check that this optimization is safe if it's not a top-level + item of the WHERE clause (e.g. because the WHERE clause can contain IS + NULL/IS NOT NULL functions). If so, we rewrite ALL/ANY with NOT EXISTS + later in this method. + + @retval false The subquery was transformed + @retval true Error +*/ + +bool Item_allany_subselect::transform_into_max_min(JOIN *join) { - DBUG_ENTER("Item_allany_subselect::transform_allany"); + DBUG_ENTER("Item_allany_subselect::transform_into_max_min"); if (!(in_strategy & SUBS_MAXMIN)) - DBUG_RETURN(0); + DBUG_RETURN(false); Item **place= optimizer->arguments() + 1; THD *thd= join->thd; SELECT_LEX *select_lex= join->select_lex; Item *subs; /* - If this is an ALL/ANY single-value subselect, try to rewrite it with - a MIN/MAX subselect. We can do that if a possible NULL result of the - subselect can be ignored. - E.g. SELECT * FROM t1 WHERE b > ANY (SELECT a FROM t2) can be rewritten - with SELECT * FROM t1 WHERE b > (SELECT MAX(a) FROM t2). - We can't check that this optimization is safe if it's not a top-level - item of the WHERE clause (e.g. because the WHERE clause can contain IS - NULL/IS NOT NULL functions). If so, we rewrite ALL/ANY with NOT EXISTS - later in this method. */ DBUG_ASSERT(!substitution); @@ -1560,12 +1580,15 @@ bool Item_allany_subselect::transform_allany(JOIN *join) subs= func->create(left_expr, subs); thd->change_item_tree(place, subs); if (subs->fix_fields(thd, &subs)) - DBUG_RETURN(1); + DBUG_RETURN(true); DBUG_ASSERT(subs == (*place)); // There was no substitutions select_lex->master_unit()->uncacheable&= ~UNCACHEABLE_DEPENDENT_INJECTED; select_lex->uncacheable&= ~UNCACHEABLE_DEPENDENT_INJECTED; - /* remove other strategies if there was (just to be safe) */ + /* + Remove other strategies if there was (we already changed the query and + can't apply other strategy). + */ in_strategy= SUBS_MAXMIN; DBUG_RETURN(false); @@ -2063,10 +2086,6 @@ bool Item_in_subselect::create_in_to_exists_cond(JOIN *join_arg) If the dependency is removed, the call can be moved to a later phase. */ init_cond_guards(); - /* - The IN=>EXISTS transformation makes non-correlated subqueries correlated. - */ - join_arg->select_lex->uncacheable|= UNCACHEABLE_DEPENDENT_INJECTED; if (left_expr->cols() == 1) res= create_single_in_to_exists_cond(join_arg, &(join_arg->in_to_exists_where), @@ -2076,6 +2095,10 @@ bool Item_in_subselect::create_in_to_exists_cond(JOIN *join_arg) &(join_arg->in_to_exists_where), &(join_arg->in_to_exists_having)); + /* + The IN=>EXISTS transformation makes non-correlated subqueries correlated. + */ + join_arg->select_lex->uncacheable|= UNCACHEABLE_DEPENDENT_INJECTED; /* The uncacheable property controls a number of actions, e.g. whether to save/restore (via init_save_join_tab/restore_tmp) the original JOIN for @@ -3515,6 +3538,7 @@ void subselect_indexsubquery_engine::print(String *str, @param si new subselect Item @param res new select_result object + @param temp temporary assignment @retval FALSE OK @@ -3529,7 +3553,14 @@ subselect_single_select_engine::change_result(Item_subselect *si, { item= si; if (temp) + { + /* + Here we reuse change_item_tree to roll back assignment. It has + nothing special about Item* pointer so it is safe conversion. We do + not change the interface to be compatible with MySQL. + */ thd->change_item_tree((Item**) &result, (Item*)res); + } else result= res; return select_lex->join->change_result(result); diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 0c02713938e..2c357b0da20 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -33,7 +33,7 @@ class Cached_item; class Item_subselect :public Item_result_field { bool value_assigned; /* value already assigned to subselect */ - bool borrowed_engine; /* the engine was taken from other Item_subselect */ + bool own_engine; /* the engine was not taken from other Item_subselect */ protected: /* thread handler, will be assigned in fix_fields only */ THD *thd; @@ -318,6 +318,8 @@ class Item_exists_subselect :public Item_subselect protected: bool value; /* value of this item (boolean: exists/not-exists) */ + void init_length_and_dec(); + public: Item_exists_subselect(st_select_lex *select_lex); Item_exists_subselect(): Item_subselect() {} @@ -529,7 +531,7 @@ public: void create_comp_func(bool invert) { func= func_creator(invert); } virtual void print(String *str, enum_query_type query_type); bool is_maxmin_applicable(JOIN *join); - bool transform_allany(JOIN *join); + bool transform_into_max_min(JOIN *join); }; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 66a45810afb..9ffcbda42e3 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -678,17 +678,28 @@ enabled by default, add OPTIMIZER_SWITCH_MATERIALIZATION */ #define CONTEXT_ANALYSIS_ONLY_DERIVED 4 -// uncachable cause +/* + Uncachable causes: + +This subquery has fields from outer query (put by user) +*/ #define UNCACHEABLE_DEPENDENT_GENERATED 1 +/* This subquery contains functions with random result */ #define UNCACHEABLE_RAND 2 +/* This subquery contains functions with side effect */ #define UNCACHEABLE_SIDEEFFECT 4 -/// forcing to save JOIN for explain +/* Forcing to save JOIN tables for explain */ #define UNCACHEABLE_EXPLAIN 8 /* For uncorrelated SELECT in an UNION with some correlated SELECTs */ #define UNCACHEABLE_UNITED 16 #define UNCACHEABLE_CHECKOPTION 32 +/* + This subquery has fields from outer query injected during + transformation process +*/ #define UNCACHEABLE_DEPENDENT_INJECTED 64 +/* This subquery has fields from outer query (any nature) */ #define UNCACHEABLE_DEPENDENT (UNCACHEABLE_DEPENDENT_GENERATED | \ UNCACHEABLE_DEPENDENT_INJECTED) diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index d3fdda04520..505f336006b 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -390,14 +390,15 @@ bool subquery_types_allow_materialization(Item_in_subselect *in_subs) Apply max min optimization of all/any subselect */ -bool convert_max_min_subquery(JOIN *join) +bool JOIN::transform_max_min_subquery() { - DBUG_ENTER("convert_max_min_subquery"); - Item_subselect *subselect= join->unit->item; + DBUG_ENTER("JOIN::transform_max_min_subquery"); + Item_subselect *subselect= unit->item; if (!subselect || (subselect->substype() != Item_subselect::ALL_SUBS && subselect->substype() != Item_subselect::ANY_SUBS)) DBUG_RETURN(0); - DBUG_RETURN(((Item_allany_subselect *) subselect)->transform_allany(join)); + DBUG_RETURN(((Item_allany_subselect *) subselect)-> + transform_into_max_min(this)); } @@ -3874,7 +3875,6 @@ bool JOIN::choose_subquery_plan(table_map join_tables) if (reopt_result == REOPT_NEW_PLAN) restore_query_plan(&save_qep); - /* TODO: should we set/unset this flag for both select_lex and its unit? */ in_subs->unit->uncacheable&= ~UNCACHEABLE_DEPENDENT_INJECTED; select_lex->uncacheable&= ~UNCACHEABLE_DEPENDENT_INJECTED; @@ -3916,6 +3916,10 @@ bool JOIN::choose_subquery_plan(table_map join_tables) if (in_subs->inject_in_to_exists_cond(this)) return TRUE; + /* + It is IN->EXISTS transformation so we should mark subquery as + dependent + */ in_subs->unit->uncacheable|= UNCACHEABLE_DEPENDENT_INJECTED; select_lex->uncacheable|= UNCACHEABLE_DEPENDENT_INJECTED; select_limit= 1; diff --git a/sql/opt_subselect.h b/sql/opt_subselect.h index 25707322649..47d85d5c38d 100644 --- a/sql/opt_subselect.h +++ b/sql/opt_subselect.h @@ -6,7 +6,6 @@ int check_and_do_in_subquery_rewrites(JOIN *join); bool convert_join_subqueries_to_semijoins(JOIN *join); -bool convert_max_min_subquery(JOIN *join); int pull_out_semijoin_tables(JOIN *join); bool optimize_semijoin_nests(JOIN *join, table_map all_table_map); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 68a33b2f431..1c67f5d8fc7 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -749,6 +749,14 @@ err: } +/** + Second phase of prepare where we collect some statistic. + + @details + We made this part separate to be able recalculate some statistic after + transforming subquery on optimization phase. +*/ + bool JOIN::prepare_stage2() { bool res= TRUE; @@ -809,7 +817,7 @@ JOIN::optimize() set_allowed_join_cache_types(); /* dump_TABLE_LIST_graph(select_lex, select_lex->leaf_tables); */ - if (convert_max_min_subquery(this) || + if (transform_max_min_subquery() || convert_join_subqueries_to_semijoins(this)) DBUG_RETURN(1); /* purecov: inspected */ /* dump_TABLE_LIST_graph(select_lex, select_lex->leaf_tables); */ @@ -20333,7 +20341,6 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) change select_result object of JOIN. @param res new select_result object - @param temp temporary assignment @retval FALSE OK diff --git a/sql/sql_select.h b/sql/sql_select.h index 1df07e002b5..9615463ade5 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1080,6 +1080,8 @@ public: bool choose_subquery_plan(table_map join_tables); void get_partial_join_cost(uint n_tables, double *read_time_arg, double *record_count_arg); + /* defined in opt_subselect.cc */ + bool transform_max_min_subquery(); private: /**