diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index fc0a933b732..e00946a1b9e 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -3562,9 +3562,7 @@ SELECT sql_no_cache * FROM t1 WHERE NOT EXISTS (SELECT i FROM t1) UNION (SELECT i FROM t1) ); -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UNION -(SELECT i FROM t1) -)' at line 3 +i SELECT * FROM t1 WHERE NOT EXISTS (((SELECT i FROM t1) UNION (SELECT i FROM t1))); ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UNION (SELECT i FROM t1)))' at line 2 @@ -3574,7 +3572,11 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp from t1' at line 1 explain select * from t1 where not exists ((select t11.i from t1 t11) union (select t12.i from t1 t12)); -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'union (select t12.i from t1 t12))' at line 2 +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 system NULL NULL NULL NULL 0 const row not found +2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL no matching row in const table +3 UNION NULL NULL NULL NULL NULL NULL NULL no matching row in const table +NULL UNION RESULT ALL NULL NULL NULL NULL NULL DROP TABLE t1; CREATE TABLE t1 (a VARCHAR(250), b INT auto_increment, PRIMARY KEY (b)); insert into t1 (a) values (FLOOR(rand() * 100)); @@ -4279,8 +4281,15 @@ Note 1003 select 2 AS `2` from `test`.`t1` where exists(select 1 AS `1` from `te EXPLAIN EXTENDED SELECT 2 FROM t1 WHERE EXISTS ((SELECT 1 FROM t2 WHERE t1.a=t2.a) UNION (SELECT 1 FROM t2 WHERE t1.a = t2.a)); -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UNION -(SELECT 1 FROM t2 WHERE t1.a = t2.a))' at line 2 +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 100.00 Using where +2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 2 100.00 Using where +3 DEPENDENT UNION t2 ALL NULL NULL NULL NULL 2 100.00 Using where +NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL +Warnings: +Note 1276 Field or reference 'test.t1.a' of SELECT #2 was resolved in SELECT #1 +Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #1 +Note 1003 select 2 AS `2` from `test`.`t1` where exists((select 1 AS `1` from `test`.`t2` where (`test`.`t1`.`a` = `test`.`t2`.`a`)) union (select 1 AS `1` from `test`.`t2` where (`test`.`t1`.`a` = `test`.`t2`.`a`))) DROP TABLE t1,t2; create table t1(f11 int, f12 int); create table t2(f21 int unsigned not null, f22 int, f23 varchar(10)); @@ -4564,4 +4573,268 @@ id g v s 51 50 NULL l 61 60 NULL l drop table t1, t2; +# +# Bug#33204: INTO is allowed in subselect, causing inconsistent results +# +CREATE TABLE t1( a INT ); +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2( a INT, b INT ); +SELECT * +FROM (SELECT a INTO @var FROM t1 WHERE a = 2) t1a; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO @var FROM t1 WHERE a = 2) t1a' at line 2 +SELECT * +FROM (SELECT a INTO OUTFILE 'file' FROM t1 WHERE a = 2) t1a; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO OUTFILE 'file' FROM t1 WHERE a = 2) t1a' at line 2 +SELECT * +FROM (SELECT a INTO DUMPFILE 'file' FROM t1 WHERE a = 2) t1a; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO DUMPFILE 'file' FROM t1 WHERE a = 2) t1a' at line 2 +SELECT * FROM ( +SELECT 1 a +UNION +SELECT a INTO @var FROM t1 WHERE a = 2 +) t1a; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO @var FROM t1 WHERE a = 2 +) t1a' at line 4 +SELECT * FROM ( +SELECT 1 a +UNION +SELECT a INTO OUTFILE 'file' FROM t1 WHERE a = 2 +) t1a; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO OUTFILE 'file' FROM t1 WHERE a = 2 +) t1a' at line 4 +SELECT * FROM ( +SELECT 1 a +UNION +SELECT a INTO DUMPFILE 'file' FROM t1 WHERE a = 2 +) t1a; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO DUMPFILE 'file' FROM t1 WHERE a = 2 +) t1a' at line 4 +SELECT * FROM (SELECT a FROM t1 WHERE a = 2) t1a; +a +2 +SELECT * FROM ( +SELECT a FROM t1 WHERE a = 2 +UNION +SELECT a FROM t1 WHERE a = 2 +) t1a; +a +2 +SELECT * FROM ( +SELECT 1 a +UNION +SELECT a FROM t1 WHERE a = 2 +UNION +SELECT a FROM t1 WHERE a = 2 +) t1a; +a +1 +2 +SELECT * FROM ((SELECT 1 a) UNION SELECT 1 a); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 1 +SELECT * FROM (SELECT 1 a UNION (SELECT 1 a)) alias; +a +1 +SELECT * FROM (SELECT 1 UNION SELECT 1) t1a; +1 +1 +SELECT * FROM ((SELECT 1 a INTO @a)) t1a; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO @a)) t1a' at line 1 +SELECT * FROM ((SELECT 1 a INTO OUTFILE 'file' )) t1a; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO OUTFILE 'file' )) t1a' at line 1 +SELECT * FROM ((SELECT 1 a INTO DUMPFILE 'file' )) t1a; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO DUMPFILE 'file' )) t1a' at line 1 +SELECT * FROM (SELECT 1 a UNION (SELECT 1 a INTO @a)) t1a; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO @a)) t1a' at line 1 +SELECT * FROM (SELECT 1 a UNION (SELECT 1 a INTO DUMPFILE 'file' )) t1a; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO DUMPFILE 'file' )) t1a' at line 1 +SELECT * FROM (SELECT 1 a UNION (SELECT 1 a INTO OUTFILE 'file' )) t1a; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO OUTFILE 'file' )) t1a' at line 1 +SELECT * FROM (SELECT 1 a UNION ((SELECT 1 a INTO @a))) t1a; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO @a))) t1a' at line 1 +SELECT * FROM (SELECT 1 a UNION ((SELECT 1 a INTO DUMPFILE 'file' ))) t1a; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO DUMPFILE 'file' ))) t1a' at line 1 +SELECT * FROM (SELECT 1 a UNION ((SELECT 1 a INTO OUTFILE 'file' ))) t1a; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO OUTFILE 'file' ))) t1a' at line 1 +SELECT * FROM (SELECT 1 a ORDER BY a) t1a; +a +1 +SELECT * FROM (SELECT 1 a UNION SELECT 1 a ORDER BY a) t1a; +a +1 +SELECT * FROM (SELECT 1 a UNION SELECT 1 a LIMIT 1) t1a; +a +1 +SELECT * FROM (SELECT 1 a UNION SELECT 1 a ORDER BY a LIMIT 1) t1a; +a +1 +SELECT * FROM t1 JOIN (SELECT 1 UNION SELECT 1) alias ON 1; +a 1 +1 1 +2 1 +SELECT * FROM t1 JOIN ((SELECT 1 UNION SELECT 1)) ON 1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')) ON 1' at line 1 +SELECT * FROM t1 JOIN (t1 t1a UNION SELECT 1) ON 1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'ON 1' at line 1 +SELECT * FROM t1 JOIN ((t1 t1a UNION SELECT 1)) ON 1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ') ON 1' at line 1 +SELECT * FROM t1 JOIN (t1 t1a) t1a ON 1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 't1a ON 1' at line 1 +SELECT * FROM t1 JOIN ((t1 t1a)) t1a ON 1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 't1a ON 1' at line 1 +SELECT * FROM t1 JOIN (t1 t1a) ON 1; +a a +1 1 +2 1 +1 2 +2 2 +SELECT * FROM t1 JOIN ((t1 t1a)) ON 1; +a a +1 1 +2 1 +1 2 +2 2 +SELECT * FROM (t1 t1a); +a +1 +2 +SELECT * FROM ((t1 t1a)); +a +1 +2 +SELECT * FROM t1 JOIN (SELECT 1 t1a) alias ON 1; +a t1a +1 1 +2 1 +SELECT * FROM t1 JOIN ((SELECT 1 t1a)) alias ON 1; +a t1a +1 1 +2 1 +SELECT * FROM t1 JOIN (SELECT 1 a) a ON 1; +a a +1 1 +2 1 +SELECT * FROM t1 JOIN ((SELECT 1 a)) a ON 1; +a a +1 1 +2 1 +SELECT * FROM (t1 JOIN (SELECT 1) t1a1 ON 1) t1a2; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 't1a2' at line 1 +SELECT * FROM t1 WHERE a = ALL ( SELECT 1 ); +a +1 +SELECT * FROM t1 WHERE a = ALL ( SELECT 1 UNION SELECT 1 ); +a +1 +SELECT * FROM t1 WHERE a = ANY ( SELECT 3 UNION SELECT 1 ); +a +1 +SELECT * FROM t1 WHERE a = ANY ( SELECT 1 UNION SELECT 1 INTO @a); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO @a)' at line 1 +SELECT * FROM t1 WHERE a = ANY ( SELECT 1 UNION SELECT 1 INTO OUTFILE 'file' ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO OUTFILE 'file' )' at line 1 +SELECT * FROM t1 WHERE a = ANY ( SELECT 1 UNION SELECT 1 INTO DUMPFILE 'file' ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO DUMPFILE 'file' )' at line 1 +SELECT * FROM t1 WHERE a = ( SELECT 1 ); +a +1 +SELECT * FROM t1 WHERE a = ( SELECT 1 UNION SELECT 1 ); +a +1 +SELECT * FROM t1 WHERE a = ( SELECT 1 INTO @a); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO @a)' at line 1 +SELECT * FROM t1 WHERE a = ( SELECT 1 INTO OUTFILE 'file' ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO OUTFILE 'file' )' at line 1 +SELECT * FROM t1 WHERE a = ( SELECT 1 INTO DUMPFILE 'file' ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO DUMPFILE 'file' )' at line 1 +SELECT * FROM t1 WHERE a = ( SELECT 1 UNION SELECT 1 INTO @a); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO @a)' at line 1 +SELECT * FROM t1 WHERE a = ( SELECT 1 UNION SELECT 1 INTO OUTFILE 'file' ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO OUTFILE 'file' )' at line 1 +SELECT * FROM t1 WHERE a = ( SELECT 1 UNION SELECT 1 INTO DUMPFILE 'file' ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO DUMPFILE 'file' )' at line 1 +SELECT ( SELECT 1 INTO @v ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO @v )' at line 1 +SELECT ( SELECT 1 INTO OUTFILE 'file' ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO OUTFILE 'file' )' at line 1 +SELECT ( SELECT 1 INTO DUMPFILE 'file' ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO DUMPFILE 'file' )' at line 1 +SELECT ( SELECT 1 UNION SELECT 1 INTO @v ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO @v )' at line 1 +SELECT ( SELECT 1 UNION SELECT 1 INTO OUTFILE 'file' ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO OUTFILE 'file' )' at line 1 +SELECT ( SELECT 1 UNION SELECT 1 INTO DUMPFILE 'file' ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO DUMPFILE 'file' )' at line 1 +SELECT ( SELECT a FROM t1 WHERE a = 1 ), a FROM t1; +( SELECT a FROM t1 WHERE a = 1 ) a +1 1 +1 2 +SELECT ( SELECT a FROM t1 WHERE a = 1 UNION SELECT 1 ), a FROM t1; +( SELECT a FROM t1 WHERE a = 1 UNION SELECT 1 ) a +1 1 +1 2 +SELECT * FROM t2 WHERE (a, b) IN (SELECT a, b FROM t2); +a b +SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UNION SELECT 1 )' at line 1 +( SELECT 1 UNION SELECT 1 ) UNION SELECT 1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UNION SELECT 1 ) UNION SELECT 1' at line 1 +SELECT ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UNION SELECT 1 ) )' at line 1 +SELECT ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UNION SELECT 1' at line 1 +SELECT ( SELECT 1 UNION SELECT 1 UNION SELECT 1 ); +( SELECT 1 UNION SELECT 1 UNION SELECT 1 ) +1 +SELECT ((SELECT 1 UNION SELECT 1 UNION SELECT 1)); +((SELECT 1 UNION SELECT 1 UNION SELECT 1)) +1 +SELECT * FROM ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UNION SELECT 1 ) )' at line 1 +SELECT * FROM ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ') UNION SELECT 1 )' at line 1 +SELECT * FROM ( SELECT 1 UNION SELECT 1 UNION SELECT 1 ) a; +1 +1 +SELECT * FROM t1 WHERE a = ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UNION SELECT 1 ) )' at line 1 +SELECT * FROM t1 WHERE a = ALL ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UNION SELECT 1 ) )' at line 1 +SELECT * FROM t1 WHERE a = ANY ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UNION SELECT 1 ) )' at line 1 +SELECT * FROM t1 WHERE a IN ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UNION SELECT 1 ) )' at line 1 +SELECT * FROM t1 WHERE a = ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UNION SELECT 1 )' at line 1 +SELECT * FROM t1 WHERE a = ALL ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UNION SELECT 1 ) UNION SELECT 1 )' at line 1 +SELECT * FROM t1 WHERE a = ANY ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UNION SELECT 1 ) UNION SELECT 1 )' at line 1 +SELECT * FROM t1 WHERE a IN ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UNION SELECT 1 )' at line 1 +SELECT * FROM t1 WHERE a = ( SELECT 1 UNION SELECT 1 UNION SELECT 1 ); +a +1 +SELECT * FROM t1 WHERE a = ALL ( SELECT 1 UNION SELECT 1 UNION SELECT 1 ); +a +1 +SELECT * FROM t1 WHERE a = ANY ( SELECT 1 UNION SELECT 1 UNION SELECT 1 ); +a +1 +SELECT * FROM t1 WHERE a IN ( SELECT 1 UNION SELECT 1 UNION SELECT 1 ); +a +1 +SELECT * FROM t1 WHERE EXISTS ( SELECT 1 UNION SELECT 1 INTO @v ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO @v )' at line 1 +SELECT EXISTS(SELECT 1+1); +EXISTS(SELECT 1+1) +1 +SELECT EXISTS(SELECT 1+1 INTO @test); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO @test)' at line 1 +SELECT * FROM t1 WHERE a IN ( SELECT 1 UNION SELECT 1 INTO @v ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO @v )' at line 1 +SELECT * FROM t1 WHERE EXISTS ( SELECT 1 INTO @v ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO @v )' at line 1 +SELECT * FROM t1 WHERE a IN ( SELECT 1 INTO @v ); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'INTO @v )' at line 1 +DROP TABLE t1, t2; End of 5.1 tests. diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index 44a3812725a..3b6541ce56a 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -153,48 +153,6 @@ ERROR 42S22: Unknown column 'a' in 'field list' 1 3 1 3 2 1 -CREATE TABLE t1 (a INT); -INSERT INTO t1 VALUES (1); -SELECT a INTO @v FROM ( -SELECT a FROM t1 -UNION -SELECT a FROM t1 -) alias; -SELECT a INTO OUTFILE '/tmp/union.out.file' FROM ( -SELECT a FROM t1 -UNION -SELECT a FROM t1 WHERE 0 -) alias; -SELECT a INTO DUMPFILE '/tmp/union.out.file' FROM ( -SELECT a FROM t1 -UNION -SELECT a FROM t1 WHERE 0 -) alias; -SELECT a FROM ( -SELECT a FROM t1 -UNION -SELECT a INTO @v FROM t1 -) alias; -SELECT a FROM ( -SELECT a FROM t1 -UNION -SELECT a INTO OUTFILE '/tmp/union.out.file' FROM t1 -) alias; -SELECT a FROM ( -SELECT a FROM t1 -UNION -SELECT a INTO DUMPFILE '/tmp/union.out.file' FROM t1 -) alias; -SELECT a FROM t1 UNION SELECT a INTO @v FROM t1; -SELECT a FROM t1 UNION SELECT a INTO OUTFILE '/tmp/union.out.file' FROM t1; -SELECT a FROM t1 UNION SELECT a INTO DUMPFILE '/tmp/union.out.file' FROM t1; -SELECT a INTO @v FROM t1 UNION SELECT a FROM t1; -ERROR HY000: Incorrect usage of UNION and INTO -SELECT a INTO OUTFILE '/tmp/union.out.file' FROM t1 UNION SELECT a FROM t1; -ERROR HY000: Incorrect usage of UNION and INTO -SELECT a INTO DUMPFILE '/tmp/union.out.file' FROM t1 UNION SELECT a FROM t1; -ERROR HY000: Incorrect usage of UNION and INTO -DROP TABLE t1; CREATE TABLE t1 ( `pseudo` char(35) NOT NULL default '', `pseudo1` char(35) NOT NULL default '', @@ -1588,3 +1546,39 @@ Warnings: Note 1003 select '0' AS `a` from `test`.`t1` union select '0' AS `a` from `test`.`t1` order by `a` DROP TABLE t1; End of 5.0 tests +# +# Bug#32858: Error: "Incorrect usage of UNION and INTO" does not take +# subselects into account +# +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1); +# Tests fix in parser rule select_derived_union. +SELECT a INTO @v FROM ( +SELECT a FROM t1 +UNION +SELECT a FROM t1 +) alias; +SELECT a INTO OUTFILE 'union.out.file' FROM ( +SELECT a FROM t1 +UNION +SELECT a FROM t1 WHERE 0 +) alias; +SELECT a INTO DUMPFILE 'union.out.file2' FROM ( +SELECT a FROM t1 +UNION +SELECT a FROM t1 WHERE 0 +) alias; +SELECT a FROM t1 UNION SELECT a INTO @v FROM t1; +SELECT a FROM t1 UNION SELECT a INTO OUTFILE 'union.out.file5' FROM t1; +SELECT a FROM t1 UNION SELECT a INTO OUTFILE 'union.out.file6' FROM t1; +SELECT a INTO @v FROM t1 UNION SELECT a FROM t1; +ERROR HY000: Incorrect usage of UNION and INTO +SELECT a INTO OUTFILE 'union.out.file7' FROM t1 UNION SELECT a FROM t1; +ERROR HY000: Incorrect usage of UNION and INTO +SELECT a INTO DUMPFILE 'union.out.file8' FROM t1 UNION SELECT a FROM t1; +ERROR HY000: Incorrect usage of UNION and INTO +# Tests fix in parser rule query_expression_body. +SELECT ( SELECT a UNION SELECT a ) INTO @v FROM t1; +SELECT ( SELECT a UNION SELECT a ) INTO OUTFILE 'union.out.file3' FROM t1; +SELECT ( SELECT a UNION SELECT a ) INTO DUMPFILE 'union.out.file4' FROM t1; +DROP TABLE t1; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 544017ebb97..d25aab68b5e 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -2513,8 +2513,6 @@ DROP TABLE t1, t2; CREATE TABLE t1 (i INT); (SELECT i FROM t1) UNION (SELECT i FROM t1); -#TODO:not supported ---error ER_PARSE_ERROR SELECT sql_no_cache * FROM t1 WHERE NOT EXISTS ( (SELECT i FROM t1) UNION @@ -2531,8 +2529,6 @@ WHERE NOT EXISTS (((SELECT i FROM t1) UNION (SELECT i FROM t1))); explain select ((select t11.i from t1 t11) union (select t12.i from t1 t12)) from t1; -#TODO:not supported ---error ER_PARSE_ERROR explain select * from t1 where not exists ((select t11.i from t1 t11) union (select t12.i from t1 t12)); @@ -3203,8 +3199,6 @@ EXPLAIN EXTENDED SELECT 2 FROM t1 WHERE EXISTS ((SELECT 1 FROM t2 WHERE t1.a=t2.a)); -#TODO:not supported ---error ER_PARSE_ERROR EXPLAIN EXTENDED SELECT 2 FROM t1 WHERE EXISTS ((SELECT 1 FROM t2 WHERE t1.a=t2.a) UNION (SELECT 1 FROM t2 WHERE t1.a = t2.a)); @@ -3544,4 +3538,231 @@ where v in(select v where t1.g=t2.g) is unknown; drop table t1, t2; +-- echo # +-- echo # Bug#33204: INTO is allowed in subselect, causing inconsistent results +-- echo # +CREATE TABLE t1( a INT ); +INSERT INTO t1 VALUES (1),(2); + +CREATE TABLE t2( a INT, b INT ); + +--error ER_PARSE_ERROR +SELECT * +FROM (SELECT a INTO @var FROM t1 WHERE a = 2) t1a; +--error ER_PARSE_ERROR +SELECT * +FROM (SELECT a INTO OUTFILE 'file' FROM t1 WHERE a = 2) t1a; +--error ER_PARSE_ERROR +SELECT * +FROM (SELECT a INTO DUMPFILE 'file' FROM t1 WHERE a = 2) t1a; + +--error ER_PARSE_ERROR +SELECT * FROM ( + SELECT 1 a + UNION + SELECT a INTO @var FROM t1 WHERE a = 2 +) t1a; + +--error ER_PARSE_ERROR +SELECT * FROM ( + SELECT 1 a + UNION + SELECT a INTO OUTFILE 'file' FROM t1 WHERE a = 2 +) t1a; + +--error ER_PARSE_ERROR +SELECT * FROM ( + SELECT 1 a + UNION + SELECT a INTO DUMPFILE 'file' FROM t1 WHERE a = 2 +) t1a; + +SELECT * FROM (SELECT a FROM t1 WHERE a = 2) t1a; + +SELECT * FROM ( + SELECT a FROM t1 WHERE a = 2 + UNION + SELECT a FROM t1 WHERE a = 2 +) t1a; + +SELECT * FROM ( + SELECT 1 a + UNION + SELECT a FROM t1 WHERE a = 2 + UNION + SELECT a FROM t1 WHERE a = 2 +) t1a; + +# This was not allowed previously. Possibly, it should be allowed on the future. +# For now, the intent is to keep the fix as non-intrusive as possible. +--error ER_PARSE_ERROR +SELECT * FROM ((SELECT 1 a) UNION SELECT 1 a); +SELECT * FROM (SELECT 1 a UNION (SELECT 1 a)) alias; +SELECT * FROM (SELECT 1 UNION SELECT 1) t1a; +--error ER_PARSE_ERROR +SELECT * FROM ((SELECT 1 a INTO @a)) t1a; +--error ER_PARSE_ERROR +SELECT * FROM ((SELECT 1 a INTO OUTFILE 'file' )) t1a; +--error ER_PARSE_ERROR +SELECT * FROM ((SELECT 1 a INTO DUMPFILE 'file' )) t1a; + +--error ER_PARSE_ERROR +SELECT * FROM (SELECT 1 a UNION (SELECT 1 a INTO @a)) t1a; +--error ER_PARSE_ERROR +SELECT * FROM (SELECT 1 a UNION (SELECT 1 a INTO DUMPFILE 'file' )) t1a; +--error ER_PARSE_ERROR +SELECT * FROM (SELECT 1 a UNION (SELECT 1 a INTO OUTFILE 'file' )) t1a; + +--error ER_PARSE_ERROR +SELECT * FROM (SELECT 1 a UNION ((SELECT 1 a INTO @a))) t1a; +--error ER_PARSE_ERROR +SELECT * FROM (SELECT 1 a UNION ((SELECT 1 a INTO DUMPFILE 'file' ))) t1a; +--error ER_PARSE_ERROR +SELECT * FROM (SELECT 1 a UNION ((SELECT 1 a INTO OUTFILE 'file' ))) t1a; + +SELECT * FROM (SELECT 1 a ORDER BY a) t1a; +SELECT * FROM (SELECT 1 a UNION SELECT 1 a ORDER BY a) t1a; +SELECT * FROM (SELECT 1 a UNION SELECT 1 a LIMIT 1) t1a; +SELECT * FROM (SELECT 1 a UNION SELECT 1 a ORDER BY a LIMIT 1) t1a; + +# Test of rule +# table_factor: '(' get_select_lex query_expression_body ')' opt_table_alias +# UNION should not be allowed inside the parentheses, nor should +# aliases after. +# +SELECT * FROM t1 JOIN (SELECT 1 UNION SELECT 1) alias ON 1; +--error ER_PARSE_ERROR +SELECT * FROM t1 JOIN ((SELECT 1 UNION SELECT 1)) ON 1; +--error ER_PARSE_ERROR +SELECT * FROM t1 JOIN (t1 t1a UNION SELECT 1) ON 1; +--error ER_PARSE_ERROR +SELECT * FROM t1 JOIN ((t1 t1a UNION SELECT 1)) ON 1; +--error ER_PARSE_ERROR +SELECT * FROM t1 JOIN (t1 t1a) t1a ON 1; +--error ER_PARSE_ERROR +SELECT * FROM t1 JOIN ((t1 t1a)) t1a ON 1; + +SELECT * FROM t1 JOIN (t1 t1a) ON 1; +SELECT * FROM t1 JOIN ((t1 t1a)) ON 1; + +SELECT * FROM (t1 t1a); +SELECT * FROM ((t1 t1a)); + +SELECT * FROM t1 JOIN (SELECT 1 t1a) alias ON 1; +SELECT * FROM t1 JOIN ((SELECT 1 t1a)) alias ON 1; + +SELECT * FROM t1 JOIN (SELECT 1 a) a ON 1; +SELECT * FROM t1 JOIN ((SELECT 1 a)) a ON 1; + +# For the join, TABLE_LIST::select_lex == NULL +# Check that we handle this. +--error ER_PARSE_ERROR +SELECT * FROM (t1 JOIN (SELECT 1) t1a1 ON 1) t1a2; + +SELECT * FROM t1 WHERE a = ALL ( SELECT 1 ); +SELECT * FROM t1 WHERE a = ALL ( SELECT 1 UNION SELECT 1 ); +SELECT * FROM t1 WHERE a = ANY ( SELECT 3 UNION SELECT 1 ); + +--error ER_PARSE_ERROR +SELECT * FROM t1 WHERE a = ANY ( SELECT 1 UNION SELECT 1 INTO @a); +--error ER_PARSE_ERROR +SELECT * FROM t1 WHERE a = ANY ( SELECT 1 UNION SELECT 1 INTO OUTFILE 'file' ); +--error ER_PARSE_ERROR +SELECT * FROM t1 WHERE a = ANY ( SELECT 1 UNION SELECT 1 INTO DUMPFILE 'file' ); + +SELECT * FROM t1 WHERE a = ( SELECT 1 ); +SELECT * FROM t1 WHERE a = ( SELECT 1 UNION SELECT 1 ); +--error ER_PARSE_ERROR +SELECT * FROM t1 WHERE a = ( SELECT 1 INTO @a); +--error ER_PARSE_ERROR +SELECT * FROM t1 WHERE a = ( SELECT 1 INTO OUTFILE 'file' ); +--error ER_PARSE_ERROR +SELECT * FROM t1 WHERE a = ( SELECT 1 INTO DUMPFILE 'file' ); + +--error ER_PARSE_ERROR +SELECT * FROM t1 WHERE a = ( SELECT 1 UNION SELECT 1 INTO @a); +--error ER_PARSE_ERROR +SELECT * FROM t1 WHERE a = ( SELECT 1 UNION SELECT 1 INTO OUTFILE 'file' ); +--error ER_PARSE_ERROR +SELECT * FROM t1 WHERE a = ( SELECT 1 UNION SELECT 1 INTO DUMPFILE 'file' ); + +--error ER_PARSE_ERROR +SELECT ( SELECT 1 INTO @v ); +--error ER_PARSE_ERROR +SELECT ( SELECT 1 INTO OUTFILE 'file' ); +--error ER_PARSE_ERROR +SELECT ( SELECT 1 INTO DUMPFILE 'file' ); + +--error ER_PARSE_ERROR +SELECT ( SELECT 1 UNION SELECT 1 INTO @v ); +--error ER_PARSE_ERROR +SELECT ( SELECT 1 UNION SELECT 1 INTO OUTFILE 'file' ); +--error ER_PARSE_ERROR +SELECT ( SELECT 1 UNION SELECT 1 INTO DUMPFILE 'file' ); + +# Make sure context is popped when we leave the nested select +SELECT ( SELECT a FROM t1 WHERE a = 1 ), a FROM t1; +SELECT ( SELECT a FROM t1 WHERE a = 1 UNION SELECT 1 ), a FROM t1; + +# Make sure we have feature F561 (see .yy file) +SELECT * FROM t2 WHERE (a, b) IN (SELECT a, b FROM t2); + +# Make sure the parser does not allow nested UNIONs anywhere + +--error ER_PARSE_ERROR +SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ); +--error ER_PARSE_ERROR +( SELECT 1 UNION SELECT 1 ) UNION SELECT 1; + +--error ER_PARSE_ERROR +SELECT ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) ); +--error ER_PARSE_ERROR +SELECT ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1; +SELECT ( SELECT 1 UNION SELECT 1 UNION SELECT 1 ); +SELECT ((SELECT 1 UNION SELECT 1 UNION SELECT 1)); + +--error ER_PARSE_ERROR +SELECT * FROM ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) ); +--error ER_PARSE_ERROR +SELECT * FROM ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 ); +SELECT * FROM ( SELECT 1 UNION SELECT 1 UNION SELECT 1 ) a; + +--error ER_PARSE_ERROR +SELECT * FROM t1 WHERE a = ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) ); +--error ER_PARSE_ERROR +SELECT * FROM t1 WHERE a = ALL ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) ); +--error ER_PARSE_ERROR +SELECT * FROM t1 WHERE a = ANY ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) ); +--error ER_PARSE_ERROR +SELECT * FROM t1 WHERE a IN ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) ); + +--error ER_PARSE_ERROR +SELECT * FROM t1 WHERE a = ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 ); +--error ER_PARSE_ERROR +SELECT * FROM t1 WHERE a = ALL ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 ); +--error ER_PARSE_ERROR +SELECT * FROM t1 WHERE a = ANY ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 ); +--error ER_PARSE_ERROR +SELECT * FROM t1 WHERE a IN ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 ); + +SELECT * FROM t1 WHERE a = ( SELECT 1 UNION SELECT 1 UNION SELECT 1 ); +SELECT * FROM t1 WHERE a = ALL ( SELECT 1 UNION SELECT 1 UNION SELECT 1 ); +SELECT * FROM t1 WHERE a = ANY ( SELECT 1 UNION SELECT 1 UNION SELECT 1 ); +SELECT * FROM t1 WHERE a IN ( SELECT 1 UNION SELECT 1 UNION SELECT 1 ); + +--error ER_PARSE_ERROR +SELECT * FROM t1 WHERE EXISTS ( SELECT 1 UNION SELECT 1 INTO @v ); +SELECT EXISTS(SELECT 1+1); +--error ER_PARSE_ERROR +SELECT EXISTS(SELECT 1+1 INTO @test); +--error ER_PARSE_ERROR +SELECT * FROM t1 WHERE a IN ( SELECT 1 UNION SELECT 1 INTO @v ); + +--error ER_PARSE_ERROR +SELECT * FROM t1 WHERE EXISTS ( SELECT 1 INTO @v ); +--error ER_PARSE_ERROR +SELECT * FROM t1 WHERE a IN ( SELECT 1 INTO @v ); + +DROP TABLE t1, t2; + --echo End of 5.1 tests. diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index ec169838d59..dc4173039d2 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -91,88 +91,6 @@ SELECT @a:=1 UNION SELECT @a:=@a+1; (SELECT 1) UNION (SELECT 2) ORDER BY (SELECT a); (SELECT 1,3) UNION (SELECT 2,1) ORDER BY (SELECT 2); - -# -# Bug#32858: Erro: "Incorrect usage of UNION and INTO" does not take subselects -# into account -# -CREATE TABLE t1 (a INT); -INSERT INTO t1 VALUES (1); - -SELECT a INTO @v FROM ( - SELECT a FROM t1 - UNION - SELECT a FROM t1 -) alias; - ---let $outfile = $MYSQLTEST_VARDIR/tmp/union.out.file ---error 0,1 ---remove_file $outfile - ---replace_result $MYSQLTEST_VARDIR -eval SELECT a INTO OUTFILE '$outfile' FROM ( - SELECT a FROM t1 - UNION - SELECT a FROM t1 WHERE 0 -) alias; ---remove_file $outfile - ---replace_result $MYSQLTEST_VARDIR -eval SELECT a INTO DUMPFILE '$outfile' FROM ( - SELECT a FROM t1 - UNION - SELECT a FROM t1 WHERE 0 -) alias; ---remove_file $outfile - -# -# INTO will not be allowed in subqueries in version 5.1 and above. -# -SELECT a FROM ( - SELECT a FROM t1 - UNION - SELECT a INTO @v FROM t1 -) alias; - ---replace_result $MYSQLTEST_VARDIR -eval SELECT a FROM ( - SELECT a FROM t1 - UNION - SELECT a INTO OUTFILE '$outfile' FROM t1 -) alias; ---remove_file $outfile - ---replace_result $MYSQLTEST_VARDIR -eval SELECT a FROM ( - SELECT a FROM t1 - UNION - SELECT a INTO DUMPFILE '$outfile' FROM t1 -) alias; ---remove_file $outfile - -SELECT a FROM t1 UNION SELECT a INTO @v FROM t1; - ---replace_result $MYSQLTEST_VARDIR -eval SELECT a FROM t1 UNION SELECT a INTO OUTFILE '$outfile' FROM t1; ---remove_file $outfile - ---replace_result $MYSQLTEST_VARDIR -eval SELECT a FROM t1 UNION SELECT a INTO DUMPFILE '$outfile' FROM t1; ---remove_file $outfile - ---error ER_WRONG_USAGE -SELECT a INTO @v FROM t1 UNION SELECT a FROM t1; - ---replace_result $MYSQLTEST_VARDIR ---error ER_WRONG_USAGE -eval SELECT a INTO OUTFILE '$outfile' FROM t1 UNION SELECT a FROM t1; - ---replace_result $MYSQLTEST_VARDIR ---error ER_WRONG_USAGE -eval SELECT a INTO DUMPFILE '$outfile' FROM t1 UNION SELECT a FROM t1; - -DROP TABLE t1; - # # Test bug reported by joc@presence-pc.com # @@ -1102,3 +1020,45 @@ DROP TABLE t1; --echo End of 5.0 tests +-- echo # +-- echo # Bug#32858: Error: "Incorrect usage of UNION and INTO" does not take +-- echo # subselects into account +-- echo # +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1); + +-- echo # Tests fix in parser rule select_derived_union. +SELECT a INTO @v FROM ( + SELECT a FROM t1 + UNION + SELECT a FROM t1 +) alias; + +SELECT a INTO OUTFILE 'union.out.file' FROM ( + SELECT a FROM t1 + UNION + SELECT a FROM t1 WHERE 0 +) alias; + +SELECT a INTO DUMPFILE 'union.out.file2' FROM ( + SELECT a FROM t1 + UNION + SELECT a FROM t1 WHERE 0 +) alias; + +SELECT a FROM t1 UNION SELECT a INTO @v FROM t1; +SELECT a FROM t1 UNION SELECT a INTO OUTFILE 'union.out.file5' FROM t1; +SELECT a FROM t1 UNION SELECT a INTO OUTFILE 'union.out.file6' FROM t1; +--error ER_WRONG_USAGE +SELECT a INTO @v FROM t1 UNION SELECT a FROM t1; +--error ER_WRONG_USAGE +SELECT a INTO OUTFILE 'union.out.file7' FROM t1 UNION SELECT a FROM t1; +--error ER_WRONG_USAGE +SELECT a INTO DUMPFILE 'union.out.file8' FROM t1 UNION SELECT a FROM t1; + +-- echo # Tests fix in parser rule query_expression_body. +SELECT ( SELECT a UNION SELECT a ) INTO @v FROM t1; +SELECT ( SELECT a UNION SELECT a ) INTO OUTFILE 'union.out.file3' FROM t1; +SELECT ( SELECT a UNION SELECT a ) INTO DUMPFILE 'union.out.file4' FROM t1; + +DROP TABLE t1; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 757f6abb00b..95bdbc5e093 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1626,7 +1626,6 @@ void THD::rollback_item_tree_changes() select_result::select_result() { thd=current_thd; - nest_level= -1; } void select_result::send_error(uint errcode,const char *err) diff --git a/sql/sql_class.h b/sql/sql_class.h index aaa959feae9..cefa65925d2 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2381,7 +2381,6 @@ class select_result :public Sql_alloc { protected: THD *thd; SELECT_LEX_UNIT *unit; - uint nest_level; public: select_result(); virtual ~select_result() {}; @@ -2418,12 +2417,6 @@ public: */ virtual void cleanup(); void set_thd(THD *thd_arg) { thd= thd_arg; } - /** - The nest level, if supported. - @return - -1 if nest level is undefined, otherwise a positive integer. - */ - int get_nest_level() { return nest_level; } #ifdef EMBEDDED_LIBRARY virtual void begin_dataset() {} #else @@ -2518,14 +2511,6 @@ class select_export :public select_to_file { CHARSET_INFO *write_cs; // output charset public: select_export(sql_exchange *ex) :select_to_file(ex) {} - /** - Creates a select_export to represent INTO OUTFILE with a - defined level of subquery nesting. - */ - select_export(sql_exchange *ex, uint nest_level_arg) :select_to_file(ex) - { - nest_level= nest_level_arg; - } ~select_export(); int prepare(List &list, SELECT_LEX_UNIT *u); bool send_data(List &items); @@ -2535,15 +2520,6 @@ public: class select_dump :public select_to_file { public: select_dump(sql_exchange *ex) :select_to_file(ex) {} - /** - Creates a select_export to represent INTO DUMPFILE with a - defined level of subquery nesting. - */ - select_dump(sql_exchange *ex, uint nest_level_arg) : - select_to_file(ex) - { - nest_level= nest_level_arg; - } int prepare(List &list, SELECT_LEX_UNIT *u); bool send_data(List &items); }; @@ -3014,16 +2990,6 @@ class select_dumpvar :public select_result_interceptor { public: List var_list; select_dumpvar() { var_list.empty(); row_count= 0;} - /** - Creates a select_dumpvar to represent INTO with a defined - level of subquery nesting. - */ - select_dumpvar(uint nest_level_arg) - { - var_list.empty(); - row_count= 0; - nest_level= nest_level_arg; - } ~select_dumpvar() {} int prepare(List &list, SELECT_LEX_UNIT *u); bool send_data(List &items); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 05283718162..43f5c73f5e7 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -468,6 +468,90 @@ Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal, DBUG_RETURN(result); } +/** + @brief Creates a new SELECT_LEX for a UNION branch. + + Sets up and initializes a SELECT_LEX structure for a query once the parser + discovers a UNION token. The current SELECT_LEX is pushed on the stack and + the new SELECT_LEX becomes the current one. + + @param lex The parser state. + + @param is_union_distinct True if the union preceding the new select statement + uses UNION DISTINCT. + + @param is_top_level This should be @c TRUE if the newly created SELECT_LEX + is a non-nested statement. + + @return false if successful, true if an error was + reported. In the latter case parsing should stop. + */ +bool add_select_to_union_list(LEX *lex, bool is_union_distinct, + bool is_top_level) +{ + /* + Only the last SELECT can have INTO. Since the grammar won't allow INTO in + a nested SELECT, we make this check only when creating a top-level SELECT. + */ + if (is_top_level && lex->result) + { + my_error(ER_WRONG_USAGE, MYF(0), "UNION", "INTO"); + return TRUE; + } + if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE) + { + my_parse_error(ER(ER_SYNTAX_ERROR)); + return TRUE; + } + /* This counter shouldn't be incremented for UNION parts */ + lex->nest_level--; + if (mysql_new_select(lex, 0)) + return TRUE; + mysql_init_select(lex); + lex->current_select->linkage=UNION_TYPE; + if (is_union_distinct) /* UNION DISTINCT - remember position */ + lex->current_select->master_unit()->union_distinct= + lex->current_select; + return FALSE; +} + +/** + @brief Initializes a SELECT_LEX for a query within parentheses (aka + braces). + + @return false if successful, true if an error was reported. In the latter + case parsing should stop. + */ +bool setup_select_in_parentheses(LEX *lex) +{ + SELECT_LEX * sel= lex->current_select; + if (sel->set_braces(1)) + { + my_parse_error(ER(ER_SYNTAX_ERROR)); + return TRUE; + } + if (sel->linkage == UNION_TYPE && + !sel->master_unit()->first_select()->braces && + sel->master_unit()->first_select()->linkage == + UNION_TYPE) + { + my_parse_error(ER(ER_SYNTAX_ERROR)); + return TRUE; + } + if (sel->linkage == UNION_TYPE && + sel->olap != UNSPECIFIED_OLAP_TYPE && + sel->master_unit()->fake_select_lex) + { + my_error(ER_WRONG_USAGE, MYF(0), "CUBE/ROLLUP", "ORDER BY"); + return TRUE; + } + /* select in braces, can't contain global parameters */ + if (sel->master_unit()->fake_select_lex) + sel->master_unit()->global_parameters= + sel->master_unit()->fake_select_lex; + return FALSE; +} + %} %union { int num; @@ -521,10 +605,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %pure_parser /* We have threads */ /* - Currently there are 168 shift/reduce conflicts. + Currently there are 174 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 168 +%expect 174 /* Comments for TOKENS. @@ -1240,6 +1324,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); join_table_list join_table table_factor table_ref esc_table_ref select_derived derived_table_list + select_derived_union %type date_time_type; %type interval @@ -1275,8 +1360,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type internal_variable_name -%type subselect take_first_select - get_select_lex +%type subselect + get_select_lex query_specification + query_expression_body %type comp_op @@ -6757,37 +6843,22 @@ select_init: select_paren: SELECT_SYM select_part2 { - LEX *lex= Lex; - SELECT_LEX * sel= lex->current_select; - if (sel->set_braces(1)) - { - my_parse_error(ER(ER_SYNTAX_ERROR)); + if (setup_select_in_parentheses(Lex)) MYSQL_YYABORT; - } - if (sel->linkage == UNION_TYPE && - !sel->master_unit()->first_select()->braces && - sel->master_unit()->first_select()->linkage == - UNION_TYPE) - { - my_parse_error(ER(ER_SYNTAX_ERROR)); - MYSQL_YYABORT; - } - if (sel->linkage == UNION_TYPE && - sel->olap != UNSPECIFIED_OLAP_TYPE && - sel->master_unit()->fake_select_lex) - { - my_error(ER_WRONG_USAGE, MYF(0), - "CUBE/ROLLUP", "ORDER BY"); - MYSQL_YYABORT; - } - /* select in braces, can't contain global parameters */ - if (sel->master_unit()->fake_select_lex) - sel->master_unit()->global_parameters= - sel->master_unit()->fake_select_lex; } | '(' select_paren ')' ; +/* The equivalent of select_paren for nested queries. */ +select_paren_derived: + SELECT_SYM select_part2_derived + { + if (setup_select_in_parentheses(Lex)) + MYSQL_YYABORT; + } + | '(' select_paren_derived ')' + ; + select_init2: select_part2 { @@ -8626,6 +8697,7 @@ when_list: } ; +/* Equivalent to in the SQL:2003 standard. */ /* Warning - may return NULL in case of incomplete SELECT */ table_ref: table_factor { $$=$1; } @@ -8653,6 +8725,7 @@ esc_table_ref: | '{' ident table_ref '}' { $$=$3; } ; +/* Equivalent to
in the SQL:2003 standard. */ /* Warning - may return NULL in case of incomplete SELECT */ derived_table_list: esc_table_ref { $$=$1; } @@ -8806,6 +8879,13 @@ normal_join: | CROSS JOIN_SYM {} ; +/* + This is a flattening of the rules
and
+ in the SQL:2003 standard, since we don't have + + I.e. +
::=
[ ] +*/ /* Warning - may return NULL in case of incomplete SELECT */ table_factor: { @@ -8843,12 +8923,29 @@ table_factor: /* incomplete derived tables return NULL, we must be nested in select_derived rule to be here. */ } - | '(' get_select_lex select_derived union_opt ')' opt_table_alias + /* + Represents a flattening of the following rules from the SQL:2003 + standard. This sub-rule corresponds to the sub-rule +
::= ... | [ AS ] + + The following rules have been flattened into query_expression_body + (since we have no ). + + ::=
+
::= + ::= + ::= [ ] + + For the time being we use the non-standard rule + select_derived_union which is a compromise between the standard + and our parser. Possibly this rule could be replaced by our + query_expression_body. + */ + | '(' get_select_lex select_derived_union ')' opt_table_alias { /* Use $2 instead of Lex->current_select as derived table will alter value of Lex->current_select. */ - - if (!($3 || $6) && $2->embedding && + if (!($3 || $5) && $2->embedding && !$2->embedding->nested_join->join_list.elements) { /* we have a derived table ($3 == NULL) but no alias, @@ -8870,7 +8967,7 @@ table_factor: if (ti == NULL) MYSQL_YYABORT; if (!($$= sel->add_table_to_list(lex->thd, - ti, $6, 0, + new Table_ident(unit), $5, 0, TL_READ))) MYSQL_YYABORT; @@ -8878,7 +8975,8 @@ table_factor: lex->pop_context(); lex->nest_level--; } - else if ($4 || $6) + else if ($3->select_lex && + $3->select_lex->master_unit()->is_union() || $5) { /* simple nested joins cannot have aliases or unions */ my_parse_error(ER(ER_SYNTAX_ERROR)); @@ -8893,6 +8991,62 @@ table_factor: } ; +select_derived_union: + select_derived opt_order_clause opt_limit_clause + | select_derived_union + UNION_SYM + union_option + { + if (add_select_to_union_list(Lex, (bool)$3, FALSE)) + MYSQL_YYABORT; + } + query_specification + { + /* + Remove from the name resolution context stack the context of the + last select in the union. + */ + Lex->pop_context(); + } + opt_order_clause opt_limit_clause + ; + +/* The equivalent of select_init2 for nested queries. */ +select_init2_derived: + select_part2_derived + { + LEX *lex= Lex; + SELECT_LEX * sel= lex->current_select; + if (lex->current_select->set_braces(0)) + { + my_parse_error(ER(ER_SYNTAX_ERROR)); + MYSQL_YYABORT; + } + if (sel->linkage == UNION_TYPE && + sel->master_unit()->first_select()->braces) + { + my_parse_error(ER(ER_SYNTAX_ERROR)); + MYSQL_YYABORT; + } + } + ; + +/* The equivalent of select_part2 for nested queries. */ +select_part2_derived: + { + LEX *lex= Lex; + SELECT_LEX *sel= lex->current_select; + if (sel->linkage != UNION_TYPE) + mysql_init_select(lex); + lex->current_select->parsing_place= SELECT_LIST; + } + select_options select_item_list + { + Select->parsing_place= NO_MATTER; + } + opt_select_from select_lock_type + ; + /* handle contents of parentheses in join expression */ select_derived: get_select_lex @@ -9508,8 +9662,7 @@ procedure_item: select_var_list_init: { LEX *lex=Lex; - if (!lex->describe && - (!(lex->result= new select_dumpvar(lex->nest_level)))) + if (!lex->describe && (!(lex->result= new select_dumpvar()))) MYSQL_YYABORT; } select_var_list @@ -9590,7 +9743,7 @@ into_destination: LEX *lex= Lex; lex->uncacheable(UNCACHEABLE_SIDEEFFECT); if (!(lex->exchange= new sql_exchange($2.str, 0)) || - !(lex->result= new select_export(lex->exchange, lex->nest_level))) + !(lex->result= new select_export(lex->exchange))) MYSQL_YYABORT; } opt_load_data_charset @@ -9604,7 +9757,7 @@ into_destination: lex->uncacheable(UNCACHEABLE_SIDEEFFECT); if (!(lex->exchange= new sql_exchange($2.str,1))) MYSQL_YYABORT; - if (!(lex->result= new select_dump(lex->exchange, lex->nest_level))) + if (!(lex->result= new select_dump(lex->exchange))) MYSQL_YYABORT; } } @@ -13223,33 +13376,8 @@ union_clause: union_list: UNION_SYM union_option { - LEX *lex=Lex; - if (lex->result && - (lex->result->get_nest_level() == -1 || - lex->result->get_nest_level() == lex->nest_level)) - { - /* - Only the last SELECT can have INTO unless the INTO and UNION - are at different nest levels. In version 5.1 and above, INTO - will onle be allowed at top level. - */ - my_error(ER_WRONG_USAGE, MYF(0), "UNION", "INTO"); - MYSQL_YYABORT; - } - if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE) - { - my_parse_error(ER(ER_SYNTAX_ERROR)); + if (add_select_to_union_list(Lex, (bool)$2, TRUE)) MYSQL_YYABORT; - } - /* This counter shouldn't be incremented for UNION parts */ - Lex->nest_level--; - if (mysql_new_select(lex, 0)) - MYSQL_YYABORT; - mysql_init_select(lex); - lex->current_select->linkage=UNION_TYPE; - if ($2) /* UNION DISTINCT - remember position */ - lex->current_select->master_unit()->union_distinct= - lex->current_select; } select_init { @@ -13302,22 +13430,39 @@ union_option: | ALL { $$=0; } ; -take_first_select: /* empty */ - { - $$= Lex->current_select->master_unit()->first_select(); - }; +query_specification: + SELECT_SYM select_init2_derived + { + $$= Lex->current_select->master_unit()->first_select(); + } + | '(' select_paren_derived ')' + { + $$= Lex->current_select->master_unit()->first_select(); + } + ; +query_expression_body: + query_specification + | query_expression_body + UNION_SYM union_option + { + if (add_select_to_union_list(Lex, (bool)$3, FALSE)) + MYSQL_YYABORT; + } + query_specification + { + Lex->pop_context(); + $$= $1; + } + ; + +/* Corresponds to in the SQL:2003 standard. */ subselect: - SELECT_SYM subselect_start select_init2 take_first_select - subselect_end - { - $$= $4; - } - | '(' subselect_start select_paren take_first_select - subselect_end ')' - { - $$= $4; - }; + subselect_start query_expression_body subselect_end + { + $$= $2; + } + ; subselect_start: {