1
0
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:
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
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
{

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
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;
#

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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 );

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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))

View File

@ -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
{

View File

@ -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
{