1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +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:
Igor Babaev
2019-09-20 09:03:38 -07:00
parent e3da362c03
commit b44171428a
21 changed files with 7212 additions and 593 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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 3 EXCEPT t2 ALL NULL NULL NULL NULL 2 100.00
NULL EXCEPT RESULT <except2,3> ALL NULL NULL NULL NULL NULL NULL NULL EXCEPT RESULT <except2,3> ALL NULL NULL NULL NULL NULL NULL
Warnings: 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 format=json (select a,b from t1) except (select c,d from t2);
EXPLAIN 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) 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 NULL EXCEPT RESULT <except2,3> ALL NULL NULL NULL NULL NULL NULL
Warnings: 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 format=json (select a,b,e,f from t1,t3) except (select c,d,g,h from t2,t4);
EXPLAIN EXPLAIN
{ {

View File

@ -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 4 INTERSECT t3 ALL NULL NULL NULL NULL 3 100.00
NULL INTERSECT RESULT <intersect2,3,4> ALL NULL NULL NULL NULL NULL NULL NULL INTERSECT RESULT <intersect2,3,4> ALL NULL NULL NULL NULL NULL NULL
Warnings: 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 format=json (select a,b from t1) intersect (select c,d from t2) intersect (select e,f from t3);
EXPLAIN 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) 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 NULL INTERSECT RESULT <intersect2,3> ALL NULL NULL NULL NULL NULL NULL
Warnings: 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'; set @@optimizer_switch='optimize_join_buffer_size=off';
EXPLAIN format=json (select a,b from t1) intersect (select c,e from t2,t3); EXPLAIN format=json (select a,b from t1) intersect (select c,e from t2,t3);
EXPLAIN EXPLAIN
@ -724,7 +724,7 @@ a b
drop procedure p1; drop procedure p1;
show create view v1; show create view v1;
View Create View character_set_client collation_connection 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 view v1;
drop tables t1,t2,t3; drop tables t1,t2,t3;
# #

View File

@ -1776,7 +1776,7 @@ End of 10.3 tests
# #
create table t1 (a int); create table t1 (a int);
(select * from t1) for update; (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; (select * from t1) union (select * from t1) for update;
ERROR HY000: Incorrect usage of lock options and SELECT in brackets ERROR HY000: Incorrect usage of lock options and SELECT in brackets
(select * from t1 for update); (select * from t1 for update);

View File

@ -1544,7 +1544,6 @@ SELECT @@GLOBAL.role;
--echo # --echo #
create table t1 (a int); create table t1 (a int);
--error ER_WRONG_USAGE
(select * from t1) for update; (select * from t1) for update;
--error ER_WRONG_USAGE --error ER_WRONG_USAGE
(select * from t1) union (select * from t1) for update; (select * from t1) union (select * from t1) for update;

View File

@ -3736,8 +3736,11 @@ WHERE NOT EXISTS (((SELECT i FROM t1) UNION (SELECT i FROM t1)));
i i
explain select ((select t11.i from t1 t11) union (select t12.i from t1 t12)) explain select ((select t11.i from t1 t11) union (select t12.i from t1 t12))
from t1; 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)) id select_type table type possible_keys key key_len ref rows Extra
from t1' at line 1 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 explain select * from t1 where not exists
((select t11.i from t1 t11) union (select t12.i from t1 t12)); ((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 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 ) ) ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) )
1 1
SELECT ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 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 ( SELECT 1 UNION SELECT 1 UNION SELECT 1 );
( SELECT 1 UNION SELECT 1 UNION SELECT 1 ) ( SELECT 1 UNION SELECT 1 UNION SELECT 1 )
1 1
@ -5335,7 +5338,8 @@ SELECT * FROM t1 WHERE a IN ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) );
a a
1 1
SELECT * FROM t1 WHERE a = ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 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 ); SELECT * FROM t1 WHERE a = ALL ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 );
a a
1 1
@ -5343,7 +5347,8 @@ SELECT * FROM t1 WHERE a = ANY ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 );
a a
1 1
SELECT * FROM t1 WHERE a IN ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 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 ); SELECT * FROM t1 WHERE a = ( SELECT 1 UNION SELECT 1 UNION SELECT 1 );
a a
1 1

View File

@ -2611,8 +2611,6 @@ SELECT sql_no_cache * FROM t1 WHERE NOT EXISTS
SELECT * FROM t1 SELECT * FROM t1
WHERE NOT EXISTS (((SELECT i FROM t1) UNION (SELECT i 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)) explain select ((select t11.i from t1 t11) union (select t12.i from t1 t12))
from t1; 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 = ANY ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) );
SELECT * FROM t1 WHERE a IN ( 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 = ( ( 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 = 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 = 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 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 = ( SELECT 1 UNION SELECT 1 UNION SELECT 1 );

View File

@ -3739,8 +3739,11 @@ WHERE NOT EXISTS (((SELECT i FROM t1) UNION (SELECT i FROM t1)));
i i
explain select ((select t11.i from t1 t11) union (select t12.i from t1 t12)) explain select ((select t11.i from t1 t11) union (select t12.i from t1 t12))
from t1; 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)) id select_type table type possible_keys key key_len ref rows Extra
from t1' at line 1 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 explain select * from t1 where not exists
((select t11.i from t1 t11) union (select t12.i from t1 t12)); ((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 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 ) ) ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) )
1 1
SELECT ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 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 ( SELECT 1 UNION SELECT 1 UNION SELECT 1 );
( SELECT 1 UNION SELECT 1 UNION SELECT 1 ) ( SELECT 1 UNION SELECT 1 UNION SELECT 1 )
1 1
@ -5337,7 +5340,8 @@ SELECT * FROM t1 WHERE a IN ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) );
a a
1 1
SELECT * FROM t1 WHERE a = ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 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 ); SELECT * FROM t1 WHERE a = ALL ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 );
a a
1 1
@ -5345,7 +5349,8 @@ SELECT * FROM t1 WHERE a = ANY ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 );
a a
1 1
SELECT * FROM t1 WHERE a IN ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 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 ); SELECT * FROM t1 WHERE a = ( SELECT 1 UNION SELECT 1 UNION SELECT 1 );
a a
1 1

