mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
MDEV-19956 Queries with subqueries containing UNION are not parsed
Shift-Reduce conflicts prevented parsing some queries with subqueries that used set operations when the subqueries occurred in expressions or in IN predicands. The grammar rules for query expression were transformed in order to avoid these conflicts. New grammar rules employ an idea taken from MySQL 8.0.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -25,7 +25,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
3 EXCEPT t2 ALL NULL NULL NULL NULL 2 100.00
|
||||
NULL EXCEPT RESULT <except2,3> ALL NULL NULL NULL NULL NULL NULL
|
||||
Warnings:
|
||||
Note 1003 /* select#1 */ select `a`.`a` AS `a`,`a`.`b` AS `b` from (/* select#2 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` except (/* select#3 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2`)) `a`
|
||||
Note 1003 /* select#1 */ select `a`.`a` AS `a`,`a`.`b` AS `b` from ((/* select#2 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1`) except (/* select#3 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2`)) `a`
|
||||
EXPLAIN format=json (select a,b from t1) except (select c,d from t2);
|
||||
EXPLAIN
|
||||
{
|
||||
@ -230,7 +230,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
3 EXCEPT t4 ALL NULL NULL NULL NULL 2 100.00 Using join buffer (flat, BNL join)
|
||||
NULL EXCEPT RESULT <except2,3> ALL NULL NULL NULL NULL NULL NULL
|
||||
Warnings:
|
||||
Note 1003 /* select#1 */ select `a`.`a` AS `a`,`a`.`b` AS `b`,`a`.`e` AS `e`,`a`.`f` AS `f` from (/* select#2 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t1` join `test`.`t3` except (/* select#3 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d`,`test`.`t4`.`g` AS `g`,`test`.`t4`.`h` AS `h` from `test`.`t2` join `test`.`t4`)) `a`
|
||||
Note 1003 /* select#1 */ select `a`.`a` AS `a`,`a`.`b` AS `b`,`a`.`e` AS `e`,`a`.`f` AS `f` from ((/* select#2 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t1` join `test`.`t3`) except (/* select#3 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d`,`test`.`t4`.`g` AS `g`,`test`.`t4`.`h` AS `h` from `test`.`t2` join `test`.`t4`)) `a`
|
||||
EXPLAIN format=json (select a,b,e,f from t1,t3) except (select c,d,g,h from t2,t4);
|
||||
EXPLAIN
|
||||
{
|
||||
|
@ -39,7 +39,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
4 INTERSECT t3 ALL NULL NULL NULL NULL 3 100.00
|
||||
NULL INTERSECT RESULT <intersect2,3,4> ALL NULL NULL NULL NULL NULL NULL
|
||||
Warnings:
|
||||
Note 1003 /* select#1 */ select `a`.`a` AS `a`,`a`.`b` AS `b` from (/* select#2 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` intersect (/* select#3 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2`) intersect (/* select#4 */ select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3`)) `a`
|
||||
Note 1003 /* select#1 */ select `a`.`a` AS `a`,`a`.`b` AS `b` from ((/* select#2 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1`) intersect (/* select#3 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2`) intersect (/* select#4 */ select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3`)) `a`
|
||||
EXPLAIN format=json (select a,b from t1) intersect (select c,d from t2) intersect (select e,f from t3);
|
||||
EXPLAIN
|
||||
{
|
||||
@ -280,7 +280,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
3 INTERSECT t3 ALL NULL NULL NULL NULL 3 100.00 Using join buffer (flat, BNL join)
|
||||
NULL INTERSECT RESULT <intersect2,3> ALL NULL NULL NULL NULL NULL NULL
|
||||
Warnings:
|
||||
Note 1003 /* select#1 */ select `a`.`a` AS `a`,`a`.`b` AS `b` from (/* select#2 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` intersect (/* select#3 */ select `test`.`t2`.`c` AS `c`,`test`.`t3`.`e` AS `e` from `test`.`t2` join `test`.`t3`)) `a`
|
||||
Note 1003 /* select#1 */ select `a`.`a` AS `a`,`a`.`b` AS `b` from ((/* select#2 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1`) intersect (/* select#3 */ select `test`.`t2`.`c` AS `c`,`test`.`t3`.`e` AS `e` from `test`.`t2` join `test`.`t3`)) `a`
|
||||
set @@optimizer_switch='optimize_join_buffer_size=off';
|
||||
EXPLAIN format=json (select a,b from t1) intersect (select c,e from t2,t3);
|
||||
EXPLAIN
|
||||
@ -724,7 +724,7 @@ a b
|
||||
drop procedure p1;
|
||||
show create view v1;
|
||||
View Create View character_set_client collation_connection
|
||||
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS (select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1`) union select `__6`.`c` AS `c`,`__6`.`d` AS `d` from (select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2` intersect (select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3`)) `__6` union (select 4 AS `4`,4 AS `4`) latin1 latin1_swedish_ci
|
||||
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS (select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1`) union select `__6`.`c` AS `c`,`__6`.`d` AS `d` from ((select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2`) intersect (select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3`)) `__6` union (select 4 AS `4`,4 AS `4`) latin1 latin1_swedish_ci
|
||||
drop view v1;
|
||||
drop tables t1,t2,t3;
|
||||
#
|
||||
|
@ -1776,7 +1776,7 @@ End of 10.3 tests
|
||||
#
|
||||
create table t1 (a int);
|
||||
(select * from t1) for update;
|
||||
ERROR HY000: Incorrect usage of lock options and SELECT in brackets
|
||||
a
|
||||
(select * from t1) union (select * from t1) for update;
|
||||
ERROR HY000: Incorrect usage of lock options and SELECT in brackets
|
||||
(select * from t1 for update);
|
||||
|
@ -1544,7 +1544,6 @@ SELECT @@GLOBAL.role;
|
||||
--echo #
|
||||
|
||||
create table t1 (a int);
|
||||
--error ER_WRONG_USAGE
|
||||
(select * from t1) for update;
|
||||
--error ER_WRONG_USAGE
|
||||
(select * from t1) union (select * from t1) for update;
|
||||
|
@ -3736,8 +3736,11 @@ WHERE NOT EXISTS (((SELECT i FROM t1) UNION (SELECT i FROM t1)));
|
||||
i
|
||||
explain select ((select t11.i from t1 t11) union (select t12.i from t1 t12))
|
||||
from t1;
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'union (select t12.i from t1 t12))
|
||||
from t1' at line 1
|
||||
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 <union2,3> ALL NULL NULL NULL NULL NULL
|
||||
explain select * from t1 where not exists
|
||||
((select t11.i from t1 t11) union (select t12.i from t1 t12));
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
@ -5305,7 +5308,7 @@ 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;
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'UNION SELECT 1' at line 1
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '' at line 1
|
||||
SELECT ( SELECT 1 UNION SELECT 1 UNION SELECT 1 );
|
||||
( SELECT 1 UNION SELECT 1 UNION SELECT 1 )
|
||||
1
|
||||
@ -5335,7 +5338,8 @@ SELECT * FROM t1 WHERE a IN ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) );
|
||||
a
|
||||
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 MariaDB server version for the right syntax to use near 'UNION SELECT 1 )' at line 1
|
||||
a
|
||||
1
|
||||
SELECT * FROM t1 WHERE a = ALL ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 );
|
||||
a
|
||||
1
|
||||
@ -5343,7 +5347,8 @@ 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 );
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'UNION SELECT 1 )' at line 1
|
||||
a
|
||||
1
|
||||
SELECT * FROM t1 WHERE a = ( SELECT 1 UNION SELECT 1 UNION SELECT 1 );
|
||||
a
|
||||
1
|
||||
|
@ -2611,8 +2611,6 @@ SELECT sql_no_cache * FROM t1 WHERE NOT EXISTS
|
||||
SELECT * FROM t1
|
||||
WHERE NOT EXISTS (((SELECT i FROM t1) UNION (SELECT i FROM t1)));
|
||||
|
||||
#TODO:not supported
|
||||
--error ER_PARSE_ERROR
|
||||
explain select ((select t11.i from t1 t11) union (select t12.i from t1 t12))
|
||||
from t1;
|
||||
|
||||
@ -4414,11 +4412,9 @@ 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 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 );
|
||||
--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 );
|
||||
|
@ -3739,8 +3739,11 @@ WHERE NOT EXISTS (((SELECT i FROM t1) UNION (SELECT i FROM t1)));
|
||||
i
|
||||
explain select ((select t11.i from t1 t11) union (select t12.i from t1 t12))
|
||||
from t1;
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'union (select t12.i from t1 t12))
|
||||
from t1' at line 1
|
||||
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 <union2,3> ALL NULL NULL NULL NULL NULL
|
||||
explain select * from t1 where not exists
|
||||
((select t11.i from t1 t11) union (select t12.i from t1 t12));
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
@ -5307,7 +5310,7 @@ 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;
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'UNION SELECT 1' at line 1
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '' at line 1
|
||||
SELECT ( SELECT 1 UNION SELECT 1 UNION SELECT 1 );
|
||||
( SELECT 1 UNION SELECT 1 UNION SELECT 1 )
|
||||
1
|
||||
@ -5337,7 +5340,8 @@ SELECT * FROM t1 WHERE a IN ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) );
|
||||
a
|
||||
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 MariaDB server version for the right syntax to use near 'UNION SELECT 1 )' at line 1
|
||||
a
|
||||
1
|
||||
SELECT * FROM t1 WHERE a = ALL ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 );
|
||||
a
|
||||
1
|
||||
@ -5345,7 +5349,8 @@ 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 );
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'UNION SELECT 1 )' at line 1
|
||||
a
|
||||
1
|
||||
SELECT * FROM t1 WHERE a = ( SELECT 1 UNION SELECT 1 UNION SELECT 1 );
|
||||
a
|
||||
1
|
||||
|
@ -3739,8 +3739,11 @@ WHERE NOT EXISTS (((SELECT i FROM t1) UNION (SELECT i FROM t1)));
|
||||
i
|
||||
explain select ((select t11.i from t1 t11) union (select t12.i from t1 t12))
|
||||
from t1;
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'union (select t12.i from t1 t12))
|
||||
from t1' at line 1
|
||||
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 <union2,3> ALL NULL NULL NULL NULL NULL
|
||||
explain select * from t1 where not exists
|
||||
((select t11.i from t1 t11) union (select t12.i from t1 t12));
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
@ -5305,7 +5308,7 @@ 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;
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'UNION SELECT 1' at line 1
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '' at line 1
|
||||
SELECT ( SELECT 1 UNION SELECT 1 UNION SELECT 1 );
|
||||
( SELECT 1 UNION SELECT 1 UNION SELECT 1 )
|
||||
1
|
||||
@ -5335,7 +5338,8 @@ SELECT * FROM t1 WHERE a IN ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) );
|
||||
a
|
||||
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 MariaDB server version for the right syntax to use near 'UNION SELECT 1 )' at line 1
|
||||
a
|
||||
1
|
||||
SELECT * FROM t1 WHERE a = ALL ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 );
|
||||
a
|
||||
1
|
||||
@ -5343,7 +5347,8 @@ 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 );
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'UNION SELECT 1 )' at line 1
|
||||
a
|
||||
1
|
||||
SELECT * FROM t1 WHERE a = ( SELECT 1 UNION SELECT 1 UNION SELECT 1 );
|
||||
a
|
||||
1
|
||||
|
@ -3735,8 +3735,11 @@ WHERE NOT EXISTS (((SELECT i FROM t1) UNION (SELECT i FROM t1)));
|
||||
i
|
||||
explain select ((select t11.i from t1 t11) union (select t12.i from t1 t12))
|
||||
from t1;
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'union (select t12.i from t1 t12))
|
||||
from t1' at line 1
|
||||
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 <union2,3> ALL NULL NULL NULL NULL NULL
|
||||
explain select * from t1 where not exists
|
||||
((select t11.i from t1 t11) union (select t12.i from t1 t12));
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
@ -5301,7 +5304,7 @@ 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;
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'UNION SELECT 1' at line 1
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '' at line 1
|
||||
SELECT ( SELECT 1 UNION SELECT 1 UNION SELECT 1 );
|
||||
( SELECT 1 UNION SELECT 1 UNION SELECT 1 )
|
||||
1
|
||||
@ -5331,7 +5334,8 @@ SELECT * FROM t1 WHERE a IN ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) );
|
||||
a
|
||||
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 MariaDB server version for the right syntax to use near 'UNION SELECT 1 )' at line 1
|
||||
a
|
||||
1
|
||||
SELECT * FROM t1 WHERE a = ALL ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 );
|
||||
a
|
||||
1
|
||||
@ -5339,7 +5343,8 @@ 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 );
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'UNION SELECT 1 )' at line 1
|
||||
a
|
||||
1
|
||||
SELECT * FROM t1 WHERE a = ( SELECT 1 UNION SELECT 1 UNION SELECT 1 );
|
||||
a
|
||||
1
|
||||
|
@ -3742,8 +3742,11 @@ WHERE NOT EXISTS (((SELECT i FROM t1) UNION (SELECT i FROM t1)));
|
||||
i
|
||||
explain select ((select t11.i from t1 t11) union (select t12.i from t1 t12))
|
||||
from t1;
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'union (select t12.i from t1 t12))
|
||||
from t1' at line 1
|
||||
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 <union2,3> ALL NULL NULL NULL NULL NULL
|
||||
explain select * from t1 where not exists
|
||||
((select t11.i from t1 t11) union (select t12.i from t1 t12));
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
@ -5311,7 +5314,7 @@ 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;
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'UNION SELECT 1' at line 1
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '' at line 1
|
||||
SELECT ( SELECT 1 UNION SELECT 1 UNION SELECT 1 );
|
||||
( SELECT 1 UNION SELECT 1 UNION SELECT 1 )
|
||||
1
|
||||
@ -5341,7 +5344,8 @@ SELECT * FROM t1 WHERE a IN ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) );
|
||||
a
|
||||
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 MariaDB server version for the right syntax to use near 'UNION SELECT 1 )' at line 1
|
||||
a
|
||||
1
|
||||
SELECT * FROM t1 WHERE a = ALL ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 );
|
||||
a
|
||||
1
|
||||
@ -5349,7 +5353,8 @@ 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 );
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'UNION SELECT 1 )' at line 1
|
||||
a
|
||||
1
|
||||
SELECT * FROM t1 WHERE a = ( SELECT 1 UNION SELECT 1 UNION SELECT 1 );
|
||||
a
|
||||
1
|
||||
|
@ -3735,8 +3735,11 @@ WHERE NOT EXISTS (((SELECT i FROM t1) UNION (SELECT i FROM t1)));
|
||||
i
|
||||
explain select ((select t11.i from t1 t11) union (select t12.i from t1 t12))
|
||||
from t1;
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'union (select t12.i from t1 t12))
|
||||
from t1' at line 1
|
||||
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 <union2,3> ALL NULL NULL NULL NULL NULL
|
||||
explain select * from t1 where not exists
|
||||
((select t11.i from t1 t11) union (select t12.i from t1 t12));
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
@ -5301,7 +5304,7 @@ 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;
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'UNION SELECT 1' at line 1
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '' at line 1
|
||||
SELECT ( SELECT 1 UNION SELECT 1 UNION SELECT 1 );
|
||||
( SELECT 1 UNION SELECT 1 UNION SELECT 1 )
|
||||
1
|
||||
@ -5331,7 +5334,8 @@ SELECT * FROM t1 WHERE a IN ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) );
|
||||
a
|
||||
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 MariaDB server version for the right syntax to use near 'UNION SELECT 1 )' at line 1
|
||||
a
|
||||
1
|
||||
SELECT * FROM t1 WHERE a = ALL ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 );
|
||||
a
|
||||
1
|
||||
@ -5339,7 +5343,8 @@ 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 );
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'UNION SELECT 1 )' at line 1
|
||||
a
|
||||
1
|
||||
SELECT * FROM t1 WHERE a = ( SELECT 1 UNION SELECT 1 UNION SELECT 1 );
|
||||
a
|
||||
1
|
||||
|
@ -122,7 +122,8 @@ void Item_subselect::init(st_select_lex *select_lex,
|
||||
parsing_place= (outer_select->in_sum_expr ?
|
||||
NO_MATTER :
|
||||
outer_select->parsing_place);
|
||||
if (unit->is_unit_op() && unit->first_select()->next_select())
|
||||
if (unit->is_unit_op() &&
|
||||
(unit->first_select()->next_select() or unit->fake_select_lex))
|
||||
engine= new subselect_union_engine(unit, result, this);
|
||||
else
|
||||
engine= new subselect_single_select_engine(select_lex, result, this);
|
||||
|
305
sql/sql_lex.cc
305
sql/sql_lex.cc
@ -1444,7 +1444,7 @@ int Lex_input_stream::lex_token(YYSTYPE *yylval, THD *thd)
|
||||
return LEFT_PAREN_LIKE;
|
||||
if (token == WITH)
|
||||
return LEFT_PAREN_WITH;
|
||||
if (token != left_paren && token != SELECT_SYM)
|
||||
if (token != left_paren && token != SELECT_SYM && token != VALUES)
|
||||
return LEFT_PAREN_ALT;
|
||||
else
|
||||
return left_paren;
|
||||
@ -5339,10 +5339,9 @@ LEX::create_unit(SELECT_LEX *first_sel)
|
||||
SELECT_LEX_UNIT *unit;
|
||||
DBUG_ENTER("LEX::create_unit");
|
||||
|
||||
if (first_sel->master_unit())
|
||||
DBUG_RETURN(first_sel->master_unit());
|
||||
unit = first_sel->master_unit();
|
||||
|
||||
if (!(unit= alloc_unit()))
|
||||
if (!unit && !(unit= alloc_unit()))
|
||||
DBUG_RETURN(NULL);
|
||||
|
||||
unit->register_select_chain(first_sel);
|
||||
@ -9001,7 +9000,8 @@ bool LEX::insert_select_hack(SELECT_LEX *sel)
|
||||
builtin_select.link_prev= NULL; // indicator of removal
|
||||
}
|
||||
|
||||
set_main_unit(sel->master_unit());
|
||||
if (set_main_unit(sel->master_unit()))
|
||||
return true;
|
||||
|
||||
DBUG_ASSERT(builtin_select.table_list.elements == 1);
|
||||
TABLE_LIST *insert_table= builtin_select.table_list.first;
|
||||
@ -9045,9 +9045,10 @@ bool LEX::insert_select_hack(SELECT_LEX *sel)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/**
|
||||
Create an Item_singlerow_subselect for a query expression.
|
||||
*/
|
||||
|
||||
Item *LEX::create_item_query_expression(THD *thd,
|
||||
st_select_lex_unit *unit)
|
||||
{
|
||||
@ -9062,118 +9063,17 @@ Item *LEX::create_item_query_expression(THD *thd,
|
||||
SELECT_LEX *curr_sel= select_stack_head();
|
||||
DBUG_ASSERT(current_select == curr_sel);
|
||||
if (!curr_sel)
|
||||
{
|
||||
curr_sel= &builtin_select;
|
||||
curr_sel->register_unit(unit, &curr_sel->context);
|
||||
curr_sel->add_statistics(unit);
|
||||
curr_sel->register_unit(unit, &curr_sel->context);
|
||||
curr_sel->add_statistics(unit);
|
||||
}
|
||||
|
||||
return new (thd->mem_root)
|
||||
Item_singlerow_subselect(thd, unit->first_select());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Process unit parsed in brackets
|
||||
*/
|
||||
|
||||
bool LEX::parsed_unit_in_brackets(SELECT_LEX_UNIT *unit)
|
||||
{
|
||||
SELECT_LEX *first_in_nest= unit->pre_last_parse->next_select()->first_nested;
|
||||
if (first_in_nest->first_nested != first_in_nest)
|
||||
{
|
||||
/* There is a priority jump starting from first_in_nest */
|
||||
if (create_priority_nest(first_in_nest) == NULL)
|
||||
return true;
|
||||
unit->fix_distinct();
|
||||
}
|
||||
push_select(unit->fake_select_lex);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Process tail of unit parsed in brackets
|
||||
*/
|
||||
SELECT_LEX *LEX::parsed_unit_in_brackets_tail(SELECT_LEX_UNIT *unit,
|
||||
Lex_order_limit_lock * l)
|
||||
{
|
||||
pop_select();
|
||||
if (l)
|
||||
{
|
||||
(l)->set_to(unit->fake_select_lex);
|
||||
}
|
||||
return unit->first_select();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Process select parsed in brackets
|
||||
*/
|
||||
|
||||
SELECT_LEX *LEX::parsed_select(SELECT_LEX *sel, Lex_order_limit_lock * l)
|
||||
{
|
||||
pop_select();
|
||||
if (l)
|
||||
{
|
||||
if (sel->next_select())
|
||||
{
|
||||
SELECT_LEX_UNIT *unit= sel->master_unit();
|
||||
if (!unit)
|
||||
unit= create_unit(sel);
|
||||
if (!unit)
|
||||
return NULL;
|
||||
if (!unit->fake_select_lex->is_set_query_expr_tail)
|
||||
l->set_to(unit->fake_select_lex);
|
||||
else
|
||||
{
|
||||
if (!l->order_list && !unit->fake_select_lex->explicit_limit)
|
||||
{
|
||||
sel= unit->fake_select_lex;
|
||||
l->order_list= &sel->order_list;
|
||||
}
|
||||
else
|
||||
sel= wrap_unit_into_derived(unit);
|
||||
if (!sel)
|
||||
return NULL;
|
||||
l->set_to(sel);
|
||||
}
|
||||
}
|
||||
else if (!sel->is_set_query_expr_tail)
|
||||
{
|
||||
l->set_to(sel);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!l->order_list && !sel->explicit_limit)
|
||||
l->order_list= &sel->order_list;
|
||||
else
|
||||
{
|
||||
SELECT_LEX_UNIT *unit= create_unit(sel);
|
||||
if (!unit)
|
||||
return NULL;
|
||||
sel= wrap_unit_into_derived(unit);
|
||||
}
|
||||
if (!sel)
|
||||
return NULL;
|
||||
l->set_to(sel);
|
||||
}
|
||||
}
|
||||
return sel;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Process select parsed in brackets
|
||||
*/
|
||||
|
||||
SELECT_LEX *LEX::parsed_select_in_brackets(SELECT_LEX *sel,
|
||||
Lex_order_limit_lock * l)
|
||||
{
|
||||
sel->braces= TRUE;
|
||||
return parsed_select(sel, l);
|
||||
}
|
||||
|
||||
|
||||
SELECT_LEX_UNIT *LEX::parsed_select_expr_start(SELECT_LEX *s1, SELECT_LEX *s2,
|
||||
enum sub_select_type unit_type,
|
||||
bool distinct)
|
||||
@ -9204,6 +9104,7 @@ SELECT_LEX_UNIT *LEX::parsed_select_expr_start(SELECT_LEX *s1, SELECT_LEX *s2,
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
res->pre_last_parse= sel1;
|
||||
push_select(res->fake_select_lex);
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -9216,12 +9117,6 @@ SELECT_LEX_UNIT *LEX::parsed_select_expr_cont(SELECT_LEX_UNIT *unit,
|
||||
SELECT_LEX *sel1;
|
||||
if (!s2->next_select())
|
||||
sel1= s2;
|
||||
else
|
||||
{
|
||||
sel1= wrap_unit_into_derived(s2->master_unit());
|
||||
if (!sel1)
|
||||
return NULL;
|
||||
}
|
||||
SELECT_LEX *last= unit->pre_last_parse->next_select();
|
||||
|
||||
int cmp= oracle? 0 : cmp_unit_op(unit_type, last->get_linkage());
|
||||
@ -9253,41 +9148,73 @@ SELECT_LEX_UNIT *LEX::parsed_select_expr_cont(SELECT_LEX_UNIT *unit,
|
||||
return unit;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Process parsed select in body
|
||||
Add primary expression as the next term in a given query expression body
|
||||
pruducing a new query expression body
|
||||
*/
|
||||
|
||||
SELECT_LEX_UNIT *LEX::parsed_body_select(SELECT_LEX *sel,
|
||||
Lex_order_limit_lock * l)
|
||||
SELECT_LEX_UNIT *
|
||||
LEX::add_primary_to_query_expression_body(SELECT_LEX_UNIT *unit,
|
||||
SELECT_LEX *sel,
|
||||
enum sub_select_type unit_type,
|
||||
bool distinct,
|
||||
bool oracle)
|
||||
{
|
||||
if (sel->braces && l && l->lock.defined_lock)
|
||||
SELECT_LEX *sel2= sel;
|
||||
if (sel->master_unit() && sel->master_unit()->first_select()->next_select())
|
||||
{
|
||||
my_error(ER_WRONG_USAGE, MYF(0), "lock options",
|
||||
"SELECT in brackets");
|
||||
return NULL;
|
||||
}
|
||||
if (!(sel= parsed_select(sel, l)))
|
||||
return NULL;
|
||||
|
||||
SELECT_LEX_UNIT *res= create_unit(sel);
|
||||
if (res && sel->tvc && sel->order_list.elements)
|
||||
{
|
||||
if (res->add_fake_select_lex(thd))
|
||||
sel2= wrap_unit_into_derived(sel->master_unit());
|
||||
if (!sel2)
|
||||
return NULL;
|
||||
SELECT_LEX *fake= res->fake_select_lex;
|
||||
fake->order_list= sel->order_list;
|
||||
fake->explicit_limit= sel->explicit_limit;
|
||||
fake->select_limit= sel->select_limit;
|
||||
fake->offset_limit= sel->offset_limit;
|
||||
}
|
||||
return res;
|
||||
SELECT_LEX *sel1= unit->first_select();
|
||||
if (!sel1->next_select())
|
||||
unit= parsed_select_expr_start(sel1, sel2, unit_type, distinct);
|
||||
else
|
||||
unit= parsed_select_expr_cont(unit, sel2, unit_type, distinct, oracle);
|
||||
return unit;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Process parsed unit in body
|
||||
Add query primary to a parenthesized query primary
|
||||
pruducing a new query expression body
|
||||
*/
|
||||
|
||||
bool LEX::parsed_body_unit(SELECT_LEX_UNIT *unit)
|
||||
SELECT_LEX_UNIT *
|
||||
LEX::add_primary_to_query_expression_body_ext_parens(
|
||||
SELECT_LEX_UNIT *unit,
|
||||
SELECT_LEX *sel,
|
||||
enum sub_select_type unit_type,
|
||||
bool distinct)
|
||||
{
|
||||
SELECT_LEX *sel1= unit->first_select();
|
||||
if (unit->first_select()->next_select())
|
||||
{
|
||||
sel1= wrap_unit_into_derived(unit);
|
||||
if (!sel1)
|
||||
return NULL;
|
||||
if (!create_unit(sel1))
|
||||
return NULL;
|
||||
}
|
||||
SELECT_LEX *sel2= sel;
|
||||
if (sel->master_unit() && sel->master_unit()->first_select()->next_select())
|
||||
{
|
||||
sel2= wrap_unit_into_derived(sel->master_unit());
|
||||
if (!sel2)
|
||||
return NULL;
|
||||
}
|
||||
unit= parsed_select_expr_start(sel1, sel2, unit_type, distinct);
|
||||
return unit;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Process multi-operand query expression body
|
||||
*/
|
||||
|
||||
bool LEX::parsed_multi_operand_query_expression_body(SELECT_LEX_UNIT *unit)
|
||||
{
|
||||
SELECT_LEX *first_in_nest=
|
||||
unit->pre_last_parse->next_select()->first_nested;
|
||||
@ -9298,27 +9225,60 @@ bool LEX::parsed_body_unit(SELECT_LEX_UNIT *unit)
|
||||
return true;
|
||||
unit->fix_distinct();
|
||||
}
|
||||
push_select(unit->fake_select_lex);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
Process parsed tail of unit in body
|
||||
|
||||
TODO: make processing for double tail case
|
||||
/**
|
||||
Add non-empty tail to a query expression body
|
||||
*/
|
||||
|
||||
SELECT_LEX_UNIT *LEX::parsed_body_unit_tail(SELECT_LEX_UNIT *unit,
|
||||
Lex_order_limit_lock * l)
|
||||
SELECT_LEX_UNIT *LEX::add_tail_to_query_expression_body(SELECT_LEX_UNIT *unit,
|
||||
Lex_order_limit_lock *l)
|
||||
{
|
||||
DBUG_ASSERT(l != NULL);
|
||||
pop_select();
|
||||
if (l)
|
||||
{
|
||||
(l)->set_to(unit->fake_select_lex);
|
||||
}
|
||||
SELECT_LEX *sel= unit->first_select()->next_select() ? unit->fake_select_lex :
|
||||
unit->first_select();
|
||||
l->set_to(sel);
|
||||
return unit;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Add non-empty tail to a parenthesized query primary
|
||||
*/
|
||||
|
||||
SELECT_LEX_UNIT *
|
||||
LEX::add_tail_to_query_expression_body_ext_parens(SELECT_LEX_UNIT *unit,
|
||||
Lex_order_limit_lock *l)
|
||||
{
|
||||
SELECT_LEX *sel= unit->first_select()->next_select() ? unit->fake_select_lex :
|
||||
unit->first_select();
|
||||
|
||||
DBUG_ASSERT(l != NULL);
|
||||
|
||||
pop_select();
|
||||
if (sel->is_set_query_expr_tail)
|
||||
{
|
||||
if (!l->order_list && !sel->explicit_limit)
|
||||
l->order_list= &sel->order_list;
|
||||
else
|
||||
{
|
||||
if (!unit)
|
||||
return NULL;
|
||||
sel= wrap_unit_into_derived(unit);
|
||||
if (!sel)
|
||||
return NULL;
|
||||
if (!create_unit(sel))
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
l->set_to(sel);
|
||||
return sel->master_unit();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Process subselect parsing
|
||||
*/
|
||||
@ -9345,7 +9305,6 @@ SELECT_LEX *LEX::parsed_subselect(SELECT_LEX_UNIT *unit)
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Process INSERT-like select
|
||||
*/
|
||||
@ -9400,40 +9359,8 @@ SELECT_LEX *LEX::parsed_TVC_end()
|
||||
}
|
||||
|
||||
|
||||
TABLE_LIST *LEX::parsed_derived_select(SELECT_LEX *sel, int for_system_time,
|
||||
LEX_CSTRING *alias)
|
||||
{
|
||||
TABLE_LIST *res;
|
||||
derived_tables|= DERIVED_SUBQUERY;
|
||||
sel->set_linkage(DERIVED_TABLE_TYPE);
|
||||
sel->braces= FALSE;
|
||||
// Add the subtree of subquery to the current SELECT_LEX
|
||||
SELECT_LEX *curr_sel= select_stack_head();
|
||||
DBUG_ASSERT(current_select == curr_sel);
|
||||
SELECT_LEX_UNIT *unit= sel->master_unit();
|
||||
if (!unit)
|
||||
{
|
||||
unit= create_unit(sel);
|
||||
if (!unit)
|
||||
return NULL;
|
||||
}
|
||||
curr_sel->register_unit(unit, &curr_sel->context);
|
||||
curr_sel->add_statistics(unit);
|
||||
|
||||
Table_ident *ti= new (thd->mem_root) Table_ident(unit);
|
||||
if (ti == NULL)
|
||||
return NULL;
|
||||
if (!(res= curr_sel->add_table_to_list(thd, ti, alias, 0,
|
||||
TL_READ, MDL_SHARED_READ)))
|
||||
return NULL;
|
||||
if (for_system_time)
|
||||
{
|
||||
res->vers_conditions= vers_conditions;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
TABLE_LIST *LEX::parsed_derived_unit(SELECT_LEX_UNIT *unit,
|
||||
TABLE_LIST *LEX::parsed_derived_table(SELECT_LEX_UNIT *unit,
|
||||
int for_system_time,
|
||||
LEX_CSTRING *alias)
|
||||
{
|
||||
@ -9444,8 +9371,6 @@ TABLE_LIST *LEX::parsed_derived_unit(SELECT_LEX_UNIT *unit,
|
||||
// Add the subtree of subquery to the current SELECT_LEX
|
||||
SELECT_LEX *curr_sel= select_stack_head();
|
||||
DBUG_ASSERT(current_select == curr_sel);
|
||||
curr_sel->register_unit(unit, &curr_sel->context);
|
||||
curr_sel->add_statistics(unit);
|
||||
|
||||
Table_ident *ti= new (thd->mem_root) Table_ident(unit);
|
||||
if (ti == NULL)
|
||||
@ -9463,7 +9388,8 @@ TABLE_LIST *LEX::parsed_derived_unit(SELECT_LEX_UNIT *unit,
|
||||
bool LEX::parsed_create_view(SELECT_LEX_UNIT *unit, int check)
|
||||
{
|
||||
SQL_I_List<TABLE_LIST> *save= &first_select_lex()->table_list;
|
||||
set_main_unit(unit);
|
||||
if (set_main_unit(unit))
|
||||
return true;
|
||||
if (check_main_unit_semantics())
|
||||
return true;
|
||||
first_select_lex()->table_list.push_front(save);
|
||||
@ -9486,7 +9412,8 @@ bool LEX::select_finalize(st_select_lex_unit *expr)
|
||||
sql_command= SQLCOM_SELECT;
|
||||
selects_allow_into= TRUE;
|
||||
selects_allow_procedure= TRUE;
|
||||
set_main_unit(expr);
|
||||
if (set_main_unit(expr))
|
||||
return true;
|
||||
return check_main_unit_semantics();
|
||||
}
|
||||
|
||||
@ -9497,6 +9424,7 @@ bool LEX::select_finalize(st_select_lex_unit *expr, Lex_select_lock l)
|
||||
select_finalize(expr);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
"IN" and "EXISTS" subselect can appear in two statement types:
|
||||
|
||||
@ -9529,7 +9457,6 @@ void LEX::relink_hack(st_select_lex *select_lex)
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool SELECT_LEX_UNIT::set_lock_to_the_last_select(Lex_select_lock l)
|
||||
{
|
||||
if (l.defined_lock)
|
||||
|
@ -4414,9 +4414,6 @@ public:
|
||||
insert_list= 0;
|
||||
}
|
||||
|
||||
bool make_select_in_brackets(SELECT_LEX* dummy_select,
|
||||
SELECT_LEX *nselect, bool automatic);
|
||||
|
||||
SELECT_LEX_UNIT *alloc_unit();
|
||||
SELECT_LEX *alloc_select(bool is_select);
|
||||
SELECT_LEX_UNIT *create_unit(SELECT_LEX*);
|
||||
@ -4426,7 +4423,7 @@ public:
|
||||
bool insert_select_hack(SELECT_LEX *sel);
|
||||
SELECT_LEX *create_priority_nest(SELECT_LEX *first_in_nest);
|
||||
|
||||
void set_main_unit(st_select_lex_unit *u)
|
||||
bool set_main_unit(st_select_lex_unit *u)
|
||||
{
|
||||
unit.options= u->options;
|
||||
unit.uncacheable= u->uncacheable;
|
||||
@ -4436,16 +4433,10 @@ public:
|
||||
unit.union_distinct= u->union_distinct;
|
||||
unit.set_with_clause(u->with_clause);
|
||||
builtin_select.exclude_from_global();
|
||||
return false;
|
||||
}
|
||||
bool check_main_unit_semantics();
|
||||
|
||||
// reaction on different parsed parts (bodies are in sql_yacc.yy)
|
||||
bool parsed_unit_in_brackets(SELECT_LEX_UNIT *unit);
|
||||
SELECT_LEX *parsed_select(SELECT_LEX *sel, Lex_order_limit_lock * l);
|
||||
SELECT_LEX *parsed_unit_in_brackets_tail(SELECT_LEX_UNIT *unit,
|
||||
Lex_order_limit_lock * l);
|
||||
SELECT_LEX *parsed_select_in_brackets(SELECT_LEX *sel,
|
||||
Lex_order_limit_lock * l);
|
||||
SELECT_LEX_UNIT *parsed_select_expr_start(SELECT_LEX *s1, SELECT_LEX *s2,
|
||||
enum sub_select_type unit_type,
|
||||
bool distinct);
|
||||
@ -4453,20 +4444,35 @@ public:
|
||||
SELECT_LEX *s2,
|
||||
enum sub_select_type unit_type,
|
||||
bool distinct, bool oracle);
|
||||
SELECT_LEX_UNIT *parsed_body_select(SELECT_LEX *sel,
|
||||
Lex_order_limit_lock * l);
|
||||
bool parsed_body_unit(SELECT_LEX_UNIT *unit);
|
||||
SELECT_LEX_UNIT *parsed_body_unit_tail(SELECT_LEX_UNIT *unit,
|
||||
Lex_order_limit_lock * l);
|
||||
bool parsed_multi_operand_query_expression_body(SELECT_LEX_UNIT *unit);
|
||||
SELECT_LEX_UNIT *add_tail_to_query_expression_body(SELECT_LEX_UNIT *unit,
|
||||
Lex_order_limit_lock *l);
|
||||
SELECT_LEX_UNIT *
|
||||
add_tail_to_query_expression_body_ext_parens(SELECT_LEX_UNIT *unit,
|
||||
Lex_order_limit_lock *l);
|
||||
SELECT_LEX_UNIT *parsed_body_ext_parens_primary(SELECT_LEX_UNIT *unit,
|
||||
SELECT_LEX *primary,
|
||||
enum sub_select_type unit_type,
|
||||
bool distinct);
|
||||
SELECT_LEX_UNIT *
|
||||
add_primary_to_query_expression_body(SELECT_LEX_UNIT *unit,
|
||||
SELECT_LEX *sel,
|
||||
enum sub_select_type unit_type,
|
||||
bool distinct,
|
||||
bool oracle);
|
||||
SELECT_LEX_UNIT *
|
||||
add_primary_to_query_expression_body_ext_parens(
|
||||
SELECT_LEX_UNIT *unit,
|
||||
SELECT_LEX *sel,
|
||||
enum sub_select_type unit_type,
|
||||
bool distinct);
|
||||
SELECT_LEX *parsed_subselect(SELECT_LEX_UNIT *unit);
|
||||
bool parsed_insert_select(SELECT_LEX *firs_select);
|
||||
bool parsed_TVC_start();
|
||||
SELECT_LEX *parsed_TVC_end();
|
||||
TABLE_LIST *parsed_derived_select(SELECT_LEX *sel, int for_system_time,
|
||||
LEX_CSTRING *alias);
|
||||
TABLE_LIST *parsed_derived_unit(SELECT_LEX_UNIT *unit,
|
||||
int for_system_time,
|
||||
LEX_CSTRING *alias);
|
||||
TABLE_LIST *parsed_derived_table(SELECT_LEX_UNIT *unit,
|
||||
int for_system_time,
|
||||
LEX_CSTRING *alias);
|
||||
bool parsed_create_view(SELECT_LEX_UNIT *unit, int check);
|
||||
bool select_finalize(st_select_lex_unit *expr);
|
||||
bool select_finalize(st_select_lex_unit *expr, Lex_select_lock l);
|
||||
|
@ -11261,7 +11261,7 @@ bool Sql_cmd_create_table_like::execute(THD *thd)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (select_lex->item_list.elements) // With select
|
||||
if (select_lex->item_list.elements || select_lex->tvc) // With select or TVC
|
||||
{
|
||||
select_result *result;
|
||||
|
||||
|
@ -599,8 +599,8 @@ static bool create_tvc_name(THD *thd, st_select_lex *parent_select,
|
||||
|
||||
bool table_value_constr::to_be_wrapped_as_with_tail()
|
||||
{
|
||||
return select_lex->master_unit()->first_select()->next_select() &&
|
||||
select_lex->order_list.elements && select_lex->explicit_limit;
|
||||
return select_lex->master_unit()->first_select()->next_select() &&
|
||||
select_lex->order_list.elements && select_lex->explicit_limit;
|
||||
}
|
||||
|
||||
|
||||
|
@ -831,8 +831,8 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
|
||||
bool is_union_select;
|
||||
bool have_except= FALSE, have_intersect= FALSE;
|
||||
bool instantiate_tmp_table= false;
|
||||
bool single_tvc= !first_sl->next_select() && first_sl->tvc &&
|
||||
!fake_select_lex;
|
||||
bool single_tvc= !first_sl->next_select() && first_sl->tvc;
|
||||
bool single_tvc_wo_order= single_tvc && !first_sl->order_list.elements;
|
||||
DBUG_ENTER("st_select_lex_unit::prepare");
|
||||
DBUG_ASSERT(thd == current_thd);
|
||||
|
||||
@ -924,8 +924,9 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
|
||||
|
||||
if (is_union_select || is_recursive)
|
||||
{
|
||||
if ((is_unit_op() && !union_needs_tmp_table() &&
|
||||
!have_except && !have_intersect) || single_tvc)
|
||||
if ((single_tvc_wo_order && !fake_select_lex) ||
|
||||
(is_unit_op() && !union_needs_tmp_table() &&
|
||||
!have_except && !have_intersect && !single_tvc))
|
||||
{
|
||||
SELECT_LEX *last= first_select();
|
||||
while (last->next_select())
|
||||
@ -940,7 +941,7 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
|
||||
else
|
||||
{
|
||||
if (!is_recursive)
|
||||
union_result= new (thd->mem_root) select_unit(thd);
|
||||
union_result= new (thd->mem_root) select_unit(thd);
|
||||
else
|
||||
{
|
||||
with_element->rec_result=
|
||||
@ -986,17 +987,40 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
|
||||
if (sl->tvc && sl->order_list.elements &&
|
||||
!sl->tvc->to_be_wrapped_as_with_tail())
|
||||
{
|
||||
SELECT_LEX_UNIT *unit= sl->master_unit();
|
||||
if (thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW)
|
||||
{
|
||||
sl->master_unit()->fake_select_lex= 0;
|
||||
sl->master_unit()->saved_fake_select_lex= 0;
|
||||
unit->fake_select_lex= 0;
|
||||
unit->saved_fake_select_lex= 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sl->order_list.empty();
|
||||
sl->explicit_limit= 0;
|
||||
sl->select_limit= 0;
|
||||
sl->offset_limit= 0;
|
||||
if (!unit->first_select()->next_select())
|
||||
{
|
||||
if (!unit->fake_select_lex)
|
||||
{
|
||||
Query_arena *arena, backup_arena;
|
||||
arena= thd->activate_stmt_arena_if_needed(&backup_arena);
|
||||
bool rc= unit->add_fake_select_lex(thd);
|
||||
if (arena)
|
||||
thd->restore_active_arena(arena, &backup_arena);
|
||||
if (rc)
|
||||
goto err;
|
||||
}
|
||||
SELECT_LEX *fake= unit->fake_select_lex;
|
||||
fake->order_list= sl->order_list;
|
||||
fake->explicit_limit= sl->explicit_limit;
|
||||
fake->select_limit= sl->select_limit;
|
||||
fake->offset_limit= sl->offset_limit;
|
||||
sl->order_list.empty();
|
||||
sl->explicit_limit= 0;
|
||||
sl->select_limit= 0;
|
||||
sl->offset_limit= 0;
|
||||
if (describe)
|
||||
fake->options|= SELECT_DESCRIBE;
|
||||
}
|
||||
else if (!sl->explicit_limit)
|
||||
sl->order_list.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1021,7 +1045,7 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
|
||||
goto err;
|
||||
}
|
||||
else if (sl->tvc->prepare(thd, sl, tmp_result, this))
|
||||
goto err;
|
||||
goto err;
|
||||
}
|
||||
else if (prepare_join(thd, sl, tmp_result, additional_options,
|
||||
is_union_select))
|
||||
|
479
sql/sql_yacc.yy
479
sql/sql_yacc.yy
@ -817,10 +817,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
|
||||
%parse-param { THD *thd }
|
||||
%lex-param { THD *thd }
|
||||
/*
|
||||
Currently there are 47 shift/reduce conflicts.
|
||||
Currently there are 38 shift/reduce conflicts.
|
||||
We should not introduce new conflicts any more.
|
||||
*/
|
||||
%expect 47
|
||||
%expect 38
|
||||
|
||||
/*
|
||||
Comments for TOKENS.
|
||||
@ -1638,6 +1638,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
|
||||
%left MYSQL_CONCAT_SYM
|
||||
%left NEG '~' NOT2_SYM BINARY
|
||||
%left COLLATE_SYM
|
||||
%left SUBQUERY_AS_EXPR
|
||||
|
||||
/*
|
||||
Tokens that can change their meaning from identifier to something else
|
||||
@ -1728,7 +1729,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
|
||||
ALTER TABLE t1 ADD SYSTEM VERSIONING;
|
||||
*/
|
||||
%left PREC_BELOW_CONTRACTION_TOKEN2
|
||||
%left TEXT_STRING '(' VALUE_SYM VERSIONING_SYM
|
||||
%left TEXT_STRING '(' ')' VALUE_SYM VERSIONING_SYM
|
||||
%left EMPTY_FROM_CLAUSE
|
||||
%right INTO
|
||||
|
||||
%type <lex_str>
|
||||
DECIMAL_NUM FLOAT_NUM NUM LONG_NUM
|
||||
@ -1991,16 +1994,18 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
|
||||
query_specification
|
||||
table_value_constructor
|
||||
simple_table
|
||||
query_simple
|
||||
query_primary
|
||||
query_primary_parens
|
||||
subquery
|
||||
select_into_query_specification
|
||||
|
||||
|
||||
%type <select_lex_unit>
|
||||
query_specification_start
|
||||
query_expression_body
|
||||
query_expression
|
||||
query_expression_unit
|
||||
query_expression_no_with_clause
|
||||
query_expression_body_ext
|
||||
query_expression_body_ext_parens
|
||||
query_expression_body
|
||||
query_specification_start
|
||||
|
||||
%type <boolfunc2creator> comp_op
|
||||
|
||||
@ -2025,7 +2030,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
|
||||
|
||||
%type <order_limit_lock>
|
||||
query_expression_tail
|
||||
opt_query_expression_tail
|
||||
order_or_limit
|
||||
order_limit_lock
|
||||
opt_order_limit_lock
|
||||
|
||||
%type <select_order> opt_order_clause order_clause order_list
|
||||
@ -2178,7 +2185,7 @@ END_OF_INPUT
|
||||
THEN_SYM WHEN_SYM DIV_SYM MOD_SYM OR2_SYM AND_AND_SYM DELETE_SYM
|
||||
MYSQL_CONCAT_SYM ORACLE_CONCAT_SYM
|
||||
|
||||
%type <with_clause> opt_with_clause with_clause
|
||||
%type <with_clause> with_clause
|
||||
|
||||
%type <lex_str_ptr> query_name
|
||||
|
||||
@ -5265,7 +5272,7 @@ create_select_query_expression:
|
||||
if (Lex->parsed_insert_select($1->first_select()))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| LEFT_PAREN_WITH with_clause query_expression_body ')'
|
||||
| LEFT_PAREN_WITH with_clause query_expression_no_with_clause ')'
|
||||
{
|
||||
SELECT_LEX *first_select= $3->first_select();
|
||||
$3->set_with_clause($2);
|
||||
@ -6773,12 +6780,7 @@ parse_vcol_expr:
|
||||
;
|
||||
|
||||
parenthesized_expr:
|
||||
query_expression
|
||||
{
|
||||
if (!($$= Lex->create_item_query_expression(thd, $1)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| expr
|
||||
expr
|
||||
| expr ',' expr_list
|
||||
{
|
||||
$3->push_front($1, thd->mem_root);
|
||||
@ -6797,6 +6799,16 @@ virtual_column_func:
|
||||
MYSQL_YYABORT;
|
||||
$$= v;
|
||||
}
|
||||
| subquery
|
||||
{
|
||||
Item *item;
|
||||
if (!(item= new (thd->mem_root) Item_singlerow_subselect(thd, $1)))
|
||||
MYSQL_YYABORT;
|
||||
Virtual_column_info *v= add_virtual_expression(thd, item);
|
||||
if (unlikely(!v))
|
||||
MYSQL_YYABORT;
|
||||
$$= v;
|
||||
}
|
||||
;
|
||||
|
||||
expr_or_literal: column_default_non_parenthesized_expr | signed_literal ;
|
||||
@ -9152,8 +9164,9 @@ opt_ignore_leaves:
|
||||
Select : retrieve data from table
|
||||
*/
|
||||
|
||||
|
||||
select:
|
||||
query_expression_body
|
||||
query_expression_no_with_clause
|
||||
{
|
||||
if (Lex->push_select($1->fake_select_lex ?
|
||||
$1->fake_select_lex :
|
||||
@ -9163,10 +9176,11 @@ select:
|
||||
opt_procedure_or_into
|
||||
{
|
||||
Lex->pop_select();
|
||||
$1->set_with_clause(NULL);
|
||||
if (Lex->select_finalize($1, $3))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| with_clause query_expression_body
|
||||
| with_clause query_expression_no_with_clause
|
||||
{
|
||||
if (Lex->push_select($2->fake_select_lex ?
|
||||
$2->fake_select_lex :
|
||||
@ -9183,7 +9197,6 @@ select:
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
select_into:
|
||||
select_into_query_specification
|
||||
{
|
||||
@ -9192,14 +9205,15 @@ select_into:
|
||||
}
|
||||
opt_order_limit_lock
|
||||
{
|
||||
st_select_lex_unit *unit;
|
||||
if (!(unit= Lex->parsed_body_select($1, $3)))
|
||||
SELECT_LEX_UNIT *unit;
|
||||
if (!(unit = Lex->create_unit($1)))
|
||||
MYSQL_YYABORT;
|
||||
if ($3)
|
||||
unit= Lex->add_tail_to_query_expression_body(unit, $3);
|
||||
if (Lex->select_finalize(unit))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
;
|
||||
|
||||
}
|
||||
;
|
||||
|
||||
simple_table:
|
||||
query_specification { $$= $1; }
|
||||
@ -9265,94 +9279,193 @@ select_into_query_specification:
|
||||
}
|
||||
;
|
||||
|
||||
opt_from_clause:
|
||||
/* Empty */
|
||||
| from_clause
|
||||
;
|
||||
/**
|
||||
|
||||
The following grammar for query expressions conformant to
|
||||
the latest SQL Standard is supported:
|
||||
|
||||
query_primary:
|
||||
simple_table
|
||||
{ $$= $1; }
|
||||
| query_primary_parens
|
||||
{ $$= $1; }
|
||||
;
|
||||
<query expression> ::=
|
||||
[ <with clause> ] <query expression body>
|
||||
[ <order by clause> ] [ <result offset clause> ] [ <fetch first clause> ]
|
||||
|
||||
query_primary_parens:
|
||||
'(' query_expression_unit
|
||||
{
|
||||
if (Lex->parsed_unit_in_brackets($2))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
query_expression_tail ')'
|
||||
{
|
||||
$$= Lex->parsed_unit_in_brackets_tail($2, $4);
|
||||
}
|
||||
| '(' query_primary
|
||||
{
|
||||
Lex->push_select($2);
|
||||
}
|
||||
query_expression_tail ')'
|
||||
{
|
||||
if (!($$= Lex->parsed_select_in_brackets($2, $4)))
|
||||
YYABORT;
|
||||
}
|
||||
;
|
||||
<with clause> ::=
|
||||
WITH [ RECURSIVE ] <with_list
|
||||
|
||||
query_expression_unit:
|
||||
query_primary
|
||||
unit_type_decl
|
||||
query_primary
|
||||
{
|
||||
if (!($$= Lex->parsed_select_expr_start($1, $3, $2.unit_type,
|
||||
$2.distinct)))
|
||||
YYABORT;
|
||||
}
|
||||
| query_expression_unit
|
||||
unit_type_decl
|
||||
query_primary
|
||||
{
|
||||
if (!($$= Lex->parsed_select_expr_cont($1, $3, $2.unit_type,
|
||||
$2.distinct, FALSE)))
|
||||
YYABORT;
|
||||
}
|
||||
;
|
||||
<with list> ::=
|
||||
<with list element> [ { <comma> <with list element> }... ]
|
||||
|
||||
query_expression_body:
|
||||
query_primary
|
||||
{
|
||||
Lex->push_select($1);
|
||||
}
|
||||
query_expression_tail
|
||||
{
|
||||
if (!($$= Lex->parsed_body_select($1, $3)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| query_expression_unit
|
||||
{
|
||||
if (Lex->parsed_body_unit($1))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
query_expression_tail
|
||||
{
|
||||
if (!($$= Lex->parsed_body_unit_tail($1, $3)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
;
|
||||
<with list element> ::=
|
||||
<query name> [ '(' <with column list> ')' ]
|
||||
AS <table subquery>
|
||||
|
||||
<with column list> ::=
|
||||
<column name list>
|
||||
|
||||
<query expression body> ::
|
||||
<query term>
|
||||
| <query expression body> UNION [ ALL | DISTINCT ] <query term>
|
||||
| <query expression body> EXCEPT [ DISTINCT ] <query term>
|
||||
|
||||
<query term> ::=
|
||||
<query primary>
|
||||
| <query term> INTERSECT [ DISTINCT ] <query primary>
|
||||
|
||||
<query primary> ::=
|
||||
<simple table>
|
||||
| '(' <query expression body>
|
||||
[ <order by clause> ] [ <result offset clause> ] [ <fetch first clause> ]
|
||||
')'
|
||||
|
||||
<simple table>
|
||||
<query specification>
|
||||
| <table value constructor>
|
||||
|
||||
<subquery>
|
||||
'(' <query_expression> ')'
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
query_expression produces the same expressions as
|
||||
<query expression>
|
||||
*/
|
||||
|
||||
query_expression:
|
||||
opt_with_clause
|
||||
query_expression_body
|
||||
query_expression_no_with_clause
|
||||
{
|
||||
if ($1)
|
||||
{
|
||||
$2->set_with_clause($1);
|
||||
$1->attach_to($2->first_select());
|
||||
}
|
||||
$1->set_with_clause(NULL);
|
||||
$$= $1;
|
||||
}
|
||||
| with_clause
|
||||
query_expression_no_with_clause
|
||||
{
|
||||
$2->set_with_clause($1);
|
||||
$1->attach_to($2->first_select());
|
||||
$$= $2;
|
||||
}
|
||||
;
|
||||
|
||||
/*
|
||||
query_expression_no_with_clause produces the same expressions as
|
||||
<query expression> without [ <with clause> ]
|
||||
*/
|
||||
|
||||
query_expression_no_with_clause:
|
||||
query_expression_body_ext { $$= $1; }
|
||||
| query_expression_body_ext_parens { $$= $1; }
|
||||
;
|
||||
|
||||
/*
|
||||
query_expression_body_ext produces the same expressions as
|
||||
<query expression body>
|
||||
[ <order by clause> ] [ <result offset clause> ] [ <fetch first clause> ]
|
||||
| '('... <query expression body>
|
||||
[ <order by clause> ] [ <result offset clause> ] [ <fetch first clause> ]
|
||||
')'...
|
||||
Note: number of ')' must be equal to the number of '(' in the rule above
|
||||
*/
|
||||
|
||||
query_expression_body_ext:
|
||||
query_expression_body
|
||||
{
|
||||
if ($1->first_select()->next_select())
|
||||
{
|
||||
if (Lex->parsed_multi_operand_query_expression_body($1))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
}
|
||||
opt_query_expression_tail
|
||||
{
|
||||
if (!$3)
|
||||
$$= $1;
|
||||
else
|
||||
$$= Lex->add_tail_to_query_expression_body($1, $3);
|
||||
}
|
||||
| query_expression_body_ext_parens
|
||||
{
|
||||
Lex->push_select(!$1->first_select()->next_select() ?
|
||||
$1->first_select() : $1->fake_select_lex);
|
||||
}
|
||||
query_expression_tail
|
||||
{
|
||||
if (!($$= Lex->add_tail_to_query_expression_body_ext_parens($1, $3)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
;
|
||||
|
||||
query_expression_body_ext_parens:
|
||||
'(' query_expression_body_ext_parens ')'
|
||||
{ $$= $2; }
|
||||
| '(' query_expression_body_ext ')'
|
||||
{
|
||||
SELECT_LEX *sel= $2->first_select()->next_select() ?
|
||||
$2->fake_select_lex : $2->first_select();
|
||||
sel->braces= true;
|
||||
$$= $2;
|
||||
}
|
||||
;
|
||||
|
||||
/*
|
||||
query_expression_body produces the same expressions as
|
||||
<query expression body>
|
||||
*/
|
||||
|
||||
query_expression_body:
|
||||
query_simple
|
||||
{
|
||||
Lex->push_select($1);
|
||||
if (!($$= Lex->create_unit($1)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| query_expression_body
|
||||
unit_type_decl
|
||||
{
|
||||
if (!$1->first_select()->next_select())
|
||||
{
|
||||
Lex->pop_select();
|
||||
}
|
||||
}
|
||||
query_primary
|
||||
{
|
||||
if (!($$= Lex->add_primary_to_query_expression_body($1, $4,
|
||||
$2.unit_type,
|
||||
$2.distinct,
|
||||
FALSE)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| query_expression_body_ext_parens
|
||||
unit_type_decl
|
||||
query_primary
|
||||
{
|
||||
if (!($$= Lex->add_primary_to_query_expression_body_ext_parens(
|
||||
$1, $3,
|
||||
$2.unit_type,
|
||||
$2.distinct)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
;
|
||||
|
||||
/*
|
||||
query_primary produces the same expressions as
|
||||
<query primary>
|
||||
*/
|
||||
|
||||
query_primary:
|
||||
query_simple
|
||||
{ $$= $1; }
|
||||
| query_expression_body_ext_parens
|
||||
{ $$= $1->first_select(); }
|
||||
;
|
||||
|
||||
/*
|
||||
query_simple produces the same expressions as
|
||||
<simple table>
|
||||
*/
|
||||
|
||||
query_simple:
|
||||
simple_table { $$= $1;}
|
||||
;
|
||||
|
||||
subselect:
|
||||
query_expression
|
||||
{
|
||||
@ -9361,11 +9474,63 @@ subselect:
|
||||
}
|
||||
;
|
||||
|
||||
/*
|
||||
subquery produces the same expressions as
|
||||
<subquery>
|
||||
|
||||
/**
|
||||
<table expression>, as in the SQL standard.
|
||||
Consider the production rule of the SQL Standard
|
||||
subquery:
|
||||
'(' query_expression')'
|
||||
|
||||
This rule is equivalent to the rule
|
||||
subquery:
|
||||
'(' query_expression_no_with_clause ')'
|
||||
| '(' with_clause query_expression_no_with_clause ')'
|
||||
that in its turn is equivalent to
|
||||
subquery:
|
||||
'(' query_expression_body_ext ')'
|
||||
| query_expression_body_ext_parens
|
||||
| '(' with_clause query_expression_no_with_clause ')'
|
||||
|
||||
The latter can be re-written into
|
||||
subquery:
|
||||
query_expression_body_ext_parens ')'
|
||||
| '(' with_clause query_expression_no_with_clause ')'
|
||||
|
||||
The last rule allows us to resolve properly the shift/reduce conflict
|
||||
when subquery is used in expressions such as in the following queries
|
||||
select (select * from t1 limit 1) + t2.a from t2
|
||||
select * from t1 where t1.a [not] in (select t2.a from t2)
|
||||
|
||||
In the rule below %prec SUBQUERY_AS_EXPR forces the parser to perform a shift
|
||||
operation rather then a reduce operation when ')' is encountered and can be
|
||||
considered as the last symbol a query expression.
|
||||
*/
|
||||
|
||||
subquery:
|
||||
query_expression_body_ext_parens %prec SUBQUERY_AS_EXPR
|
||||
{
|
||||
if (!$1->fake_select_lex)
|
||||
$1->first_select()->braces= false;
|
||||
else
|
||||
$1->fake_select_lex->braces= false;
|
||||
if (!($$= Lex->parsed_subselect($1)))
|
||||
YYABORT;
|
||||
}
|
||||
| '(' with_clause query_expression_no_with_clause ')'
|
||||
{
|
||||
$3->set_with_clause($2);
|
||||
$2->attach_to($3->first_select());
|
||||
if (!($$= Lex->parsed_subselect($3)))
|
||||
YYABORT;
|
||||
}
|
||||
;
|
||||
|
||||
opt_from_clause:
|
||||
/* empty */ %prec EMPTY_FROM_CLAUSE
|
||||
| from_clause
|
||||
;
|
||||
|
||||
from_clause:
|
||||
FROM table_reference_list
|
||||
;
|
||||
@ -9529,6 +9694,7 @@ select_lock_type:
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
opt_select_lock_type:
|
||||
/* empty */
|
||||
{
|
||||
@ -9540,6 +9706,7 @@ opt_select_lock_type:
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
opt_lock_wait_timeout_new:
|
||||
/* empty */
|
||||
{
|
||||
@ -9826,15 +9993,15 @@ bool_pri:
|
||||
;
|
||||
|
||||
predicate:
|
||||
bit_expr IN_SYM '(' subselect ')'
|
||||
bit_expr IN_SYM subquery
|
||||
{
|
||||
$$= new (thd->mem_root) Item_in_subselect(thd, $1, $4);
|
||||
$$= new (thd->mem_root) Item_in_subselect(thd, $1, $3);
|
||||
if (unlikely($$ == NULL))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| bit_expr not IN_SYM '(' subselect ')'
|
||||
| bit_expr not IN_SYM subquery
|
||||
{
|
||||
Item *item= new (thd->mem_root) Item_in_subselect(thd, $1, $5);
|
||||
Item *item= new (thd->mem_root) Item_in_subselect(thd, $1, $4);
|
||||
if (unlikely(item == NULL))
|
||||
MYSQL_YYABORT;
|
||||
$$= negate_expression(thd, item);
|
||||
@ -10353,6 +10520,11 @@ primary_expr:
|
||||
column_default_non_parenthesized_expr
|
||||
| explicit_cursor_attr
|
||||
| '(' parenthesized_expr ')' { $$= $2; }
|
||||
| subquery
|
||||
{
|
||||
if (!($$= Lex->create_item_query_expression(thd, $1->master_unit())))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
;
|
||||
|
||||
string_factor_expr:
|
||||
@ -12151,35 +12323,12 @@ table_primary_ident:
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
/*
|
||||
Represents a flattening of the following rules from the SQL:2003
|
||||
standard. This sub-rule corresponds to the sub-rule
|
||||
<table primary> ::= ... | <derived table> [ AS ] <correlation name>
|
||||
|
||||
<derived table> ::= <table subquery>
|
||||
<table subquery> ::= <subquery>
|
||||
<subquery> ::= <left paren> <query expression> <right paren>
|
||||
<query expression> ::= [ <with clause> ] <query expression body>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
table_primary_derived:
|
||||
query_primary_parens opt_for_system_time_clause table_alias_clause
|
||||
subquery
|
||||
opt_for_system_time_clause table_alias_clause
|
||||
{
|
||||
if (!($$= Lex->parsed_derived_select($1, $2, $3)))
|
||||
YYABORT;
|
||||
}
|
||||
| '('
|
||||
query_expression
|
||||
')' opt_for_system_time_clause table_alias_clause
|
||||
{
|
||||
if (!($$= Lex->parsed_derived_unit($2, $4, $5)))
|
||||
YYABORT;
|
||||
if (!($$= Lex->parsed_derived_table($1->master_unit(), $2, $3)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
;
|
||||
|
||||
@ -12315,7 +12464,6 @@ table_alias:
|
||||
|
||||
opt_table_alias_clause:
|
||||
/* empty */ { $$=0; }
|
||||
|
||||
| table_alias_clause { $$= $1; }
|
||||
;
|
||||
|
||||
@ -12449,7 +12597,7 @@ opt_window_clause:
|
||||
{}
|
||||
| WINDOW_SYM
|
||||
window_def_list
|
||||
{}
|
||||
{}
|
||||
;
|
||||
|
||||
window_def_list:
|
||||
@ -12778,10 +12926,8 @@ delete_limit_clause:
|
||||
| LIMIT limit_option ROWS_SYM EXAMINED_SYM { thd->parse_error(); MYSQL_YYABORT; }
|
||||
;
|
||||
|
||||
opt_order_limit_lock:
|
||||
/* empty */
|
||||
{ $$= NULL; }
|
||||
| order_or_limit
|
||||
order_limit_lock:
|
||||
order_or_limit
|
||||
{
|
||||
$$= $1;
|
||||
$$->lock.empty();
|
||||
@ -12801,32 +12947,45 @@ opt_order_limit_lock:
|
||||
$$->lock= $1;
|
||||
}
|
||||
;
|
||||
|
||||
opt_order_limit_lock:
|
||||
/* empty */
|
||||
{
|
||||
Lex->pop_select();
|
||||
$$= NULL;
|
||||
}
|
||||
| order_limit_lock { $$= $1; }
|
||||
;
|
||||
|
||||
query_expression_tail:
|
||||
order_limit_lock
|
||||
;
|
||||
|
||||
opt_query_expression_tail:
|
||||
opt_order_limit_lock
|
||||
;
|
||||
|
||||
opt_procedure_or_into:
|
||||
/* empty */
|
||||
{
|
||||
$$.empty();
|
||||
}
|
||||
{
|
||||
$$.empty();
|
||||
}
|
||||
| procedure_clause opt_select_lock_type
|
||||
{
|
||||
$$= $2;
|
||||
}
|
||||
{
|
||||
$$= $2;
|
||||
}
|
||||
| into opt_select_lock_type
|
||||
{
|
||||
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
|
||||
ER_WARN_DEPRECATED_SYNTAX,
|
||||
ER_THD(thd, ER_WARN_DEPRECATED_SYNTAX),
|
||||
"<select expression> INTO <destination>;",
|
||||
"'SELECT <select list> INTO <destination>"
|
||||
" FROM...'");
|
||||
$$= $2;
|
||||
}
|
||||
{
|
||||
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
|
||||
ER_WARN_DEPRECATED_SYNTAX,
|
||||
ER_THD(thd, ER_WARN_DEPRECATED_SYNTAX),
|
||||
"<select expression> INTO <destination>;",
|
||||
"'SELECT <select list> INTO <destination>"
|
||||
" FROM...'");
|
||||
$$= $2;
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
order_or_limit:
|
||||
order_clause opt_limit_clause
|
||||
{
|
||||
@ -15215,16 +15374,6 @@ temporal_literal:
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
opt_with_clause:
|
||||
/*empty */ { $$= 0; }
|
||||
| with_clause
|
||||
{
|
||||
$$= $1;
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
with_clause:
|
||||
WITH opt_recursive
|
||||
{
|
||||
|
@ -295,10 +295,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
|
||||
%parse-param { THD *thd }
|
||||
%lex-param { THD *thd }
|
||||
/*
|
||||
Currently there are 50 shift/reduce conflicts.
|
||||
Currently there are 41 shift/reduce conflicts.
|
||||
We should not introduce new conflicts any more.
|
||||
*/
|
||||
%expect 50
|
||||
%expect 41
|
||||
|
||||
/*
|
||||
Comments for TOKENS.
|
||||
@ -1115,6 +1115,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
|
||||
%left '^'
|
||||
%left MYSQL_CONCAT_SYM
|
||||
%left NEG '~' NOT2_SYM BINARY
|
||||
%left SUBQUERY_AS_EXPR
|
||||
%left COLLATE_SYM
|
||||
|
||||
/*
|
||||
@ -1206,7 +1207,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
|
||||
ALTER TABLE t1 ADD SYSTEM VERSIONING;
|
||||
*/
|
||||
%left PREC_BELOW_CONTRACTION_TOKEN2
|
||||
%left TEXT_STRING '(' VALUE_SYM VERSIONING_SYM
|
||||
%left TEXT_STRING '(' ')' VALUE_SYM VERSIONING_SYM
|
||||
%left EMPTY_FROM_CLAUSE
|
||||
%right INTO
|
||||
|
||||
%type <lex_str>
|
||||
DECIMAL_NUM FLOAT_NUM NUM LONG_NUM
|
||||
@ -1478,16 +1481,18 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
|
||||
query_specification
|
||||
table_value_constructor
|
||||
simple_table
|
||||
query_simple
|
||||
query_primary
|
||||
query_primary_parens
|
||||
subquery
|
||||
select_into_query_specification
|
||||
|
||||
|
||||
%type <select_lex_unit>
|
||||
query_specification_start
|
||||
query_expression_body
|
||||
query_expression
|
||||
query_expression_unit
|
||||
query_expression_no_with_clause
|
||||
query_expression_body_ext
|
||||
query_expression_body_ext_parens
|
||||
query_expression_body
|
||||
query_specification_start
|
||||
|
||||
%type <boolfunc2creator> comp_op
|
||||
|
||||
@ -1512,7 +1517,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
|
||||
|
||||
%type <order_limit_lock>
|
||||
query_expression_tail
|
||||
opt_query_expression_tail
|
||||
order_or_limit
|
||||
order_limit_lock
|
||||
opt_order_limit_lock
|
||||
|
||||
%type <select_order> opt_order_clause order_clause order_list
|
||||
@ -1681,7 +1688,7 @@ END_OF_INPUT
|
||||
THEN_SYM WHEN_SYM DIV_SYM MOD_SYM OR2_SYM AND_AND_SYM DELETE_SYM
|
||||
MYSQL_CONCAT_SYM ORACLE_CONCAT_SYM
|
||||
|
||||
%type <with_clause> opt_with_clause with_clause
|
||||
%type <with_clause> with_clause
|
||||
|
||||
%type <lex_str_ptr> query_name
|
||||
|
||||
@ -5273,7 +5280,7 @@ create_select_query_expression:
|
||||
if (Lex->parsed_insert_select($1->first_select()))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| LEFT_PAREN_WITH with_clause query_expression_body ')'
|
||||
| LEFT_PAREN_WITH with_clause query_expression_no_with_clause ')'
|
||||
{
|
||||
SELECT_LEX *first_select= $3->first_select();
|
||||
$3->set_with_clause($2);
|
||||
@ -6782,12 +6789,7 @@ parse_vcol_expr:
|
||||
;
|
||||
|
||||
parenthesized_expr:
|
||||
query_expression
|
||||
{
|
||||
if (!($$= Lex->create_item_query_expression(thd, $1)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| expr
|
||||
expr
|
||||
| expr ',' expr_list
|
||||
{
|
||||
$3->push_front($1, thd->mem_root);
|
||||
@ -6806,6 +6808,16 @@ virtual_column_func:
|
||||
MYSQL_YYABORT;
|
||||
$$= v;
|
||||
}
|
||||
| subquery
|
||||
{
|
||||
Item *item;
|
||||
if (!(item= new (thd->mem_root) Item_singlerow_subselect(thd, $1)))
|
||||
MYSQL_YYABORT;
|
||||
Virtual_column_info *v= add_virtual_expression(thd, item);
|
||||
if (unlikely(!v))
|
||||
MYSQL_YYABORT;
|
||||
$$= v;
|
||||
}
|
||||
;
|
||||
|
||||
expr_or_literal: column_default_non_parenthesized_expr | signed_literal ;
|
||||
@ -9254,7 +9266,7 @@ opt_ignore_leaves:
|
||||
*/
|
||||
|
||||
select:
|
||||
query_expression_body
|
||||
query_expression_no_with_clause
|
||||
{
|
||||
if (Lex->push_select($1->fake_select_lex ?
|
||||
$1->fake_select_lex :
|
||||
@ -9264,10 +9276,11 @@ select:
|
||||
opt_procedure_or_into
|
||||
{
|
||||
Lex->pop_select();
|
||||
$1->set_with_clause(NULL);
|
||||
if (Lex->select_finalize($1, $3))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| with_clause query_expression_body
|
||||
| with_clause query_expression_no_with_clause
|
||||
{
|
||||
if (Lex->push_select($2->fake_select_lex ?
|
||||
$2->fake_select_lex :
|
||||
@ -9293,9 +9306,11 @@ select_into:
|
||||
}
|
||||
opt_order_limit_lock
|
||||
{
|
||||
st_select_lex_unit *unit;
|
||||
if (!(unit= Lex->parsed_body_select($1, $3)))
|
||||
SELECT_LEX_UNIT *unit;
|
||||
if (!(unit = Lex->create_unit($1)))
|
||||
MYSQL_YYABORT;
|
||||
if ($3)
|
||||
unit= Lex->add_tail_to_query_expression_body(unit, $3);
|
||||
if (Lex->select_finalize(unit))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
@ -9366,94 +9381,193 @@ select_into_query_specification:
|
||||
}
|
||||
;
|
||||
|
||||
opt_from_clause:
|
||||
/* Empty */
|
||||
| from_clause
|
||||
;
|
||||
/**
|
||||
|
||||
The following grammar for query expressions conformant to
|
||||
the latest SQL Standard is supported:
|
||||
|
||||
query_primary:
|
||||
simple_table
|
||||
{ $$= $1; }
|
||||
| query_primary_parens
|
||||
{ $$= $1; }
|
||||
;
|
||||
<query expression> ::=
|
||||
[ <with clause> ] <query expression body>
|
||||
[ <order by clause> ] [ <result offset clause> ] [ <fetch first clause> ]
|
||||
|
||||
query_primary_parens:
|
||||
'(' query_expression_unit
|
||||
{
|
||||
if (Lex->parsed_unit_in_brackets($2))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
query_expression_tail ')'
|
||||
{
|
||||
$$= Lex->parsed_unit_in_brackets_tail($2, $4);
|
||||
}
|
||||
| '(' query_primary
|
||||
{
|
||||
Lex->push_select($2);
|
||||
}
|
||||
query_expression_tail ')'
|
||||
{
|
||||
if (!($$= Lex->parsed_select_in_brackets($2, $4)))
|
||||
YYABORT;
|
||||
}
|
||||
;
|
||||
<with clause> ::=
|
||||
WITH [ RECURSIVE ] <with_list
|
||||
|
||||
query_expression_unit:
|
||||
query_primary
|
||||
unit_type_decl
|
||||
query_primary
|
||||
{
|
||||
if (!($$= Lex->parsed_select_expr_start($1, $3, $2.unit_type,
|
||||
$2.distinct)))
|
||||
YYABORT;
|
||||
}
|
||||
| query_expression_unit
|
||||
unit_type_decl
|
||||
query_primary
|
||||
{
|
||||
if (!($$= Lex->parsed_select_expr_cont($1, $3, $2.unit_type,
|
||||
$2.distinct, TRUE)))
|
||||
YYABORT;
|
||||
}
|
||||
;
|
||||
<with list> ::=
|
||||
<with list element> [ { <comma> <with list element> }... ]
|
||||
|
||||
query_expression_body:
|
||||
query_primary
|
||||
{
|
||||
Lex->push_select($1);
|
||||
}
|
||||
query_expression_tail
|
||||
{
|
||||
if (!($$= Lex->parsed_body_select($1, $3)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| query_expression_unit
|
||||
{
|
||||
if (Lex->parsed_body_unit($1))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
query_expression_tail
|
||||
{
|
||||
if (!($$= Lex->parsed_body_unit_tail($1, $3)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
;
|
||||
<with list element> ::=
|
||||
<query name> [ '(' <with column list> ')' ]
|
||||
AS <table subquery>
|
||||
|
||||
<with column list> ::=
|
||||
<column name list>
|
||||
|
||||
<query expression body> ::
|
||||
<query term>
|
||||
| <query expression body> UNION [ ALL | DISTINCT ] <query term>
|
||||
| <query expression body> EXCEPT [ DISTINCT ] <query term>
|
||||
|
||||
<query term> ::=
|
||||
<query primary>
|
||||
| <query term> INTERSECT [ DISTINCT ] <query primary>
|
||||
|
||||
<query primary> ::=
|
||||
<simple table>
|
||||
| '(' <query expression body>
|
||||
[ <order by clause> ] [ <result offset clause> ] [ <fetch first clause> ]
|
||||
')'
|
||||
|
||||
<simple table>
|
||||
<query specification>
|
||||
| <table value constructor>
|
||||
|
||||
<subquery>
|
||||
'(' <query_expression> ')'
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
query_expression produces the same expressions as
|
||||
<query expression>
|
||||
*/
|
||||
|
||||
query_expression:
|
||||
opt_with_clause
|
||||
query_expression_body
|
||||
query_expression_no_with_clause
|
||||
{
|
||||
if ($1)
|
||||
{
|
||||
$2->set_with_clause($1);
|
||||
$1->attach_to($2->first_select());
|
||||
}
|
||||
$1->set_with_clause(NULL);
|
||||
$$= $1;
|
||||
}
|
||||
| with_clause
|
||||
query_expression_no_with_clause
|
||||
{
|
||||
$2->set_with_clause($1);
|
||||
$1->attach_to($2->first_select());
|
||||
$$= $2;
|
||||
}
|
||||
;
|
||||
|
||||
/*
|
||||
query_expression_no_with_clause produces the same expressions as
|
||||
<query expression> without [ <with clause> ]
|
||||
*/
|
||||
|
||||
query_expression_no_with_clause:
|
||||
query_expression_body_ext { $$= $1; }
|
||||
| query_expression_body_ext_parens { $$= $1; }
|
||||
;
|
||||
|
||||
/*
|
||||
query_expression_body_ext produces the same expressions as
|
||||
<query expression body>
|
||||
[ <order by clause> ] [ <result offset clause> ] [ <fetch first clause> ]
|
||||
| '('... <query expression body>
|
||||
[ <order by clause> ] [ <result offset clause> ] [ <fetch first clause> ]
|
||||
')'...
|
||||
Note: number of ')' must be equal to the number of '(' in the rule above
|
||||
*/
|
||||
|
||||
query_expression_body_ext:
|
||||
query_expression_body
|
||||
{
|
||||
if ($1->first_select()->next_select())
|
||||
{
|
||||
if (Lex->parsed_multi_operand_query_expression_body($1))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
}
|
||||
opt_query_expression_tail
|
||||
{
|
||||
if (!$3)
|
||||
$$= $1;
|
||||
else
|
||||
$$= Lex->add_tail_to_query_expression_body($1, $3);
|
||||
}
|
||||
| query_expression_body_ext_parens
|
||||
{
|
||||
Lex->push_select(!$1->first_select()->next_select() ?
|
||||
$1->first_select() : $1->fake_select_lex);
|
||||
}
|
||||
query_expression_tail
|
||||
{
|
||||
if (!($$= Lex->add_tail_to_query_expression_body_ext_parens($1, $3)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
;
|
||||
|
||||
query_expression_body_ext_parens:
|
||||
'(' query_expression_body_ext_parens ')'
|
||||
{ $$= $2; }
|
||||
| '(' query_expression_body_ext ')'
|
||||
{
|
||||
SELECT_LEX *sel= $2->first_select()->next_select() ?
|
||||
$2->fake_select_lex : $2->first_select();
|
||||
sel->braces= true;
|
||||
$$= $2;
|
||||
}
|
||||
;
|
||||
|
||||
/*
|
||||
query_expression_body produces the same expressions as
|
||||
<query expression body>
|
||||
*/
|
||||
|
||||
query_expression_body:
|
||||
query_simple
|
||||
{
|
||||
Lex->push_select($1);
|
||||
if (!($$= Lex->create_unit($1)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| query_expression_body
|
||||
unit_type_decl
|
||||
{
|
||||
if (!$1->first_select()->next_select())
|
||||
{
|
||||
Lex->pop_select();
|
||||
}
|
||||
}
|
||||
query_primary
|
||||
{
|
||||
if (!($$= Lex->add_primary_to_query_expression_body($1, $4,
|
||||
$2.unit_type,
|
||||
$2.distinct,
|
||||
TRUE)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| query_expression_body_ext_parens
|
||||
unit_type_decl
|
||||
query_primary
|
||||
{
|
||||
if (!($$= Lex->add_primary_to_query_expression_body_ext_parens(
|
||||
$1, $3,
|
||||
$2.unit_type,
|
||||
$2.distinct)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
;
|
||||
|
||||
/*
|
||||
query_primary produces the same expressions as
|
||||
<query primary>
|
||||
*/
|
||||
|
||||
query_primary:
|
||||
query_simple
|
||||
{ $$= $1; }
|
||||
| query_expression_body_ext_parens
|
||||
{ $$= $1->first_select(); }
|
||||
;
|
||||
|
||||
/*
|
||||
query_simple produces the same expressions as
|
||||
<simple table>
|
||||
*/
|
||||
|
||||
query_simple:
|
||||
simple_table { $$= $1;}
|
||||
;
|
||||
|
||||
subselect:
|
||||
query_expression
|
||||
{
|
||||
@ -9462,11 +9576,63 @@ subselect:
|
||||
}
|
||||
;
|
||||
|
||||
/*
|
||||
subquery produces the same expressions as
|
||||
<subquery>
|
||||
|
||||
/**
|
||||
<table expression>, as in the SQL standard.
|
||||
Consider the production rule of the SQL Standard
|
||||
subquery:
|
||||
'(' query_expression ')'
|
||||
|
||||
This rule is equivalent to the rule
|
||||
subquery:
|
||||
'(' query_expression_no_with_clause ')'
|
||||
| '(' with_clause query_expression_no_with_clause ')'
|
||||
that in its turn is equivalent to
|
||||
subquery:
|
||||
'(' query_expression_body_ext ')'
|
||||
| query_expression_body_ext_parens
|
||||
| '(' with_clause query_expression_no_with_clause ')'
|
||||
|
||||
The latter can be re-written into
|
||||
subquery:
|
||||
query_expression_body_ext_parens
|
||||
| '(' with_clause query_expression_no_with_clause ')'
|
||||
|
||||
The last rule allows us to resolve properly the shift/reduce conflict
|
||||
when subquery is used in expressions such as in the following queries
|
||||
select (select * from t1 limit 1) + t2.a from t2
|
||||
select * from t1 where t1.a [not] in (select t2.a from t2)
|
||||
|
||||
In the rule below %prec SUBQUERY_AS_EXPR forces the parser to perform a shift
|
||||
operation rather then a reduce operation when ')' is encountered and can be
|
||||
considered as the last symbol a query expression.
|
||||
*/
|
||||
|
||||
subquery:
|
||||
query_expression_body_ext_parens %prec SUBQUERY_AS_EXPR
|
||||
{
|
||||
if (!$1->fake_select_lex)
|
||||
$1->first_select()->braces= false;
|
||||
else
|
||||
$1->fake_select_lex->braces= false;
|
||||
if (!($$= Lex->parsed_subselect($1)))
|
||||
YYABORT;
|
||||
}
|
||||
| '(' with_clause query_expression_no_with_clause ')'
|
||||
{
|
||||
$3->set_with_clause($2);
|
||||
$2->attach_to($3->first_select());
|
||||
if (!($$= Lex->parsed_subselect($3)))
|
||||
YYABORT;
|
||||
}
|
||||
;
|
||||
|
||||
opt_from_clause:
|
||||
/* empty */ %prec EMPTY_FROM_CLAUSE
|
||||
| from_clause
|
||||
;
|
||||
|
||||
from_clause:
|
||||
FROM table_reference_list
|
||||
;
|
||||
@ -9936,15 +10102,15 @@ bool_pri:
|
||||
;
|
||||
|
||||
predicate:
|
||||
bit_expr IN_SYM '(' subselect ')'
|
||||
bit_expr IN_SYM subquery
|
||||
{
|
||||
$$= new (thd->mem_root) Item_in_subselect(thd, $1, $4);
|
||||
$$= new (thd->mem_root) Item_in_subselect(thd, $1, $3);
|
||||
if (unlikely($$ == NULL))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| bit_expr not IN_SYM '(' subselect ')'
|
||||
| bit_expr not IN_SYM subquery
|
||||
{
|
||||
Item *item= new (thd->mem_root) Item_in_subselect(thd, $1, $5);
|
||||
Item *item= new (thd->mem_root) Item_in_subselect(thd, $1, $4);
|
||||
if (unlikely(item == NULL))
|
||||
MYSQL_YYABORT;
|
||||
$$= negate_expression(thd, item);
|
||||
@ -10463,6 +10629,11 @@ primary_expr:
|
||||
column_default_non_parenthesized_expr
|
||||
| explicit_cursor_attr
|
||||
| '(' parenthesized_expr ')' { $$= $2; }
|
||||
| subquery
|
||||
{
|
||||
if (!($$= Lex->create_item_query_expression(thd, $1->master_unit())))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
;
|
||||
|
||||
string_factor_expr:
|
||||
@ -12261,37 +12432,15 @@ table_primary_ident:
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
/*
|
||||
Represents a flattening of the following rules from the SQL:2003
|
||||
standard. This sub-rule corresponds to the sub-rule
|
||||
<table primary> ::= ... | <derived table> [ AS ] <correlation name>
|
||||
|
||||
<derived table> ::= <table subquery>
|
||||
<table subquery> ::= <subquery>
|
||||
<subquery> ::= <left paren> <query expression> <right paren>
|
||||
<query expression> ::= [ <with clause> ] <query expression body>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
table_primary_derived:
|
||||
query_primary_parens opt_for_system_time_clause table_alias_clause
|
||||
subquery
|
||||
opt_for_system_time_clause table_alias_clause
|
||||
{
|
||||
if (!($$= Lex->parsed_derived_select($1, $2, $3)))
|
||||
YYABORT;
|
||||
}
|
||||
| '('
|
||||
query_expression
|
||||
')' opt_for_system_time_clause table_alias_clause
|
||||
{
|
||||
if (!($$= Lex->parsed_derived_unit($2, $4, $5)))
|
||||
YYABORT;
|
||||
if (!($$= Lex->parsed_derived_table($1->master_unit(), $2, $3)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
;
|
||||
;
|
||||
|
||||
opt_outer:
|
||||
/* empty */ {}
|
||||
@ -12425,7 +12574,6 @@ table_alias:
|
||||
|
||||
opt_table_alias_clause:
|
||||
/* empty */ { $$=0; }
|
||||
|
||||
| table_alias_clause { $$= $1; }
|
||||
;
|
||||
|
||||
@ -12888,10 +13036,8 @@ delete_limit_clause:
|
||||
| LIMIT limit_option ROWS_SYM EXAMINED_SYM { thd->parse_error(); MYSQL_YYABORT; }
|
||||
;
|
||||
|
||||
opt_order_limit_lock:
|
||||
/* empty */
|
||||
{ $$= NULL; }
|
||||
| order_or_limit
|
||||
order_limit_lock:
|
||||
order_or_limit
|
||||
{
|
||||
$$= $1;
|
||||
$$->lock.empty();
|
||||
@ -12911,29 +13057,42 @@ opt_order_limit_lock:
|
||||
$$->lock= $1;
|
||||
}
|
||||
;
|
||||
opt_order_limit_lock:
|
||||
/* empty */
|
||||
{
|
||||
Lex->pop_select();
|
||||
$$= NULL;
|
||||
}
|
||||
| order_limit_lock { $$= $1; }
|
||||
;
|
||||
|
||||
query_expression_tail:
|
||||
order_limit_lock
|
||||
;
|
||||
|
||||
opt_query_expression_tail:
|
||||
opt_order_limit_lock
|
||||
;
|
||||
|
||||
opt_procedure_or_into:
|
||||
/* empty */
|
||||
{
|
||||
$$.empty();
|
||||
}
|
||||
{
|
||||
$$.empty();
|
||||
}
|
||||
| procedure_clause opt_select_lock_type
|
||||
{
|
||||
$$= $2;
|
||||
}
|
||||
{
|
||||
$$= $2;
|
||||
}
|
||||
| into opt_select_lock_type
|
||||
{
|
||||
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
|
||||
ER_WARN_DEPRECATED_SYNTAX,
|
||||
ER_THD(thd, ER_WARN_DEPRECATED_SYNTAX),
|
||||
"<select expression> INTO <destination>;",
|
||||
"'SELECT <select list> INTO <destination>"
|
||||
" FROM...'");
|
||||
$$= $2;
|
||||
}
|
||||
{
|
||||
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
|
||||
ER_WARN_DEPRECATED_SYNTAX,
|
||||
ER_THD(thd, ER_WARN_DEPRECATED_SYNTAX),
|
||||
"<select expression> INTO <destination>;",
|
||||
"'SELECT <select list> INTO <destination>"
|
||||
" FROM...'");
|
||||
$$= $2;
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
@ -15347,16 +15506,6 @@ temporal_literal:
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
opt_with_clause:
|
||||
/*empty */ { $$= 0; }
|
||||
| with_clause
|
||||
{
|
||||
$$= $1;
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
with_clause:
|
||||
WITH opt_recursive
|
||||
{
|
||||
|
Reference in New Issue
Block a user