View File

@ -3739,8 +3739,11 @@ WHERE NOT EXISTS (((SELECT i FROM t1) UNION (SELECT i FROM t1)));
i i
explain select ((select t11.i from t1 t11) union (select t12.i from t1 t12)) explain select ((select t11.i from t1 t11) union (select t12.i from t1 t12))
from t1; 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)) id select_type table type possible_keys key key_len ref rows Extra
from t1' at line 1 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 explain select * from t1 where not exists
((select t11.i from t1 t11) union (select t12.i from t1 t12)); ((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 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 ) ) ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) )
1 1
SELECT ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 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 ( SELECT 1 UNION SELECT 1 UNION SELECT 1 );
( SELECT 1 UNION SELECT 1 UNION SELECT 1 ) ( SELECT 1 UNION SELECT 1 UNION SELECT 1 )
1 1
@ -5335,7 +5338,8 @@ SELECT * FROM t1 WHERE a IN ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) );
a a
1 1
SELECT * FROM t1 WHERE a = ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 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 ); SELECT * FROM t1 WHERE a = ALL ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 );
a a
1 1
@ -5343,7 +5347,8 @@ SELECT * FROM t1 WHERE a = ANY ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 );
a a
1 1
SELECT * FROM t1 WHERE a IN ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 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 ); SELECT * FROM t1 WHERE a = ( SELECT 1 UNION SELECT 1 UNION SELECT 1 );
a a
1 1

View File

@ -3735,8 +3735,11 @@ WHERE NOT EXISTS (((SELECT i FROM t1) UNION (SELECT i FROM t1)));
i i
explain select ((select t11.i from t1 t11) union (select t12.i from t1 t12)) explain select ((select t11.i from t1 t11) union (select t12.i from t1 t12))
from t1; 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)) id select_type table type possible_keys key key_len ref rows Extra
from t1' at line 1 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 explain select * from t1 where not exists
((select t11.i from t1 t11) union (select t12.i from t1 t12)); ((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 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 ) ) ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) )
1 1
SELECT ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 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 ( SELECT 1 UNION SELECT 1 UNION SELECT 1 );
( SELECT 1 UNION SELECT 1 UNION SELECT 1 ) ( SELECT 1 UNION SELECT 1 UNION SELECT 1 )
1 1
@ -5331,7 +5334,8 @@ SELECT * FROM t1 WHERE a IN ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) );
a a
1 1
SELECT * FROM t1 WHERE a = ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 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 ); SELECT * FROM t1 WHERE a = ALL ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 );
a a
1 1
@ -5339,7 +5343,8 @@ SELECT * FROM t1 WHERE a = ANY ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 );
a a
1 1
SELECT * FROM t1 WHERE a IN ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 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 ); SELECT * FROM t1 WHERE a = ( SELECT 1 UNION SELECT 1 UNION SELECT 1 );
a a
1 1

View File

@ -3742,8 +3742,11 @@ WHERE NOT EXISTS (((SELECT i FROM t1) UNION (SELECT i FROM t1)));
i i
explain select ((select t11.i from t1 t11) union (select t12.i from t1 t12)) explain select ((select t11.i from t1 t11) union (select t12.i from t1 t12))
from t1; 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)) id select_type table type possible_keys key key_len ref rows Extra
from t1' at line 1 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 explain select * from t1 where not exists
((select t11.i from t1 t11) union (select t12.i from t1 t12)); ((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 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 ) ) ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) )
1 1
SELECT ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 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 ( SELECT 1 UNION SELECT 1 UNION SELECT 1 );
( SELECT 1 UNION SELECT 1 UNION SELECT 1 ) ( SELECT 1 UNION SELECT 1 UNION SELECT 1 )
1 1
@ -5341,7 +5344,8 @@ SELECT * FROM t1 WHERE a IN ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) );
a a
1 1
SELECT * FROM t1 WHERE a = ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 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 ); SELECT * FROM t1 WHERE a = ALL ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 );
a a
1 1
@ -5349,7 +5353,8 @@ SELECT * FROM t1 WHERE a = ANY ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 );
a a
1 1
SELECT * FROM t1 WHERE a IN ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 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 ); SELECT * FROM t1 WHERE a = ( SELECT 1 UNION SELECT 1 UNION SELECT 1 );
a a
1 1

View File

@ -3735,8 +3735,11 @@ WHERE NOT EXISTS (((SELECT i FROM t1) UNION (SELECT i FROM t1)));
i i
explain select ((select t11.i from t1 t11) union (select t12.i from t1 t12)) explain select ((select t11.i from t1 t11) union (select t12.i from t1 t12))
from t1; 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)) id select_type table type possible_keys key key_len ref rows Extra
from t1' at line 1 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 explain select * from t1 where not exists
((select t11.i from t1 t11) union (select t12.i from t1 t12)); ((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 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 ) ) ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) )
1 1
SELECT ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 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 ( SELECT 1 UNION SELECT 1 UNION SELECT 1 );
( SELECT 1 UNION SELECT 1 UNION SELECT 1 ) ( SELECT 1 UNION SELECT 1 UNION SELECT 1 )
1 1
@ -5331,7 +5334,8 @@ SELECT * FROM t1 WHERE a IN ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) );
a a
1 1
SELECT * FROM t1 WHERE a = ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 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 ); SELECT * FROM t1 WHERE a = ALL ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 );
a a
1 1
@ -5339,7 +5343,8 @@ SELECT * FROM t1 WHERE a = ANY ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 );
a a
1 1
SELECT * FROM t1 WHERE a IN ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 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 ); SELECT * FROM t1 WHERE a = ( SELECT 1 UNION SELECT 1 UNION SELECT 1 );
a a
1 1

View File

@ -122,7 +122,8 @@ void Item_subselect::init(st_select_lex *select_lex,
parsing_place= (outer_select->in_sum_expr ? parsing_place= (outer_select->in_sum_expr ?
NO_MATTER : NO_MATTER :
outer_select->parsing_place); 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); engine= new subselect_union_engine(unit, result, this);
else else
engine= new subselect_single_select_engine(select_lex, result, this); engine= new subselect_single_select_engine(select_lex, result, this);

View File

@ -1444,7 +1444,7 @@ int Lex_input_stream::lex_token(YYSTYPE *yylval, THD *thd)
return LEFT_PAREN_LIKE; return LEFT_PAREN_LIKE;
if (token == WITH) if (token == WITH)
return LEFT_PAREN_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; return LEFT_PAREN_ALT;
else else
return left_paren; return left_paren;
@ -5339,10 +5339,9 @@ LEX::create_unit(SELECT_LEX *first_sel)
SELECT_LEX_UNIT *unit; SELECT_LEX_UNIT *unit;
DBUG_ENTER("LEX::create_unit"); DBUG_ENTER("LEX::create_unit");
if (first_sel->master_unit()) unit = first_sel->master_unit();
DBUG_RETURN(first_sel->master_unit());
if (!(unit= alloc_unit())) if (!unit && !(unit= alloc_unit()))
DBUG_RETURN(NULL); DBUG_RETURN(NULL);
unit->register_select_chain(first_sel); 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 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); DBUG_ASSERT(builtin_select.table_list.elements == 1);
TABLE_LIST *insert_table= builtin_select.table_list.first; 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. Create an Item_singlerow_subselect for a query expression.
*/ */
Item *LEX::create_item_query_expression(THD *thd, Item *LEX::create_item_query_expression(THD *thd,
st_select_lex_unit *unit) st_select_lex_unit *unit)
{ {
@ -9062,118 +9063,17 @@ Item *LEX::create_item_query_expression(THD *thd,
SELECT_LEX *curr_sel= select_stack_head(); SELECT_LEX *curr_sel= select_stack_head();
DBUG_ASSERT(current_select == curr_sel); DBUG_ASSERT(current_select == curr_sel);
if (!curr_sel) if (!curr_sel)
{
curr_sel= &builtin_select; curr_sel= &builtin_select;
curr_sel->register_unit(unit, &curr_sel->context); curr_sel->register_unit(unit, &curr_sel->context);
curr_sel->add_statistics(unit); curr_sel->add_statistics(unit);
}
return new (thd->mem_root) return new (thd->mem_root)
Item_singlerow_subselect(thd, unit->first_select()); 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, SELECT_LEX_UNIT *LEX::parsed_select_expr_start(SELECT_LEX *s1, SELECT_LEX *s2,
enum sub_select_type unit_type, enum sub_select_type unit_type,
bool distinct) bool distinct)
@ -9204,6 +9104,7 @@ SELECT_LEX_UNIT *LEX::parsed_select_expr_start(SELECT_LEX *s1, SELECT_LEX *s2,
if (res == NULL) if (res == NULL)
return NULL; return NULL;
res->pre_last_parse= sel1; res->pre_last_parse= sel1;
push_select(res->fake_select_lex);
return res; return res;
} }
@ -9216,12 +9117,6 @@ SELECT_LEX_UNIT *LEX::parsed_select_expr_cont(SELECT_LEX_UNIT *unit,
SELECT_LEX *sel1; SELECT_LEX *sel1;
if (!s2->next_select()) if (!s2->next_select())
sel1= s2; sel1= s2;
else
{
sel1= wrap_unit_into_derived(s2->master_unit());
if (!sel1)
return NULL;
}
SELECT_LEX *last= unit->pre_last_parse->next_select(); SELECT_LEX *last= unit->pre_last_parse->next_select();
int cmp= oracle? 0 : cmp_unit_op(unit_type, last->get_linkage()); 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; return unit;
} }
/**
Process parsed select in body
*/
SELECT_LEX_UNIT *LEX::parsed_body_select(SELECT_LEX *sel,
Lex_order_limit_lock * l)
{
if (sel->braces && l && l->lock.defined_lock)
{
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))
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;
}
/** /**
Process parsed unit in body Add primary expression as the next term in a given query expression body
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(SELECT_LEX_UNIT *unit,
SELECT_LEX *sel,
enum sub_select_type unit_type,
bool distinct,
bool oracle)
{
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;
}
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;
}
/**
Add query primary to a parenthesized query primary
pruducing a new query expression body
*/
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= SELECT_LEX *first_in_nest=
unit->pre_last_parse->next_select()->first_nested; unit->pre_last_parse->next_select()->first_nested;
@ -9298,27 +9225,60 @@ bool LEX::parsed_body_unit(SELECT_LEX_UNIT *unit)
return true; return true;
unit->fix_distinct(); unit->fix_distinct();
} }
push_select(unit->fake_select_lex);
return false; 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, SELECT_LEX_UNIT *LEX::add_tail_to_query_expression_body(SELECT_LEX_UNIT *unit,
Lex_order_limit_lock *l) Lex_order_limit_lock *l)
{ {
DBUG_ASSERT(l != NULL);
pop_select(); pop_select();
if (l) SELECT_LEX *sel= unit->first_select()->next_select() ? unit->fake_select_lex :
{ unit->first_select();
(l)->set_to(unit->fake_select_lex); l->set_to(sel);
}
return unit; 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 Process subselect parsing
*/ */
@ -9345,7 +9305,6 @@ SELECT_LEX *LEX::parsed_subselect(SELECT_LEX_UNIT *unit)
} }
/** /**
Process INSERT-like select 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); TABLE_LIST *LEX::parsed_derived_table(SELECT_LEX_UNIT *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,
int for_system_time, int for_system_time,
LEX_CSTRING *alias) 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 // Add the subtree of subquery to the current SELECT_LEX
SELECT_LEX *curr_sel= select_stack_head(); SELECT_LEX *curr_sel= select_stack_head();
DBUG_ASSERT(current_select == curr_sel); 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); Table_ident *ti= new (thd->mem_root) Table_ident(unit);
if (ti == NULL) 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) bool LEX::parsed_create_view(SELECT_LEX_UNIT *unit, int check)
{ {
SQL_I_List<TABLE_LIST> *save= &first_select_lex()->table_list; 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()) if (check_main_unit_semantics())
return true; return true;
first_select_lex()->table_list.push_front(save); 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; sql_command= SQLCOM_SELECT;
selects_allow_into= TRUE; selects_allow_into= TRUE;
selects_allow_procedure= TRUE; selects_allow_procedure= TRUE;
set_main_unit(expr); if (set_main_unit(expr))
return true;
return check_main_unit_semantics(); 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); select_finalize(expr);
} }
/* /*
"IN" and "EXISTS" subselect can appear in two statement types: "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) bool SELECT_LEX_UNIT::set_lock_to_the_last_select(Lex_select_lock l)
{ {
if (l.defined_lock) if (l.defined_lock)

View File

@ -4414,9 +4414,6 @@ public:
insert_list= 0; insert_list= 0;
} }
bool make_select_in_brackets(SELECT_LEX* dummy_select,
SELECT_LEX *nselect, bool automatic);
SELECT_LEX_UNIT *alloc_unit(); SELECT_LEX_UNIT *alloc_unit();
SELECT_LEX *alloc_select(bool is_select); SELECT_LEX *alloc_select(bool is_select);
SELECT_LEX_UNIT *create_unit(SELECT_LEX*); SELECT_LEX_UNIT *create_unit(SELECT_LEX*);
@ -4426,7 +4423,7 @@ public:
bool insert_select_hack(SELECT_LEX *sel); bool insert_select_hack(SELECT_LEX *sel);
SELECT_LEX *create_priority_nest(SELECT_LEX *first_in_nest); 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.options= u->options;
unit.uncacheable= u->uncacheable; unit.uncacheable= u->uncacheable;
@ -4436,16 +4433,10 @@ public:
unit.union_distinct= u->union_distinct; unit.union_distinct= u->union_distinct;
unit.set_with_clause(u->with_clause); unit.set_with_clause(u->with_clause);
builtin_select.exclude_from_global(); builtin_select.exclude_from_global();
return false;
} }
bool check_main_unit_semantics(); 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, SELECT_LEX_UNIT *parsed_select_expr_start(SELECT_LEX *s1, SELECT_LEX *s2,
enum sub_select_type unit_type, enum sub_select_type unit_type,
bool distinct); bool distinct);
@ -4453,18 +4444,33 @@ public:
SELECT_LEX *s2, SELECT_LEX *s2,
enum sub_select_type unit_type, enum sub_select_type unit_type,
bool distinct, bool oracle); bool distinct, bool oracle);
SELECT_LEX_UNIT *parsed_body_select(SELECT_LEX *sel, 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); Lex_order_limit_lock *l);
bool parsed_body_unit(SELECT_LEX_UNIT *unit); SELECT_LEX_UNIT *
SELECT_LEX_UNIT *parsed_body_unit_tail(SELECT_LEX_UNIT *unit, add_tail_to_query_expression_body_ext_parens(SELECT_LEX_UNIT *unit,
Lex_order_limit_lock *l); 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); SELECT_LEX *parsed_subselect(SELECT_LEX_UNIT *unit);
bool parsed_insert_select(SELECT_LEX *firs_select); bool parsed_insert_select(SELECT_LEX *firs_select);
bool parsed_TVC_start(); bool parsed_TVC_start();
SELECT_LEX *parsed_TVC_end(); SELECT_LEX *parsed_TVC_end();
TABLE_LIST *parsed_derived_select(SELECT_LEX *sel, int for_system_time, TABLE_LIST *parsed_derived_table(SELECT_LEX_UNIT *unit,
LEX_CSTRING *alias);
TABLE_LIST *parsed_derived_unit(SELECT_LEX_UNIT *unit,
int for_system_time, int for_system_time,
LEX_CSTRING *alias); LEX_CSTRING *alias);
bool parsed_create_view(SELECT_LEX_UNIT *unit, int check); bool parsed_create_view(SELECT_LEX_UNIT *unit, int check);

View File

@ -11261,7 +11261,7 @@ bool Sql_cmd_create_table_like::execute(THD *thd)
} }
#endif #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; select_result *result;

View File

@ -831,8 +831,8 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
bool is_union_select; bool is_union_select;
bool have_except= FALSE, have_intersect= FALSE; bool have_except= FALSE, have_intersect= FALSE;
bool instantiate_tmp_table= false; bool instantiate_tmp_table= false;
bool single_tvc= !first_sl->next_select() && first_sl->tvc && bool single_tvc= !first_sl->next_select() && first_sl->tvc;
!fake_select_lex; bool single_tvc_wo_order= single_tvc && !first_sl->order_list.elements;
DBUG_ENTER("st_select_lex_unit::prepare"); DBUG_ENTER("st_select_lex_unit::prepare");
DBUG_ASSERT(thd == current_thd); 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_union_select || is_recursive)
{ {
if ((is_unit_op() && !union_needs_tmp_table() && if ((single_tvc_wo_order && !fake_select_lex) ||
!have_except && !have_intersect) || single_tvc) (is_unit_op() && !union_needs_tmp_table() &&
!have_except && !have_intersect && !single_tvc))
{ {
SELECT_LEX *last= first_select(); SELECT_LEX *last= first_select();
while (last->next_select()) while (last->next_select())
@ -986,17 +987,40 @@ bool st_select_lex_unit::prepare(TABLE_LIST *derived_arg,
if (sl->tvc && sl->order_list.elements && if (sl->tvc && sl->order_list.elements &&
!sl->tvc->to_be_wrapped_as_with_tail()) !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) if (thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW)
{ {
sl->master_unit()->fake_select_lex= 0; unit->fake_select_lex= 0;
sl->master_unit()->saved_fake_select_lex= 0; unit->saved_fake_select_lex= 0;
} }
else else
{ {
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->order_list.empty();
sl->explicit_limit= 0; sl->explicit_limit= 0;
sl->select_limit= 0; sl->select_limit= 0;
sl->offset_limit= 0; sl->offset_limit= 0;
if (describe)
fake->options|= SELECT_DESCRIBE;
}
else if (!sl->explicit_limit)
sl->order_list.empty();
} }
} }

View File

@ -817,10 +817,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%parse-param { THD *thd } %parse-param { THD *thd }
%lex-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. We should not introduce new conflicts any more.
*/ */
%expect 47 %expect 38
/* /*
Comments for TOKENS. Comments for TOKENS.
@ -1638,6 +1638,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%left MYSQL_CONCAT_SYM %left MYSQL_CONCAT_SYM
%left NEG '~' NOT2_SYM BINARY %left NEG '~' NOT2_SYM BINARY
%left COLLATE_SYM %left COLLATE_SYM
%left SUBQUERY_AS_EXPR
/* /*
Tokens that can change their meaning from identifier to something else 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; ALTER TABLE t1 ADD SYSTEM VERSIONING;
*/ */
%left PREC_BELOW_CONTRACTION_TOKEN2 %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> %type <lex_str>
DECIMAL_NUM FLOAT_NUM NUM LONG_NUM DECIMAL_NUM FLOAT_NUM NUM LONG_NUM
@ -1991,16 +1994,18 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
query_specification query_specification
table_value_constructor table_value_constructor
simple_table simple_table
query_simple
query_primary query_primary
query_primary_parens subquery
select_into_query_specification select_into_query_specification
%type <select_lex_unit> %type <select_lex_unit>
query_specification_start
query_expression_body
query_expression 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 %type <boolfunc2creator> comp_op
@ -2025,7 +2030,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%type <order_limit_lock> %type <order_limit_lock>
query_expression_tail query_expression_tail
opt_query_expression_tail
order_or_limit order_or_limit
order_limit_lock
opt_order_limit_lock opt_order_limit_lock
%type <select_order> opt_order_clause order_clause order_list %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 THEN_SYM WHEN_SYM DIV_SYM MOD_SYM OR2_SYM AND_AND_SYM DELETE_SYM
MYSQL_CONCAT_SYM ORACLE_CONCAT_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 %type <lex_str_ptr> query_name
@ -5265,7 +5272,7 @@ create_select_query_expression:
if (Lex->parsed_insert_select($1->first_select())) if (Lex->parsed_insert_select($1->first_select()))
MYSQL_YYABORT; 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(); SELECT_LEX *first_select= $3->first_select();
$3->set_with_clause($2); $3->set_with_clause($2);
@ -6773,12 +6780,7 @@ parse_vcol_expr:
; ;
parenthesized_expr: parenthesized_expr:
query_expression expr
{
if (!($$= Lex->create_item_query_expression(thd, $1)))
MYSQL_YYABORT;
}
| expr
| expr ',' expr_list | expr ',' expr_list
{ {
$3->push_front($1, thd->mem_root); $3->push_front($1, thd->mem_root);
@ -6797,6 +6799,16 @@ virtual_column_func:
MYSQL_YYABORT; MYSQL_YYABORT;
$$= v; $$= 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 ; expr_or_literal: column_default_non_parenthesized_expr | signed_literal ;
@ -9152,8 +9164,9 @@ opt_ignore_leaves:
Select : retrieve data from table Select : retrieve data from table
*/ */
select: select:
query_expression_body query_expression_no_with_clause
{ {
if (Lex->push_select($1->fake_select_lex ? if (Lex->push_select($1->fake_select_lex ?
$1->fake_select_lex : $1->fake_select_lex :
@ -9163,10 +9176,11 @@ select:
opt_procedure_or_into opt_procedure_or_into
{ {
Lex->pop_select(); Lex->pop_select();
$1->set_with_clause(NULL);
if (Lex->select_finalize($1, $3)) if (Lex->select_finalize($1, $3))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| with_clause query_expression_body | with_clause query_expression_no_with_clause
{ {
if (Lex->push_select($2->fake_select_lex ? if (Lex->push_select($2->fake_select_lex ?
$2->fake_select_lex : $2->fake_select_lex :
@ -9183,7 +9197,6 @@ select:
} }
; ;
select_into: select_into:
select_into_query_specification select_into_query_specification
{ {
@ -9192,15 +9205,16 @@ select_into:
} }
opt_order_limit_lock opt_order_limit_lock
{ {
st_select_lex_unit *unit; SELECT_LEX_UNIT *unit;
if (!(unit= Lex->parsed_body_select($1, $3))) if (!(unit = Lex->create_unit($1)))
MYSQL_YYABORT; MYSQL_YYABORT;
if ($3)
unit= Lex->add_tail_to_query_expression_body(unit, $3);
if (Lex->select_finalize(unit)) if (Lex->select_finalize(unit))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
; ;
simple_table: simple_table:
query_specification { $$= $1; } query_specification { $$= $1; }
| table_value_constructor { $$= $1; } | table_value_constructor { $$= $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: <query expression> ::=
simple_table [ <with clause> ] <query expression body>
{ $$= $1; } [ <order by clause> ] [ <result offset clause> ] [ <fetch first clause> ]
| query_primary_parens
{ $$= $1; }
;
query_primary_parens: <with clause> ::=
'(' query_expression_unit WITH [ RECURSIVE ] <with_list
{
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;
}
;
query_expression_unit: <with list> ::=
query_primary <with list element> [ { <comma> <with list element> }... ]
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;
}
;
query_expression_body: <with list element> ::=
query_primary <query name> [ '(' <with column list> ')' ]
{ AS <table subquery>
Lex->push_select($1);
} <with column list> ::=
query_expression_tail <column name list>
{
if (!($$= Lex->parsed_body_select($1, $3))) <query expression body> ::
MYSQL_YYABORT; <query term>
} | <query expression body> UNION [ ALL | DISTINCT ] <query term>
| query_expression_unit | <query expression body> EXCEPT [ DISTINCT ] <query term>
{
if (Lex->parsed_body_unit($1)) <query term> ::=
MYSQL_YYABORT; <query primary>
} | <query term> INTERSECT [ DISTINCT ] <query primary>
query_expression_tail
{ <query primary> ::=
if (!($$= Lex->parsed_body_unit_tail($1, $3))) <simple table>
MYSQL_YYABORT; | '(' <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: query_expression:
opt_with_clause query_expression_no_with_clause
query_expression_body
{ {
if ($1) $1->set_with_clause(NULL);
$$= $1;
}
| with_clause
query_expression_no_with_clause
{ {
$2->set_with_clause($1); $2->set_with_clause($1);
$1->attach_to($2->first_select()); $1->attach_to($2->first_select());
}
$$= $2; $$= $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: subselect:
query_expression query_expression
{ {
@ -9361,11 +9474,63 @@ subselect:
} }
; ;
/*
subquery produces the same expressions as
<subquery>
/** Consider the production rule of the SQL Standard
<table expression>, as in 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_clause:
FROM table_reference_list FROM table_reference_list
; ;
@ -9529,6 +9694,7 @@ select_lock_type:
} }
; ;
opt_select_lock_type: opt_select_lock_type:
/* empty */ /* empty */
{ {
@ -9540,6 +9706,7 @@ opt_select_lock_type:
} }
; ;
opt_lock_wait_timeout_new: opt_lock_wait_timeout_new:
/* empty */ /* empty */
{ {
@ -9826,15 +9993,15 @@ bool_pri:
; ;
predicate: 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)) if (unlikely($$ == NULL))
MYSQL_YYABORT; 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)) if (unlikely(item == NULL))
MYSQL_YYABORT; MYSQL_YYABORT;
$$= negate_expression(thd, item); $$= negate_expression(thd, item);
@ -10353,6 +10520,11 @@ primary_expr:
column_default_non_parenthesized_expr column_default_non_parenthesized_expr
| explicit_cursor_attr | explicit_cursor_attr
| '(' parenthesized_expr ')' { $$= $2; } | '(' parenthesized_expr ')' { $$= $2; }
| subquery
{
if (!($$= Lex->create_item_query_expression(thd, $1->master_unit())))
MYSQL_YYABORT;
}
; ;
string_factor_expr: 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: 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))) if (!($$= Lex->parsed_derived_table($1->master_unit(), $2, $3)))
YYABORT; MYSQL_YYABORT;
}
| '('
query_expression
')' opt_for_system_time_clause table_alias_clause
{
if (!($$= Lex->parsed_derived_unit($2, $4, $5)))
YYABORT;
} }
; ;
@ -12315,7 +12464,6 @@ table_alias:
opt_table_alias_clause: opt_table_alias_clause:
/* empty */ { $$=0; } /* empty */ { $$=0; }
| table_alias_clause { $$= $1; } | table_alias_clause { $$= $1; }
; ;
@ -12778,10 +12926,8 @@ delete_limit_clause:
| LIMIT limit_option ROWS_SYM EXAMINED_SYM { thd->parse_error(); MYSQL_YYABORT; } | LIMIT limit_option ROWS_SYM EXAMINED_SYM { thd->parse_error(); MYSQL_YYABORT; }
; ;
opt_order_limit_lock: order_limit_lock:
/* empty */ order_or_limit
{ $$= NULL; }
| order_or_limit
{ {
$$= $1; $$= $1;
$$->lock.empty(); $$->lock.empty();
@ -12801,7 +12947,21 @@ opt_order_limit_lock:
$$->lock= $1; $$->lock= $1;
} }
; ;
opt_order_limit_lock:
/* empty */
{
Lex->pop_select();
$$= NULL;
}
| order_limit_lock { $$= $1; }
;
query_expression_tail: query_expression_tail:
order_limit_lock
;
opt_query_expression_tail:
opt_order_limit_lock opt_order_limit_lock
; ;
@ -12826,7 +12986,6 @@ opt_procedure_or_into:
} }
; ;
order_or_limit: order_or_limit:
order_clause opt_limit_clause order_clause opt_limit_clause
{ {
@ -15215,16 +15374,6 @@ temporal_literal:
} }
; ;
opt_with_clause:
/*empty */ { $$= 0; }
| with_clause
{
$$= $1;
}
;
with_clause: with_clause:
WITH opt_recursive WITH opt_recursive
{ {

View File

@ -295,10 +295,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%parse-param { THD *thd } %parse-param { THD *thd }
%lex-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. We should not introduce new conflicts any more.
*/ */
%expect 50 %expect 41
/* /*
Comments for TOKENS. Comments for TOKENS.
@ -1115,6 +1115,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%left '^' %left '^'
%left MYSQL_CONCAT_SYM %left MYSQL_CONCAT_SYM
%left NEG '~' NOT2_SYM BINARY %left NEG '~' NOT2_SYM BINARY
%left SUBQUERY_AS_EXPR
%left COLLATE_SYM %left COLLATE_SYM
/* /*
@ -1206,7 +1207,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
ALTER TABLE t1 ADD SYSTEM VERSIONING; ALTER TABLE t1 ADD SYSTEM VERSIONING;
*/ */
%left PREC_BELOW_CONTRACTION_TOKEN2 %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> %type <lex_str>
DECIMAL_NUM FLOAT_NUM NUM LONG_NUM DECIMAL_NUM FLOAT_NUM NUM LONG_NUM
@ -1478,16 +1481,18 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
query_specification query_specification
table_value_constructor table_value_constructor
simple_table simple_table
query_simple
query_primary query_primary
query_primary_parens subquery
select_into_query_specification select_into_query_specification
%type <select_lex_unit> %type <select_lex_unit>
query_specification_start
query_expression_body
query_expression 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 %type <boolfunc2creator> comp_op
@ -1512,7 +1517,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%type <order_limit_lock> %type <order_limit_lock>
query_expression_tail query_expression_tail
opt_query_expression_tail
order_or_limit order_or_limit
order_limit_lock
opt_order_limit_lock opt_order_limit_lock
%type <select_order> opt_order_clause order_clause order_list %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 THEN_SYM WHEN_SYM DIV_SYM MOD_SYM OR2_SYM AND_AND_SYM DELETE_SYM
MYSQL_CONCAT_SYM ORACLE_CONCAT_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 %type <lex_str_ptr> query_name
@ -5273,7 +5280,7 @@ create_select_query_expression:
if (Lex->parsed_insert_select($1->first_select())) if (Lex->parsed_insert_select($1->first_select()))
MYSQL_YYABORT; 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(); SELECT_LEX *first_select= $3->first_select();
$3->set_with_clause($2); $3->set_with_clause($2);
@ -6782,12 +6789,7 @@ parse_vcol_expr:
; ;
parenthesized_expr: parenthesized_expr:
query_expression expr
{
if (!($$= Lex->create_item_query_expression(thd, $1)))
MYSQL_YYABORT;
}
| expr
| expr ',' expr_list | expr ',' expr_list
{ {
$3->push_front($1, thd->mem_root); $3->push_front($1, thd->mem_root);
@ -6806,6 +6808,16 @@ virtual_column_func:
MYSQL_YYABORT; MYSQL_YYABORT;
$$= v; $$= 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 ; expr_or_literal: column_default_non_parenthesized_expr | signed_literal ;
@ -9254,7 +9266,7 @@ opt_ignore_leaves:
*/ */
select: select:
query_expression_body query_expression_no_with_clause
{ {
if (Lex->push_select($1->fake_select_lex ? if (Lex->push_select($1->fake_select_lex ?
$1->fake_select_lex : $1->fake_select_lex :
@ -9264,10 +9276,11 @@ select:
opt_procedure_or_into opt_procedure_or_into
{ {
Lex->pop_select(); Lex->pop_select();
$1->set_with_clause(NULL);
if (Lex->select_finalize($1, $3)) if (Lex->select_finalize($1, $3))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
| with_clause query_expression_body | with_clause query_expression_no_with_clause
{ {
if (Lex->push_select($2->fake_select_lex ? if (Lex->push_select($2->fake_select_lex ?
$2->fake_select_lex : $2->fake_select_lex :
@ -9293,9 +9306,11 @@ select_into:
} }
opt_order_limit_lock opt_order_limit_lock
{ {
st_select_lex_unit *unit; SELECT_LEX_UNIT *unit;
if (!(unit= Lex->parsed_body_select($1, $3))) if (!(unit = Lex->create_unit($1)))
MYSQL_YYABORT; MYSQL_YYABORT;
if ($3)
unit= Lex->add_tail_to_query_expression_body(unit, $3);
if (Lex->select_finalize(unit)) if (Lex->select_finalize(unit))
MYSQL_YYABORT; 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: <query expression> ::=
simple_table [ <with clause> ] <query expression body>
{ $$= $1; } [ <order by clause> ] [ <result offset clause> ] [ <fetch first clause> ]
| query_primary_parens
{ $$= $1; }
;
query_primary_parens: <with clause> ::=
'(' query_expression_unit WITH [ RECURSIVE ] <with_list
{
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;
}
;
query_expression_unit: <with list> ::=
query_primary <with list element> [ { <comma> <with list element> }... ]
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;
}
;
query_expression_body: <with list element> ::=
query_primary <query name> [ '(' <with column list> ')' ]
{ AS <table subquery>
Lex->push_select($1);
} <with column list> ::=
query_expression_tail <column name list>
{
if (!($$= Lex->parsed_body_select($1, $3))) <query expression body> ::
MYSQL_YYABORT; <query term>
} | <query expression body> UNION [ ALL | DISTINCT ] <query term>
| query_expression_unit | <query expression body> EXCEPT [ DISTINCT ] <query term>
{
if (Lex->parsed_body_unit($1)) <query term> ::=
MYSQL_YYABORT; <query primary>
} | <query term> INTERSECT [ DISTINCT ] <query primary>
query_expression_tail
{ <query primary> ::=
if (!($$= Lex->parsed_body_unit_tail($1, $3))) <simple table>
MYSQL_YYABORT; | '(' <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: query_expression:
opt_with_clause query_expression_no_with_clause
query_expression_body
{ {
if ($1) $1->set_with_clause(NULL);
$$= $1;
}
| with_clause
query_expression_no_with_clause
{ {
$2->set_with_clause($1); $2->set_with_clause($1);
$1->attach_to($2->first_select()); $1->attach_to($2->first_select());
}
$$= $2; $$= $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: subselect:
query_expression query_expression
{ {
@ -9462,11 +9576,63 @@ subselect:
} }
; ;
/*
subquery produces the same expressions as
<subquery>
/** Consider the production rule of the SQL Standard
<table expression>, as in 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_clause:
FROM table_reference_list FROM table_reference_list
; ;
@ -9936,15 +10102,15 @@ bool_pri:
; ;
predicate: 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)) if (unlikely($$ == NULL))
MYSQL_YYABORT; 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)) if (unlikely(item == NULL))
MYSQL_YYABORT; MYSQL_YYABORT;
$$= negate_expression(thd, item); $$= negate_expression(thd, item);
@ -10463,6 +10629,11 @@ primary_expr:
column_default_non_parenthesized_expr column_default_non_parenthesized_expr
| explicit_cursor_attr | explicit_cursor_attr
| '(' parenthesized_expr ')' { $$= $2; } | '(' parenthesized_expr ')' { $$= $2; }
| subquery
{
if (!($$= Lex->create_item_query_expression(thd, $1->master_unit())))
MYSQL_YYABORT;
}
; ;
string_factor_expr: 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: 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))) if (!($$= Lex->parsed_derived_table($1->master_unit(), $2, $3)))
YYABORT; MYSQL_YYABORT;
}
| '('
query_expression
')' opt_for_system_time_clause table_alias_clause
{
if (!($$= Lex->parsed_derived_unit($2, $4, $5)))
YYABORT;
} }
; ;
;
opt_outer: opt_outer:
/* empty */ {} /* empty */ {}
@ -12425,7 +12574,6 @@ table_alias:
opt_table_alias_clause: opt_table_alias_clause:
/* empty */ { $$=0; } /* empty */ { $$=0; }
| table_alias_clause { $$= $1; } | table_alias_clause { $$= $1; }
; ;
@ -12888,10 +13036,8 @@ delete_limit_clause:
| LIMIT limit_option ROWS_SYM EXAMINED_SYM { thd->parse_error(); MYSQL_YYABORT; } | LIMIT limit_option ROWS_SYM EXAMINED_SYM { thd->parse_error(); MYSQL_YYABORT; }
; ;
opt_order_limit_lock: order_limit_lock:
/* empty */ order_or_limit
{ $$= NULL; }
| order_or_limit
{ {
$$= $1; $$= $1;
$$->lock.empty(); $$->lock.empty();
@ -12911,7 +13057,20 @@ opt_order_limit_lock:
$$->lock= $1; $$->lock= $1;
} }
; ;
opt_order_limit_lock:
/* empty */
{
Lex->pop_select();
$$= NULL;
}
| order_limit_lock { $$= $1; }
;
query_expression_tail: query_expression_tail:
order_limit_lock
;
opt_query_expression_tail:
opt_order_limit_lock opt_order_limit_lock
; ;
@ -15347,16 +15506,6 @@ temporal_literal:
} }
; ;
opt_with_clause:
/*empty */ { $$= 0; }
| with_clause
{
$$= $1;
}
;
with_clause: with_clause:
WITH opt_recursive WITH opt_recursive
{ {