[Commits] 804855b1605: # Das ist eine Kombination aus 5 Commits.

Oleksandr Byelkin sanja at mariadb.com
Tue Apr 3 10:50:40 EEST 2018


revision-id: 804855b160566ddfc5b9efc48ae4d69332ce5625 (mariadb-10.3.1-46-g804855b1605)
parent(s): 4a32e2395e1ff6cf7274d0567282b1747031108b
author: Oleksandr Byelkin
committer: Oleksandr Byelkin
timestamp: 2018-04-03 09:50:40 +0200
message:

# Das ist eine Kombination aus 5 Commits.
# Das ist die erste Commit-Beschreibung:

Start point for attempts to solve subselect/dirived problem

# Die Commit-Beschreibung #2 wird ausgelassen:

# ccc

# Die Commit-Beschreibung #3 wird ausgelassen:

# cccc

# Die Commit-Beschreibung #4 wird ausgelassen:

# ccc 2018-02-09 s

# Die Commit-Beschreibung #5 wird ausgelassen:

# Intermediate commit with added query_expression.

---
 mysql-test/r/except.result                    |    4 +-
 mysql-test/r/fulltext_order_by.result         |    4 +-
 mysql-test/r/func_analyse.result              |   10 +-
 mysql-test/r/intersect.result                 |   18 +-
 mysql-test/r/join.result                      |    2 +-
 mysql-test/r/parser.result                    |   33 +-
 mysql-test/r/sp.result                        |    2 +-
 mysql-test/r/subselect.result                 |    6 +-
 mysql-test/r/subselect_no_exists_to_in.result |    6 +-
 mysql-test/r/subselect_no_mat.result          |    6 +-
 mysql-test/r/subselect_no_opts.result         |    6 +-
 mysql-test/r/subselect_no_scache.result       |    6 +-
 mysql-test/r/subselect_no_semijoin.result     |    6 +-
 mysql-test/r/test.result                      |  114 ++
 mysql-test/r/union.result                     |   10 +-
 mysql-test/t/except.test                      |    4 +-
 mysql-test/t/func_analyse.test                |    8 +-
 mysql-test/t/intersect.test                   |    4 +-
 mysql-test/t/parser.test                      |   17 +-
 mysql-test/t/sp.test                          |    2 +-
 mysql-test/t/subselect.test                   |   11 -
 mysql-test/t/test.test                        |   26 +
 mysql-test/t/union.test                       |    7 +-
 sql/events.cc                                 |    9 +-
 sql/item.cc                                   |   18 +-
 sql/item_subselect.cc                         |   18 +-
 sql/log_event.cc                              |    6 +-
 sql/opt_range.cc                              |    2 +-
 sql/opt_table_elimination.cc                  |    4 +-
 sql/set_var.cc                                |    2 +-
 sql/sp_head.cc                                |    2 +-
 sql/sp_rcontext.cc                            |   14 +-
 sql/sql_admin.cc                              |   18 +-
 sql/sql_alter.cc                              |    4 +-
 sql/sql_base.cc                               |    8 +-
 sql/sql_base.h                                |    6 +-
 sql/sql_cache.cc                              |    8 +-
 sql/sql_class.h                               |   10 +-
 sql/sql_cte.cc                                |    4 +-
 sql/sql_delete.cc                             |   32 +-
 sql/sql_derived.cc                            |    3 +-
 sql/sql_do.cc                                 |    2 +-
 sql/sql_error.cc                              |    2 +-
 sql/sql_help.cc                               |   11 +-
 sql/sql_insert.cc                             |   40 +-
 sql/sql_lex.cc                                |  825 ++++++++++--
 sql/sql_lex.h                                 |  237 +++-
 sql/sql_load.cc                               |    9 +-
 sql/sql_parse.cc                              |   93 +-
 sql/sql_partition.cc                          |    3 +-
 sql/sql_partition_admin.cc                    |    4 +-
 sql/sql_prepare.cc                            |   49 +-
 sql/sql_profile.cc                            |    4 +-
 sql/sql_select.cc                             |   22 +-
 sql/sql_sequence.cc                           |    4 +-
 sql/sql_show.cc                               |   27 +-
 sql/sql_table.cc                              |    6 +-
 sql/sql_truncate.cc                           |    2 +-
 sql/sql_union.cc                              |    2 +-
 sql/sql_update.cc                             |   30 +-
 sql/sql_view.cc                               |   39 +-
 sql/sql_yacc.yy                               | 1719 +++++++++++++++++++------
 sql/sql_yacc_ora.yy                           |  168 +--
 sql/structs.h                                 |   53 +
 sql/table.cc                                  |   29 +-
 sql/wsrep_mysqld.cc                           |    4 +-
 storage/mroonga/ha_mroonga.cpp                |    2 +-
 storage/spider/spd_db_mysql.cc                |    2 +-
 storage/tokudb/tokudb_dir_cmd.cc              |    4 +-
 69 files changed, 3018 insertions(+), 854 deletions(-)

diff --git a/mysql-test/r/except.result b/mysql-test/r/except.result
index fdaa625ea65..bf68be1b169 100644
--- a/mysql-test/r/except.result
+++ b/mysql-test/r/except.result
@@ -500,7 +500,7 @@ a
 (select 1 from dual) except (select 1 from dual);
 1
 (select 1 from dual into @v) except (select 1 from dual);
-ERROR HY000: Incorrect usage of EXCEPT and INTO
+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 'into @v) except (select 1 from dual)' at line 1
 select 1 from dual ORDER BY 1 except select 1 from dual;
 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 'except select 1 from dual' at line 1
 select 1 as a from dual union all select 1 from dual;
@@ -508,7 +508,7 @@ a
 1
 1
 select 1 from dual except all select 1 from dual;
-ERROR HY000: Incorrect usage of EXCEPT and ALL
+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 'all select 1 from dual' at line 1
 create table t1 (a int, b blob, a1 int, b1 blob) engine=MyISAM;
 create table t2 (c int, d blob, c1 int, d1 blob) engine=MyISAM;
 insert into t1 values (1,"ddd", 1, "sdfrrwwww"),(2, "fgh", 2, "dffggtt");
diff --git a/mysql-test/r/fulltext_order_by.result b/mysql-test/r/fulltext_order_by.result
index c2f57c6f9c2..db7e9b5157c 100644
--- a/mysql-test/r/fulltext_order_by.result
+++ b/mysql-test/r/fulltext_order_by.result
@@ -126,7 +126,7 @@ group by
 a.text, b.id, b.betreff
 order by 
 match(b.betreff) against ('+abc' in boolean mode) desc;
-ERROR 42000: Table 'b' from one of the SELECTs cannot be used in field list
+ERROR 42000: Table 'b' from one of the SELECTs cannot be used in global ORDER clause
 select a.text, b.id, b.betreff
 from 
 t2 a inner join t3 b on a.id = b.forum inner join
@@ -142,7 +142,7 @@ where
 match(c.beitrag) against ('+abc' in boolean mode)
 order by 
 match(b.betreff) against ('+abc' in boolean mode) desc;
-ERROR 42000: Table 'b' from one of the SELECTs cannot be used in field list
+ERROR 42000: Table 'b' from one of the SELECTs cannot be used in global ORDER clause
 select a.text, b.id, b.betreff
 from 
 t2 a inner join t3 b on a.id = b.forum inner join
diff --git a/mysql-test/r/func_analyse.result b/mysql-test/r/func_analyse.result
index 1e78e603bca..c38528de45e 100644
--- a/mysql-test/r/func_analyse.result
+++ b/mysql-test/r/func_analyse.result
@@ -153,13 +153,19 @@ End of 5.1 tests
 # Start of 10.2 tests
 #
 (SELECT 1 FROM DUAL PROCEDURE ANALYSE());
+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 'PROCEDURE ANALYSE())' at line 1
+((SELECT 1 FROM DUAL PROCEDURE ANALYSE()));
+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 'PROCEDURE ANALYSE()))' at line 1
+(SELECT 1 FROM DUAL) PROCEDURE ANALYSE();
 Field_name	Min_value	Max_value	Min_length	Max_length	Empties_or_zeros	Nulls	Avg_value_or_avg_length	Std	Optimal_fieldtype
 1	1	1	1	1	0	0	1.0000	0.0000	ENUM('1') NOT NULL
-((SELECT 1 FROM DUAL PROCEDURE ANALYSE()));
+((SELECT 1 FROM DUAL)) PROCEDURE ANALYSE();
 Field_name	Min_value	Max_value	Min_length	Max_length	Empties_or_zeros	Nulls	Avg_value_or_avg_length	Std	Optimal_fieldtype
 1	1	1	1	1	0	0	1.0000	0.0000	ENUM('1') NOT NULL
+create table t1 (a int);
 SELECT * FROM t1 UNION SELECT * FROM t1 PROCEDURE analyse();
-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 'PROCEDURE analyse()' at line 1
+a
+drop table t1;
 #
 # MDEV-10030 sql_yacc.yy: Split table_expression and remove PROCEDURE from create_select, select_paren_derived, select_derived2, query_specification
 #
diff --git a/mysql-test/r/intersect.result b/mysql-test/r/intersect.result
index 5dfb7fb6875..573d28caea5 100644
--- a/mysql-test/r/intersect.result
+++ b/mysql-test/r/intersect.result
@@ -497,7 +497,7 @@ a
 1
 1
 (select 1 from dual into @v) intersect (select 1 from dual);
-ERROR HY000: Incorrect usage of INTERSECT and INTO
+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 'into @v) intersect (select 1 from dual)' at line 1
 select 1 from dual ORDER BY 1 intersect select 1 from dual;
 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 'intersect select 1 from dual' at line 1
 select 1 as a from dual union all select 1 from dual;
@@ -505,7 +505,7 @@ a
 1
 1
 select 1 from dual intersect all select 1 from dual;
-ERROR HY000: Incorrect usage of INTERSECT and ALL
+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 'all select 1 from dual' at line 1
 create table t1 (a int, b blob, a1 int, b1 blob);
 create table t2 (c int, d blob, c1 int, d1 blob);
 insert into t1 values (1,"ddd", 1, "sdfrrwwww"),(2, "fgh", 2, "dffggtt");
@@ -599,14 +599,14 @@ explain extended
 (select a,b from t1) union (select c,d from t2) intersect (select e,f from t3) union (select 4,4);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
 1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	2	100.00	
-3	UNION	<derived2>	ALL	NULL	NULL	NULL	NULL	2	100.00	
+5	UNION	<derived2>	ALL	NULL	NULL	NULL	NULL	2	100.00	
 2	DERIVED	t2	ALL	NULL	NULL	NULL	NULL	2	100.00	
-4	INTERSECT	t3	ALL	NULL	NULL	NULL	NULL	2	100.00	
-NULL	INTERSECT RESULT	<intersect2,4>	ALL	NULL	NULL	NULL	NULL	NULL	NULL	
-5	UNION	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
-NULL	UNION RESULT	<union1,3,5>	ALL	NULL	NULL	NULL	NULL	NULL	NULL	
+3	INTERSECT	t3	ALL	NULL	NULL	NULL	NULL	2	100.00	
+NULL	INTERSECT RESULT	<intersect2,3>	ALL	NULL	NULL	NULL	NULL	NULL	NULL	
+4	UNION	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+NULL	UNION RESULT	<union1,5,4>	ALL	NULL	NULL	NULL	NULL	NULL	NULL	
 Warnings:
-Note	1003	(/* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1`) union /* select#3 */ select `__3`.`c` AS `c`,`__3`.`d` AS `d` from ((/* select#2 */ 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`)) `__3` union (/* select#5 */ select 4 AS `4`,4 AS `4`)
+Note	1003	(/* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1`) union /* select#5 */ select `__5`.`c` AS `c`,`__5`.`d` AS `d` from ((/* select#2 */ select `test`.`t2`.`c` AS `c`,`test`.`t2`.`d` AS `d` from `test`.`t2`) intersect (/* select#3 */ select `test`.`t3`.`e` AS `e`,`test`.`t3`.`f` AS `f` from `test`.`t3`)) `__5` union (/* select#4 */ select 4 AS `4`,4 AS `4`)
 (select e,f from t3) intersect (select c,d from t2) union (select a,b from t1) union (select 4,4);
 e	f
 3	3
@@ -686,6 +686,6 @@ 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 `__3`.`c` AS `c`,`__3`.`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`)) `__3` 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 all select `__3`.`c` AS `c`,`__3`.`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`) union (select 4 AS `4`,4 AS `4`)) `__3`	latin1	latin1_swedish_ci
 drop view v1;
 drop tables t1,t2,t3;
diff --git a/mysql-test/r/join.result b/mysql-test/r/join.result
index df48dbba605..a5d207d0364 100644
--- a/mysql-test/r/join.result
+++ b/mysql-test/r/join.result
@@ -1483,7 +1483,7 @@ DROP TABLE t1,t2,t3,t4,t5;
 # MDEV-4752: Segfault during parsing of illegal query
 #
 SELECT * FROM t5 JOIN (t1 JOIN t2 UNION SELECT * FROM t3 JOIN t4);
-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 'SELECT * FROM t3 JOIN t4)' 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 'UNION SELECT * FROM t3 JOIN t4)' at line 1
 #
 # MDEV-4959: join of const table with NULL fields
 #
diff --git a/mysql-test/r/parser.result b/mysql-test/r/parser.result
index f197fbe6a19..7f45a8d4cae 100644
--- a/mysql-test/r/parser.result
+++ b/mysql-test/r/parser.result
@@ -705,8 +705,11 @@ FOR UPDATE;
 1
 1
 SELECT 1 FROM DUAL WHERE 1 GROUP BY 1 HAVING 1 ORDER BY 1
-PROCEDURE ANALYSE() FOR UPDATE;
+PROCEDURE ANALYSE();
 ERROR HY000: Can't use ORDER clause with this procedure
+SELECT 1 FROM DUAL WHERE 1 GROUP BY 1 HAVING 1 ORDER BY 1
+PROCEDURE ANALYSE() FOR UPDATE;
+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 'FOR UPDATE' at line 2
 SELECT 1 FROM
 (SELECT 1 FROM DUAL WHERE 1 GROUP BY 1 HAVING 1 ORDER BY 1
 FOR UPDATE) a;
@@ -734,7 +737,7 @@ SELECT 1 FROM t1
 UNION
 SELECT 1 FROM DUAL WHERE 1 GROUP BY 1 HAVING 1 ORDER BY 1
 PROCEDURE ANALYSE() FOR UPDATE;
-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 'PROCEDURE ANALYSE() FOR UPDATE' at line 4
+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 'FOR UPDATE' at line 4
 SELECT 1 FROM DUAL PROCEDURE ANALYSE() 
 UNION
 SELECT 1 FROM t1;
@@ -794,7 +797,7 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp
 SELECT 1 FROM t1 INTO @var17727401 UNION SELECT 1 FROM t1 INTO 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 1 FROM t1 INTO t1' at line 1
 (SELECT 1 FROM t1 INTO @var17727401) UNION (SELECT 1 FROM t1 INTO t1);
-ERROR HY000: Incorrect usage of UNION and INTO
+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 'INTO @var17727401) UNION (SELECT 1 FROM t1 INTO t1)' at line 1
 SELECT 1 FROM t1 UNION SELECT 1 FROM t1 INTO @var17727401;
 Warnings:
 Warning	1329	No data - zero rows fetched, selected, or processed
@@ -808,17 +811,17 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp
 (SELECT 1 FROM t1 LIMIT 1) LIMIT 1;
 1
 ((SELECT 1 FROM t1 ORDER BY 1) ORDER BY 1) ORDER BY 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 'ORDER BY 1) ORDER BY 1' at line 1
+1
 ((SELECT 1 FROM t1 LIMIT 1) LIMIT 1) LIMIT 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 'LIMIT 1) LIMIT 1' at line 1
+1
 (SELECT 1 FROM t1 ORDER BY 1) LIMIT 1;
 1
 (SELECT 1 FROM t1 LIMIT 1) ORDER BY 1;
 1
 ((SELECT 1 FROM t1 ORDER BY 1) LIMIT 1) ORDER BY 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 'LIMIT 1) ORDER BY 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 1 FROM t1 LIMIT 1) ORDER BY 1) LIMIT 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 'ORDER BY 1) LIMIT 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 1 FROM t1 UNION SELECT 1 FROM t1 ORDER BY 1;
 1
 SELECT (SELECT 1 FROM t1 UNION SELECT 1 FROM t1 ORDER BY 1);
@@ -1265,19 +1268,27 @@ CREATE TABLE t1 (i INT);
 (SELECT * FROM t1 PROCEDURE ANALYSE(10, 10))
 UNION
 (SELECT * FROM t1 PROCEDURE ANALYSE(10, 10));
-ERROR HY000: Incorrect usage of UNION and SELECT ... PROCEDURE ANALYSE()
+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 'PROCEDURE ANALYSE(10, 10))
+UNION
+(SELECT * FROM t1 PROCEDURE ANALYSE(10, 10))' at line 1
 (SELECT * FROM t1 PROCEDURE ANALYSE(10, 10))
 UNION
 SELECT * FROM t1 PROCEDURE ANALYSE(10, 10);
-ERROR HY000: Incorrect usage of UNION and SELECT ... PROCEDURE ANALYSE()
+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 'PROCEDURE ANALYSE(10, 10))
+UNION
+SELECT * FROM t1 PROCEDURE ANALYSE(10, 10)' at line 1
 (SELECT * FROM t1 PROCEDURE ANALYSE(10, 10))
 UNION
 (SELECT 1);
-ERROR HY000: Incorrect usage of UNION and SELECT ... PROCEDURE ANALYSE()
+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 'PROCEDURE ANALYSE(10, 10))
+UNION
+(SELECT 1)' at line 1
 (SELECT * FROM t1 PROCEDURE ANALYSE(10, 10))
 UNION
 SELECT 1;
-ERROR HY000: Incorrect usage of UNION and SELECT ... PROCEDURE ANALYSE()
+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 'PROCEDURE ANALYSE(10, 10))
+UNION
+SELECT 1' at line 1
 SELECT * FROM t1 PROCEDURE ANALYSE(10, 10)
 UNION
 (SELECT * FROM t1 PROCEDURE ANALYSE(10, 10));
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index cb2237699fb..6bf44d24089 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -314,7 +314,7 @@ delete from t1|
 drop procedure b|
 drop procedure if exists b2|
 create procedure b2(x int)
-repeat(select 1 into outfile 'b2');
+repeat(select 1) into outfile 'b2';
 insert into test.t1 values (repeat("b2",3), x);
 set x = x-1;
 until x = 0 end repeat|
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result
index 919693efffb..41fca2056e4 100644
--- a/mysql-test/r/subselect.result
+++ b/mysql-test/r/subselect.result
@@ -5291,9 +5291,11 @@ SELECT ( SELECT a FROM t1 WHERE a = 1 UNION SELECT 1 ), a FROM t1;
 SELECT * FROM t2 WHERE (a, b) IN (SELECT a, b FROM t2);
 a	b
 SELECT 1 UNION ( SELECT 1 UNION SELECT 1 );
-ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'UNION SELECT 1 )' at line 1
+1
+1
 ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1;
-ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'UNION SELECT 1 ) UNION SELECT 1' at line 1
+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
 SELECT ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1;
diff --git a/mysql-test/r/subselect_no_exists_to_in.result b/mysql-test/r/subselect_no_exists_to_in.result
index 806475b3380..94fc8c364fe 100644
--- a/mysql-test/r/subselect_no_exists_to_in.result
+++ b/mysql-test/r/subselect_no_exists_to_in.result
@@ -5293,9 +5293,11 @@ SELECT ( SELECT a FROM t1 WHERE a = 1 UNION SELECT 1 ), a FROM t1;
 SELECT * FROM t2 WHERE (a, b) IN (SELECT a, b FROM t2);
 a	b
 SELECT 1 UNION ( SELECT 1 UNION SELECT 1 );
-ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'UNION SELECT 1 )' at line 1
+1
+1
 ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1;
-ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'UNION SELECT 1 ) UNION SELECT 1' at line 1
+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
 SELECT ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1;
diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result
index 237a6dbf9bb..473f2a2750e 100644
--- a/mysql-test/r/subselect_no_mat.result
+++ b/mysql-test/r/subselect_no_mat.result
@@ -5291,9 +5291,11 @@ SELECT ( SELECT a FROM t1 WHERE a = 1 UNION SELECT 1 ), a FROM t1;
 SELECT * FROM t2 WHERE (a, b) IN (SELECT a, b FROM t2);
 a	b
 SELECT 1 UNION ( SELECT 1 UNION SELECT 1 );
-ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'UNION SELECT 1 )' at line 1
+1
+1
 ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1;
-ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'UNION SELECT 1 ) UNION SELECT 1' at line 1
+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
 SELECT ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1;
diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result
index af1afe47f32..7ec9eddd812 100644
--- a/mysql-test/r/subselect_no_opts.result
+++ b/mysql-test/r/subselect_no_opts.result
@@ -5287,9 +5287,11 @@ SELECT ( SELECT a FROM t1 WHERE a = 1 UNION SELECT 1 ), a FROM t1;
 SELECT * FROM t2 WHERE (a, b) IN (SELECT a, b FROM t2);
 a	b
 SELECT 1 UNION ( SELECT 1 UNION SELECT 1 );
-ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'UNION SELECT 1 )' at line 1
+1
+1
 ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1;
-ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'UNION SELECT 1 ) UNION SELECT 1' at line 1
+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
 SELECT ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1;
diff --git a/mysql-test/r/subselect_no_scache.result b/mysql-test/r/subselect_no_scache.result
index 75be8642069..23262c8cf74 100644
--- a/mysql-test/r/subselect_no_scache.result
+++ b/mysql-test/r/subselect_no_scache.result
@@ -5297,9 +5297,11 @@ SELECT ( SELECT a FROM t1 WHERE a = 1 UNION SELECT 1 ), a FROM t1;
 SELECT * FROM t2 WHERE (a, b) IN (SELECT a, b FROM t2);
 a	b
 SELECT 1 UNION ( SELECT 1 UNION SELECT 1 );
-ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'UNION SELECT 1 )' at line 1
+1
+1
 ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1;
-ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'UNION SELECT 1 ) UNION SELECT 1' at line 1
+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
 SELECT ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1;
diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result
index a6a6397375b..17cbfb4f30b 100644
--- a/mysql-test/r/subselect_no_semijoin.result
+++ b/mysql-test/r/subselect_no_semijoin.result
@@ -5287,9 +5287,11 @@ SELECT ( SELECT a FROM t1 WHERE a = 1 UNION SELECT 1 ), a FROM t1;
 SELECT * FROM t2 WHERE (a, b) IN (SELECT a, b FROM t2);
 a	b
 SELECT 1 UNION ( SELECT 1 UNION SELECT 1 );
-ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'UNION SELECT 1 )' at line 1
+1
+1
 ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1;
-ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'UNION SELECT 1 ) UNION SELECT 1' at line 1
+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
 SELECT ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1;
diff --git a/mysql-test/r/test.result b/mysql-test/r/test.result
new file mode 100644
index 00000000000..5f4d08d9d01
--- /dev/null
+++ b/mysql-test/r/test.result
@@ -0,0 +1,114 @@
+select 1 union ( select 2 union select 3);
+1
+1
+2
+3
+explain extended
+select 1 union ( select 2 union select 3);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	PRIMARY	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+4	UNION	<derived2>	ALL	NULL	NULL	NULL	NULL	2	100.00	
+2	DERIVED	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+3	UNION	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+NULL	UNION RESULT	<union2,3>	ALL	NULL	NULL	NULL	NULL	NULL	NULL	
+NULL	UNION RESULT	<union1,4>	ALL	NULL	NULL	NULL	NULL	NULL	NULL	
+Warnings:
+Note	1003	/* select#1 */ select 1 AS `1` union /* select#4 */ select `__4`.`2` AS `2` from (/* select#2 */ select 2 AS `2` union /* select#3 */ select 3 AS `3`) `__4`
+select 1 union ( select 1 union select 1);
+1
+1
+explain extended
+select 1 union ( select 1 union select 1);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	PRIMARY	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+4	UNION	<derived2>	ALL	NULL	NULL	NULL	NULL	2	100.00	
+2	DERIVED	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+3	UNION	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+NULL	UNION RESULT	<union2,3>	ALL	NULL	NULL	NULL	NULL	NULL	NULL	
+NULL	UNION RESULT	<union1,4>	ALL	NULL	NULL	NULL	NULL	NULL	NULL	
+Warnings:
+Note	1003	/* select#1 */ select 1 AS `1` union /* select#4 */ select `__4`.`1` AS `1` from (/* select#2 */ select 1 AS `1` union /* select#3 */ select 1 AS `1`) `__4`
+select 1 union all ( select 1 union select 1);
+1
+1
+explain extended
+select 1 union all ( select 1 union select 1);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	PRIMARY	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+4	UNION	<derived2>	ALL	NULL	NULL	NULL	NULL	2	100.00	
+2	DERIVED	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+3	UNION	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+NULL	UNION RESULT	<union2,3>	ALL	NULL	NULL	NULL	NULL	NULL	NULL	
+NULL	UNION RESULT	<union1,4>	ALL	NULL	NULL	NULL	NULL	NULL	NULL	
+Warnings:
+Note	1003	/* select#1 */ select 1 AS `1` union /* select#4 */ select `__4`.`1` AS `1` from (/* select#2 */ select 1 AS `1` union /* select#3 */ select 1 AS `1`) `__4`
+select 1 union ( select 1 union all select 1);
+1
+1
+explain extended
+select 1 union ( select 1 union all select 1);
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	PRIMARY	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+4	UNION	<derived2>	ALL	NULL	NULL	NULL	NULL	2	100.00	
+2	DERIVED	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+3	UNION	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+NULL	UNION RESULT	<union1,4>	ALL	NULL	NULL	NULL	NULL	NULL	NULL	
+Warnings:
+Note	1003	/* select#1 */ select 1 AS `1` union /* select#4 */ select `__4`.`1` AS `1` from (/* select#2 */ select 1 AS `1` union all /* select#3 */ select 1 AS `1`) `__4`
+select 1 union select 1 union all select 1;
+1
+1
+1
+explain extended
+select 1 union select 1 union all select 1;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	PRIMARY	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+2	UNION	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+3	UNION	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+NULL	UNION RESULT	<union1,2,3>	ALL	NULL	NULL	NULL	NULL	NULL	NULL	
+Warnings:
+Note	1003	/* select#1 */ select 1 AS `1` union /* select#2 */ select 1 AS `1` union all /* select#3 */ select 1 AS `1`
+(select 1 as a) union (select 2) order by a;
+a
+1
+2
+explain extended
+(select 1 as a) union (select 2) order by a;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	PRIMARY	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+2	UNION	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+NULL	UNION RESULT	<union1,2>	ALL	NULL	NULL	NULL	NULL	NULL	NULL	Using filesort
+Warnings:
+Note	1003	(/* select#1 */ select 1 AS `a`) union (/* select#2 */ select 2 AS `2`) order by `a`
+/* select#1 */ select 1 AS `a` union /* select#2 */ select 2 AS `2` order by `a`;
+a
+1
+2
+explain extended
+/* select#1 */ select 1 AS `a` union /* select#2 */ select 2 AS `2` order by `a`;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	PRIMARY	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+2	UNION	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+NULL	UNION RESULT	<union1,2>	ALL	NULL	NULL	NULL	NULL	NULL	NULL	Using filesort
+Warnings:
+Note	1003	/* select#1 */ select 1 AS `a` union /* select#2 */ select 2 AS `2` order by `a`
+select 1 union ( select 1 union (select 1 union (select 1 union select 1)));
+1
+1
+explain extended all
+select 1 union ( select 1 union (select 1 union (select 1 union select 1)));
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	filtered	Extra
+1	PRIMARY	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+8	UNION	<derived2>	ALL	NULL	NULL	NULL	NULL	2	100.00	
+2	DERIVED	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+7	UNION	<derived3>	ALL	NULL	NULL	NULL	NULL	2	100.00	
+3	DERIVED	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+6	UNION	<derived4>	ALL	NULL	NULL	NULL	NULL	2	100.00	
+4	DERIVED	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+5	UNION	NULL	NULL	NULL	NULL	NULL	NULL	NULL	NULL	No tables used
+NULL	UNION RESULT	<union4,5>	ALL	NULL	NULL	NULL	NULL	NULL	NULL	
+NULL	UNION RESULT	<union3,6>	ALL	NULL	NULL	NULL	NULL	NULL	NULL	
+NULL	UNION RESULT	<union2,7>	ALL	NULL	NULL	NULL	NULL	NULL	NULL	
+NULL	UNION RESULT	<union1,8>	ALL	NULL	NULL	NULL	NULL	NULL	NULL	
+Warnings:
+Note	1003	/* select#1/0 Filter Select: select `1` AS `1` */ select 1 AS `1` union /* select#8/0 */ select `__8`.`1` AS `1` from (/* select#2/1 Filter Select: select `1` AS `1` */ select 1 AS `1` union /* select#7/1 */ select `__7`.`1` AS `1` from (/* select#3/2 Filter Select: select `1` AS `1` */ select 1 AS `1` union /* select#6/2 */ select `__6`.`1` AS `1` from (/* select#4/3 Filter Select: select `1` AS `1` */ select 1 AS `1` union /* select#5/3 */ select 1 AS `1`) `__6`) `__7`) `__8`
diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result
index b193f032146..20cc895e476 100644
--- a/mysql-test/r/union.result
+++ b/mysql-test/r/union.result
@@ -494,7 +494,7 @@ drop temporary table t1;
 create table t1 select a from t1 union select a from t2;
 ERROR 42S01: Table 't1' already exists
 select a from t1 union select a from t2 order by t2.a;
-ERROR 42000: Table 't2' from one of the SELECTs cannot be used in field list
+ERROR 42000: Table 't2' from one of the SELECTs cannot be used in global ORDER clause
 drop table t1,t2;
 select length(version()) > 1 as `*` UNION select 2;
 *
@@ -1532,13 +1532,11 @@ SELECT a FROM (SELECT a FROM t1 UNION SELECT a FROM t1 ORDER BY c) AS test;
 ERROR 42S22: Unknown column 'c' in 'order clause'
 DROP TABLE t1;
 (select 1 into @var) union (select 1);
-ERROR HY000: Incorrect usage of UNION and INTO
+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 'into @var) union (select 1)' at line 1
 (select 1) union (select 1 into @var);
-select @var;
- at var
-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 'into @var)' at line 1
 (select 2) union (select 1 into @var);
-ERROR 42000: Result consisted of more than one row
+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 'into @var)' at line 1
 CREATE TABLE t1 (a int);
 INSERT INTO t1 VALUES (10), (20);
 CREATE TABLE t2 (b int);
diff --git a/mysql-test/t/except.test b/mysql-test/t/except.test
index e13137701a9..b34141ec568 100644
--- a/mysql-test/t/except.test
+++ b/mysql-test/t/except.test
@@ -60,13 +60,13 @@ drop tables t1,t2,t3,t4;
 
 select 1 as a from dual except select 1 from dual;
 (select 1 from dual) except (select 1 from dual);
---error ER_WRONG_USAGE
+--error ER_PARSE_ERROR
 (select 1 from dual into @v) except (select 1 from dual);
 --error ER_PARSE_ERROR
 select 1 from dual ORDER BY 1 except select 1 from dual;
 
 select 1 as a from dual union all select 1 from dual;
---error ER_WRONG_USAGE
+--error ER_PARSE_ERROR
 select 1 from dual except all select 1 from dual;
 
 
diff --git a/mysql-test/t/func_analyse.test b/mysql-test/t/func_analyse.test
index d99f5c0fa9a..9e5ea94a507 100644
--- a/mysql-test/t/func_analyse.test
+++ b/mysql-test/t/func_analyse.test
@@ -161,12 +161,16 @@ DROP TABLE t1, t2;
 --echo #
 --echo # Start of 10.2 tests
 --echo #
+--error ER_PARSE_ERROR
 (SELECT 1 FROM DUAL PROCEDURE ANALYSE());
+--error ER_PARSE_ERROR
 ((SELECT 1 FROM DUAL PROCEDURE ANALYSE()));
+(SELECT 1 FROM DUAL) PROCEDURE ANALYSE();
+((SELECT 1 FROM DUAL)) PROCEDURE ANALYSE();
 
-# TODO:
---error ER_PARSE_ERROR
+create table t1 (a int);
 SELECT * FROM t1 UNION SELECT * FROM t1 PROCEDURE analyse();
+drop table t1;
 
 --echo #
 --echo # MDEV-10030 sql_yacc.yy: Split table_expression and remove PROCEDURE from create_select, select_paren_derived, select_derived2, query_specification
diff --git a/mysql-test/t/intersect.test b/mysql-test/t/intersect.test
index 6028b2fa498..29e6a058f04 100644
--- a/mysql-test/t/intersect.test
+++ b/mysql-test/t/intersect.test
@@ -59,13 +59,13 @@ drop tables t1,t2,t3;
 
 select 1 as a from dual intersect select 1 from dual;
 (select 1 from dual) intersect (select 1 from dual);
---error ER_WRONG_USAGE
+--error ER_PARSE_ERROR
 (select 1 from dual into @v) intersect (select 1 from dual);
 --error ER_PARSE_ERROR
 select 1 from dual ORDER BY 1 intersect select 1 from dual;
 
 select 1 as a from dual union all select 1 from dual;
---error ER_WRONG_USAGE
+--error ER_PARSE_ERROR
 select 1 from dual intersect all select 1 from dual;
 
 
diff --git a/mysql-test/t/parser.test b/mysql-test/t/parser.test
index 98eaa7a7774..ff05bf951b6 100644
--- a/mysql-test/t/parser.test
+++ b/mysql-test/t/parser.test
@@ -825,6 +825,9 @@ SELECT 1 FROM DUAL WHERE 1 GROUP BY 1 HAVING 1 ORDER BY 1
   FOR UPDATE;
 
 --error ER_ORDER_WITH_PROC
+SELECT 1 FROM DUAL WHERE 1 GROUP BY 1 HAVING 1 ORDER BY 1
+  PROCEDURE ANALYSE();
+--error ER_PARSE_ERROR
 SELECT 1 FROM DUAL WHERE 1 GROUP BY 1 HAVING 1 ORDER BY 1
   PROCEDURE ANALYSE() FOR UPDATE;
 
@@ -916,7 +919,7 @@ SELECT EXISTS(SELECT 1 FROM t1 INTO @var17727401);
 
 --error ER_PARSE_ERROR
 SELECT 1 FROM t1 INTO @var17727401 UNION SELECT 1 FROM t1 INTO t1;
---error ER_WRONG_USAGE
+--error ER_PARSE_ERROR
 (SELECT 1 FROM t1 INTO @var17727401) UNION (SELECT 1 FROM t1 INTO t1);
 
 SELECT 1 FROM t1 UNION SELECT 1 FROM t1 INTO @var17727401;
@@ -934,9 +937,9 @@ SELECT 1 FROM t1 PROCEDURE ANALYSE() INTO @var17727401;
 (SELECT 1 FROM t1 ORDER BY 1) ORDER BY 1;
 (SELECT 1 FROM t1 LIMIT 1) LIMIT 1;
 
---error ER_PARSE_ERROR
+#--error ER_PARSE_ERROR
 ((SELECT 1 FROM t1 ORDER BY 1) ORDER BY 1) ORDER BY 1;
---error ER_PARSE_ERROR
+#--error ER_PARSE_ERROR
 ((SELECT 1 FROM t1 LIMIT 1) LIMIT 1) LIMIT 1;
 
 (SELECT 1 FROM t1 ORDER BY 1) LIMIT 1;
@@ -1276,22 +1279,22 @@ DROP TABLE t1;
 --echo #
 
 CREATE TABLE t1 (i INT);
---error ER_WRONG_USAGE
+--error ER_PARSE_ERROR
 (SELECT * FROM t1 PROCEDURE ANALYSE(10, 10))
 UNION
 (SELECT * FROM t1 PROCEDURE ANALYSE(10, 10));
 
---error ER_WRONG_USAGE
+--error ER_PARSE_ERROR
 (SELECT * FROM t1 PROCEDURE ANALYSE(10, 10))
 UNION
 SELECT * FROM t1 PROCEDURE ANALYSE(10, 10);
 
---error ER_WRONG_USAGE
+--error ER_PARSE_ERROR
 (SELECT * FROM t1 PROCEDURE ANALYSE(10, 10))
 UNION
 (SELECT 1);
 
---error ER_WRONG_USAGE
+--error ER_PARSE_ERROR
 (SELECT * FROM t1 PROCEDURE ANALYSE(10, 10))
 UNION
 SELECT 1;
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index 94d779de203..cb3c3d568ea 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -440,7 +440,7 @@ drop procedure b|
 drop procedure if exists b2|
 --enable_warnings
 create procedure b2(x int)
-repeat(select 1 into outfile 'b2');
+repeat(select 1) into outfile 'b2';
   insert into test.t1 values (repeat("b2",3), x);
   set x = x-1;
 until x = 0 end repeat|
diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test
index 7412eae8ecf..779f65235e6 100644
--- a/mysql-test/t/subselect.test
+++ b/mysql-test/t/subselect.test
@@ -2606,8 +2606,6 @@ SELECT sql_no_cache * FROM t1 WHERE NOT EXISTS
    (SELECT i FROM t1)
   );
 
-#TODO:not supported
---error ER_PARSE_ERROR
 SELECT * FROM t1
 WHERE NOT EXISTS (((SELECT i FROM t1) UNION (SELECT i FROM t1)));
 
@@ -4393,12 +4391,9 @@ SELECT * FROM t2 WHERE (a, b) IN (SELECT a, b FROM t2);
 
 # Make sure the parser does not allow nested UNIONs anywhere
 
---error ER_PARSE_ERROR
 SELECT 1 UNION ( SELECT 1 UNION SELECT 1 );
---error ER_PARSE_ERROR
 ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1;
 
---error ER_PARSE_ERROR
 SELECT ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) );
 --error ER_PARSE_ERROR
 SELECT ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1;
@@ -4412,20 +4407,14 @@ SELECT * FROM ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 );
 SELECT * FROM ( ( SELECT 1 UNION SELECT 1 ) UNION SELECT 1 ) a;
 SELECT * FROM ( SELECT 1 UNION SELECT 1 UNION SELECT 1 ) a;
 
---error ER_PARSE_ERROR
 SELECT * FROM t1 WHERE a =     ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) );
---error ER_PARSE_ERROR
 SELECT * FROM t1 WHERE a = ALL ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) );
---error ER_PARSE_ERROR
 SELECT * FROM t1 WHERE a = ANY ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) );
---error ER_PARSE_ERROR
 SELECT * FROM t1 WHERE a IN    ( SELECT 1 UNION ( SELECT 1 UNION SELECT 1 ) );
 
 --error ER_PARSE_ERROR
 SELECT * FROM t1 WHERE a =     ( ( SELECT 1 UNION SELECT 1 )  UNION SELECT 1 );
---error ER_PARSE_ERROR
 SELECT * FROM t1 WHERE a = ALL ( ( SELECT 1 UNION SELECT 1 )  UNION SELECT 1 );
---error ER_PARSE_ERROR
 SELECT * FROM t1 WHERE a = ANY ( ( SELECT 1 UNION SELECT 1 )  UNION SELECT 1 );
 --error ER_PARSE_ERROR
 SELECT * FROM t1 WHERE a IN    ( ( SELECT 1 UNION SELECT 1 )  UNION SELECT 1 );
diff --git a/mysql-test/t/test.test b/mysql-test/t/test.test
new file mode 100644
index 00000000000..3a4534dcf94
--- /dev/null
+++ b/mysql-test/t/test.test
@@ -0,0 +1,26 @@
+select 1 union ( select 2 union select 3);
+explain extended
+select 1 union ( select 2 union select 3);
+select 1 union ( select 1 union select 1);
+explain extended
+select 1 union ( select 1 union select 1);
+select 1 union all ( select 1 union select 1);
+explain extended
+select 1 union all ( select 1 union select 1);
+select 1 union ( select 1 union all select 1);
+explain extended
+select 1 union ( select 1 union all select 1);
+select 1 union select 1 union all select 1;
+explain extended
+select 1 union select 1 union all select 1;
+
+(select 1 as a) union (select 2) order by a;
+explain extended
+(select 1 as a) union (select 2) order by a;
+/* select#1 */ select 1 AS `a` union /* select#2 */ select 2 AS `2` order by `a`;
+explain extended
+/* select#1 */ select 1 AS `a` union /* select#2 */ select 2 AS `2` order by `a`;
+
+select 1 union ( select 1 union (select 1 union (select 1 union select 1)));
+explain extended all
+select 1 union ( select 1 union (select 1 union (select 1 union select 1)));
diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test
index a2e1fd09ade..c299505a8df 100644
--- a/mysql-test/t/union.test
+++ b/mysql-test/t/union.test
@@ -973,12 +973,13 @@ DROP TABLE t1;
 
 #
 # Bug#23345: Wrongly allowed INTO in a non-last select of a UNION.
+# (fixed)
 #
---error 1221
+--error ER_PARSE_ERROR
 (select 1 into @var) union (select 1);
+--error ER_PARSE_ERROR
 (select 1) union (select 1 into @var);
-select @var;
---error 1172
+--error ER_PARSE_ERROR
 (select 2) union (select 1 into @var);
 
 #
diff --git a/sql/events.cc b/sql/events.cc
index 9ecc55fbdf0..9879a32c0a9 100644
--- a/sql/events.cc
+++ b/sql/events.cc
@@ -807,12 +807,13 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
   */
   if (thd->lex->sql_command == SQLCOM_SHOW_EVENTS)
   {
-    DBUG_ASSERT(thd->lex->select_lex.db);
-    if (!is_infoschema_db(thd->lex->select_lex.db) && // There is no events in I_S
-        check_access(thd, EVENT_ACL, thd->lex->select_lex.db,
+    DBUG_ASSERT(thd->lex->first_select_lex()->db);
+    if (!is_infoschema_db(thd->lex->first_select_lex()->db) && // There is no events in I_S
+        check_access(thd, EVENT_ACL, thd->lex->first_select_lex()->db,
                      NULL, NULL, 0, 0))
       DBUG_RETURN(1);
-    db= normalize_db_name(thd->lex->select_lex.db, db_tmp, sizeof(db_tmp));
+    db= normalize_db_name(thd->lex->first_select_lex()->db, db_tmp,
+                          sizeof(db_tmp));
   }
   ret= db_repository->fill_schema_events(thd, tables, db);
 
diff --git a/sql/item.cc b/sql/item.cc
index 92459bd6f7f..9b2e37cbce3 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -738,7 +738,13 @@ Item_ident::Item_ident(THD *thd, Name_resolution_context *context_arg,
    alias_name_used(FALSE), cached_field_index(NO_CACHED_FIELD_INDEX),
    cached_table(0), depended_from(0), can_be_depended(TRUE)
 {
+  DBUG_ENTER("Item_ident::Item_ident");
+  DBUG_PRINT("XXX", ("Name: %s  cur sel: %p (%d)", field_name.str,
+                     thd->lex->current_select,
+                     (thd->lex->current_select ?
+                      thd->lex->current_select->select_number : 0)));
   name= *field_name_arg;
+  DBUG_VOID_RETURN;
 }
 
 
@@ -747,13 +753,17 @@ Item_ident::Item_ident(THD *thd, TABLE_LIST *view_arg,
   :Item_result_field(thd), orig_db_name(NullS),
    orig_table_name(view_arg->table_name),
    orig_field_name(*field_name_arg),
-   context(&view_arg->view->select_lex.context),
+   /* TODO: suspicious use of first_select_lex */
+   context(&view_arg->view->first_select_lex()->context),
    db_name(NullS), table_name(view_arg->alias),
    field_name(*field_name_arg),
    alias_name_used(FALSE), cached_field_index(NO_CACHED_FIELD_INDEX),
    cached_table(NULL), depended_from(NULL), can_be_depended(TRUE)
 {
+  DBUG_ENTER("Item_ident::Item_ident");
+  DBUG_PRINT("XXX", ("Name: %s", field_name.str));
   name= *field_name_arg;
+  DBUG_VOID_RETURN;
 }
 
 
@@ -775,7 +785,11 @@ Item_ident::Item_ident(THD *thd, Item_ident *item)
    cached_table(item->cached_table),
    depended_from(item->depended_from),
    can_be_depended(item->can_be_depended)
-{}
+{
+  DBUG_ENTER("Item_ident::Item_ident");
+  DBUG_PRINT("XXX", ("Name: %s", field_name.str));
+  DBUG_VOID_RETURN;
+}
 
 void Item_ident::cleanup()
 {
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 55196b451de..7f2371d6955 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -123,13 +123,6 @@ void Item_subselect::init(st_select_lex *select_lex,
     else
       engine= new subselect_single_select_engine(select_lex, result, this);
   }
-  {
-    SELECT_LEX *upper= unit->outer_select();
-    if (upper->parsing_place == IN_HAVING)
-      upper->subquery_in_having= 1;
-    /* The subquery is an expression cache candidate */
-    upper->expr_cache_may_be_used[upper->parsing_place]= TRUE;
-  }
   DBUG_PRINT("info", ("engine: 0x%lx", (ulong)engine));
   DBUG_VOID_RETURN;
 }
@@ -219,7 +212,8 @@ Item_subselect::~Item_subselect()
   if (own_engine)
     delete engine;
   else
-    engine->cleanup();
+    if (engine)  // can be empty in case of EOM
+      engine->cleanup();
   engine= NULL;
   DBUG_VOID_RETURN;
 }
@@ -243,6 +237,14 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref)
 
   DBUG_ASSERT(unit->thd == thd);
 
+  {
+    SELECT_LEX *upper= unit->outer_select();
+    if (upper->parsing_place == IN_HAVING)
+      upper->subquery_in_having= 1;
+    /* The subquery is an expression cache candidate */
+    upper->expr_cache_may_be_used[upper->parsing_place]= TRUE;
+  }
+
   status_var_increment(thd_param->status_var.feature_subquery);
 
   DBUG_ASSERT(fixed == 0);
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 73987a562fa..f9b24d1f544 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -4083,7 +4083,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
         have to use the transactional cache to ensure we don't
         calculate any checksum for the CREATE part.
       */
-      trx_cache= (lex->select_lex.item_list.elements &&
+      trx_cache= (lex->first_select_lex()->item_list.elements &&
                   thd->is_current_stmt_binlog_format_row()) ||
                   (thd->variables.option_bits & OPTION_GTID_BEGIN);
       use_cache= (lex->tmp_table() &&
@@ -6970,8 +6970,8 @@ int Load_log_event::do_apply_event(NET* net, rpl_group_info *rgi,
 
       ex.skip_lines = skip_lines;
       List<Item> field_list;
-      thd->lex->select_lex.context.resolve_in_table_list_only(&tables);
-      set_fields(tables.db, field_list, &thd->lex->select_lex.context);
+      thd->lex->first_select_lex()->context.resolve_in_table_list_only(&tables);
+      set_fields(tables.db, field_list, &thd->lex->first_select_lex()->context);
       thd->variables.pseudo_thread_id= thread_id;
       if (net)
       {
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 01aff0a9e7d..3859a81e528 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -4535,7 +4535,7 @@ double get_sweep_read_cost(const PARAM *param, ha_rows records)
     if (max_cost != DBL_MAX  && (busy_blocks+index_reads_cost) >= n_blocks)
       return 1;
     */
-    JOIN *join= param->thd->lex->select_lex.join;
+    JOIN *join= param->thd->lex->first_select_lex()->join;
     if (!join || join->table_count == 1)
     {
       /* No join, assume reading is done in one 'sweep' */
diff --git a/sql/opt_table_elimination.cc b/sql/opt_table_elimination.cc
index 1d6fb4dabfe..b723385bc0a 100644
--- a/sql/opt_table_elimination.cc
+++ b/sql/opt_table_elimination.cc
@@ -617,7 +617,7 @@ void eliminate_tables(JOIN *join)
     we should also take into account tables mentioned in "val".
   */
   if (join->thd->lex->sql_command == SQLCOM_INSERT_SELECT &&
-      join->select_lex == &thd->lex->select_lex)
+      join->select_lex == thd->lex->first_select_lex())
   {
     List_iterator<Item> val_it(thd->lex->value_list);
     while ((item= val_it++))
@@ -640,7 +640,7 @@ void eliminate_tables(JOIN *join)
       used_tables |= (*(cur_list->item))->used_tables();
   }
   
-  if (join->select_lex == &thd->lex->select_lex)
+  if (join->select_lex == thd->lex->first_select_lex())
   {
 
     /* Multi-table UPDATE: don't eliminate tables referred from SET statement */
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 311b33bc0dd..bf80a836b9c 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -741,7 +741,7 @@ int sql_set_variables(THD *thd, List<set_var_base> *var_list, bool free)
 
 err:
   if (free)
-    free_underlaid_joins(thd, &thd->lex->select_lex);
+    free_underlaid_joins(thd, thd->lex->first_select_lex());
   DBUG_RETURN(error);
 }
 
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 5bd4ff95f9c..b5f46774a36 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -303,7 +303,7 @@ sp_get_flags_for_command(LEX *lex)
        - EXPLAIN DELETE ...
        - ANALYZE DELETE ...
     */
-    if (lex->select_lex.item_list.is_empty() &&
+    if (lex->first_select_lex()->item_list.is_empty() &&
         !lex->describe && !lex->analyze_stmt)
       flags= 0;
     else
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index 6b418e9e387..7f6d48d838e 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -164,9 +164,10 @@ bool sp_rcontext::resolve_type_ref(THD *thd, Column_definition *def,
   // Make %TYPE variables see temporary tables that shadow permanent tables
   thd->temporary_tables= open_tables_state_backup.temporary_tables;
 
-  if ((table_list= lex.select_lex.add_table_to_list(thd, ref, NULL, 0,
-                                                    TL_READ_NO_INSERT,
-                                                    MDL_SHARED_READ)) &&
+  if ((table_list=
+       lex.first_select_lex()->add_table_to_list(thd, ref, NULL, 0,
+                                                 TL_READ_NO_INSERT,
+                                                 MDL_SHARED_READ)) &&
       !check_table_access(thd, SELECT_ACL, table_list, TRUE, UINT_MAX, FALSE) &&
       !open_tables_only_view_structure(thd, table_list,
                                        thd->mdl_context.has_locks()))
@@ -223,9 +224,10 @@ bool sp_rcontext::resolve_table_rowtype_ref(THD *thd,
   // Make %ROWTYPE variables see temporary tables that shadow permanent tables
   thd->temporary_tables= open_tables_state_backup.temporary_tables;
 
-  if ((table_list= lex.select_lex.add_table_to_list(thd, ref, NULL, 0,
-                                                    TL_READ_NO_INSERT,
-                                                    MDL_SHARED_READ)) &&
+  if ((table_list=
+       lex.first_select_lex()->add_table_to_list(thd, ref, NULL, 0,
+                                                 TL_READ_NO_INSERT,
+                                                 MDL_SHARED_READ)) &&
       !check_table_access(thd, SELECT_ACL, table_list, TRUE, UINT_MAX, FALSE) &&
       !open_tables_only_view_structure(thd, table_list,
                                        thd->mdl_context.has_locks()))
diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
index ce12b73a9e2..604b9b6b83f 100644
--- a/sql/sql_admin.cc
+++ b/sql/sql_admin.cc
@@ -306,7 +306,7 @@ static bool open_only_one_table(THD* thd, TABLE_LIST* table,
                                 bool is_view_operator_func)
 {
   LEX *lex= thd->lex;
-  SELECT_LEX *select= &lex->select_lex;
+  SELECT_LEX *select= lex->first_select_lex();
   TABLE_LIST *save_next_global, *save_next_local;
   bool open_error;
   save_next_global= table->next_global;
@@ -1296,7 +1296,7 @@ bool mysql_preload_keys(THD* thd, TABLE_LIST* tables)
 bool Sql_cmd_analyze_table::execute(THD *thd)
 {
   LEX *m_lex= thd->lex;
-  TABLE_LIST *first_table= m_lex->select_lex.table_list.first;
+  TABLE_LIST *first_table= m_lex->first_select_lex()->table_list.first;
   bool res= TRUE;
   thr_lock_type lock_type = TL_READ_NO_INSERT;
   DBUG_ENTER("Sql_cmd_analyze_table::execute");
@@ -1316,7 +1316,7 @@ bool Sql_cmd_analyze_table::execute(THD *thd)
     */
     res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
   }
-  m_lex->select_lex.table_list.first= first_table;
+  m_lex->first_select_lex()->table_list.first= first_table;
   m_lex->query_tables= first_table;
 
 error:
@@ -1327,7 +1327,7 @@ bool Sql_cmd_analyze_table::execute(THD *thd)
 bool Sql_cmd_check_table::execute(THD *thd)
 {
   LEX *m_lex= thd->lex;
-  TABLE_LIST *first_table= m_lex->select_lex.table_list.first;
+  TABLE_LIST *first_table= m_lex->first_select_lex()->table_list.first;
   thr_lock_type lock_type = TL_READ_NO_INSERT;
   bool res= TRUE;
   DBUG_ENTER("Sql_cmd_check_table::execute");
@@ -1340,7 +1340,7 @@ bool Sql_cmd_check_table::execute(THD *thd)
                          lock_type, 0, 0, HA_OPEN_FOR_REPAIR, 0,
                          &handler::ha_check, &view_check);
 
-  m_lex->select_lex.table_list.first= first_table;
+  m_lex->first_select_lex()->table_list.first= first_table;
   m_lex->query_tables= first_table;
 
 error:
@@ -1351,7 +1351,7 @@ bool Sql_cmd_check_table::execute(THD *thd)
 bool Sql_cmd_optimize_table::execute(THD *thd)
 {
   LEX *m_lex= thd->lex;
-  TABLE_LIST *first_table= m_lex->select_lex.table_list.first;
+  TABLE_LIST *first_table= m_lex->first_select_lex()->table_list.first;
   bool res= TRUE;
   DBUG_ENTER("Sql_cmd_optimize_table::execute");
 
@@ -1373,7 +1373,7 @@ bool Sql_cmd_optimize_table::execute(THD *thd)
     */
     res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
   }
-  m_lex->select_lex.table_list.first= first_table;
+  m_lex->first_select_lex()->table_list.first= first_table;
   m_lex->query_tables= first_table;
 
 error:
@@ -1384,7 +1384,7 @@ bool Sql_cmd_optimize_table::execute(THD *thd)
 bool Sql_cmd_repair_table::execute(THD *thd)
 {
   LEX *m_lex= thd->lex;
-  TABLE_LIST *first_table= m_lex->select_lex.table_list.first;
+  TABLE_LIST *first_table= m_lex->first_select_lex()->table_list.first;
   bool res= TRUE;
   DBUG_ENTER("Sql_cmd_repair_table::execute");
 
@@ -1408,7 +1408,7 @@ bool Sql_cmd_repair_table::execute(THD *thd)
     */
     res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
   }
-  m_lex->select_lex.table_list.first= first_table;
+  m_lex->first_select_lex()->table_list.first= first_table;
   m_lex->query_tables= first_table;
 
 error:
diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc
index 3d1e4c0fa65..dc4e9a91a7e 100644
--- a/sql/sql_alter.cc
+++ b/sql/sql_alter.cc
@@ -198,7 +198,7 @@ bool Sql_cmd_alter_table::execute(THD *thd)
 {
   LEX *lex= thd->lex;
   /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
-  SELECT_LEX *select_lex= &lex->select_lex;
+  SELECT_LEX *select_lex= lex->first_select_lex();
   /* first table of first SELECT_LEX */
   TABLE_LIST *first_table= (TABLE_LIST*) select_lex->table_list.first;
   /*
@@ -342,7 +342,7 @@ bool Sql_cmd_alter_table::execute(THD *thd)
 bool Sql_cmd_discard_import_tablespace::execute(THD *thd)
 {
   /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
-  SELECT_LEX *select_lex= &thd->lex->select_lex;
+  SELECT_LEX *select_lex= thd->lex->first_select_lex();
   /* first table of first SELECT_LEX */
   TABLE_LIST *table_list= (TABLE_LIST*) select_lex->table_list.first;
 
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 93dd6239749..ed3093488f3 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -7221,7 +7221,7 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
   TABLE_LIST *first_select_table= (select_insert ?
                                    tables->next_local:
                                    0);
-  SELECT_LEX *select_lex= select_insert ? &thd->lex->select_lex :
+  SELECT_LEX *select_lex= select_insert ? thd->lex->first_select_lex() :
                                           thd->lex->current_select;
   if (select_lex->first_cond_optimization)
   {
@@ -7249,7 +7249,7 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
       {
         /* new counting for SELECT of INSERT ... SELECT command */
         first_select_table= 0;
-        thd->lex->select_lex.insert_tables= tablenr;
+        thd->lex->first_select_lex()->insert_tables= tablenr;
         tablenr= 0;
       }
       if(table_list->jtbm_subselect)
@@ -7795,7 +7795,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, List<TABLE_LIST> &leaves,
     from subquery of VIEW, because tables of subquery belongs to VIEW
     (see condition before prepare_check_option() call)
   */
-  bool it_is_update= (select_lex == &thd->lex->select_lex) &&
+  bool it_is_update= (select_lex == thd->lex->first_select_lex()) &&
     thd->lex->which_check_option_applicable();
   bool save_is_item_list_lookup= select_lex->is_item_list_lookup;
   TABLE_LIST *derived= select_lex->master_unit()->derived;
@@ -7815,7 +7815,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, List<TABLE_LIST> &leaves,
 
   for (table= tables; table; table= table->next_local)
   {
-    if (select_lex == &thd->lex->select_lex &&
+    if (select_lex == thd->lex->first_select_lex() &&
         select_lex->first_cond_optimization &&
         table->merged_for_insert &&
         table->prepare_where(thd, conds, FALSE))
diff --git a/sql/sql_base.h b/sql/sql_base.h
index 7a8d27c9147..bacdad0b2f4 100644
--- a/sql/sql_base.h
+++ b/sql/sql_base.h
@@ -364,10 +364,12 @@ inline bool setup_fields_with_no_wrap(THD *thd, Ref_ptr_array ref_pointer_array,
                                       bool allow_sum_func)
 {
   bool res;
-  thd->lex->select_lex.no_wrap_view_item= TRUE;
+  SELECT_LEX *first= thd->lex->first_select_lex();
+  DBUG_ASSERT(thd->lex->current_select == first);
+  first->no_wrap_view_item= TRUE;
   res= setup_fields(thd, ref_pointer_array, item, mark_used_columns,
                     sum_func_list, allow_sum_func);
-  thd->lex->select_lex.no_wrap_view_item= FALSE;
+  first->no_wrap_view_item= FALSE;
   return res;
 }
 
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index ed5a8f84127..6d829334d3b 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -4110,13 +4110,13 @@ Query_cache::is_cacheable(THD *thd, LEX *lex,
 
   if (thd->lex->safe_to_cache_query &&
       (thd->variables.query_cache_type == 1 ||
-       (thd->variables.query_cache_type == 2 && (lex->select_lex.options &
-						 OPTION_TO_QUERY_CACHE))) &&
+       (thd->variables.query_cache_type == 2 &&
+        (lex->builtin_select.options & OPTION_TO_QUERY_CACHE))) &&
       qc_is_able_to_intercept_result(thd))
   {
     DBUG_PRINT("qcache", ("options: %lx  %lx  type: %u",
                           (long) OPTION_TO_QUERY_CACHE,
-                          (long) lex->select_lex.options,
+                          (long) lex->builtin_select.options,
                           (int) thd->variables.query_cache_type));
 
     if (!(table_count= process_and_count_tables(thd, tables_used,
@@ -4137,7 +4137,7 @@ Query_cache::is_cacheable(THD *thd, LEX *lex,
 	     ("not interesting query: %d or not cacheable, options %lx %lx  type: %u  net->vio present: %u",
 	      (int) lex->sql_command,
 	      (long) OPTION_TO_QUERY_CACHE,
-	      (long) lex->select_lex.options,
+	      (long) lex->builtin_select.options,
 	      (int) thd->variables.query_cache_type,
               (uint) MY_TEST(qc_is_able_to_intercept_result(thd))));
   DBUG_RETURN(0);
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 2bbcf3cd436..34999656d05 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -4397,6 +4397,7 @@ class THD :public Statement,
   TMP_TABLE_SHARE* save_tmp_table_share(TABLE *table);
   void restore_tmp_table_share(TMP_TABLE_SHARE *share);
 
+  bool inline is_main_lex(LEX *lex) { return lex == &main_lex; }
 private:
   /* Whether a lock has been acquired? */
   bool m_tmp_tables_locked;
@@ -5946,7 +5947,14 @@ class select_dumpvar :public select_result_interceptor {
 
 inline bool add_item_to_list(THD *thd, Item *item)
 {
-  return thd->lex->current_select->add_item_to_list(thd, item);
+  DBUG_ENTER("add_item_to_list");
+
+  DBUG_PRINT("XXX", ("Add '%s' -> cur sel: %p (%d)", item->name.str,
+                     thd->lex->current_select,
+                     (thd->lex->current_select ?
+                      thd->lex->current_select->select_number : 0)));
+  bool res= thd->lex->current_select->add_item_to_list(thd, item);
+  DBUG_RETURN(res);
 }
 
 inline bool add_value_to_list(THD *thd, Item *value)
diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc
index 2047c7c8762..fab38b57520 100644
--- a/sql/sql_cte.cc
+++ b/sql/sql_cte.cc
@@ -679,7 +679,7 @@ void With_element::move_anchors_ahead()
   st_select_lex *next_sl;
   st_select_lex *new_pos= spec->first_select();
   st_select_lex *last_sl;
-  new_pos->linkage= UNION_TYPE;
+  new_pos->set_linkage(UNION_TYPE);
   for (st_select_lex *sl= new_pos; sl; sl= next_sl)
   {
     next_sl= sl->next_select(); 
@@ -825,7 +825,7 @@ st_select_lex_unit *With_element::clone_parsed_spec(THD *thd,
   if (parser_state.init(thd, (char*) unparsed_spec.str, unparsed_spec.length))
     goto err;
   lex_start(thd);
-  with_select= &lex->select_lex;
+  with_select= lex->first_select_lex();
   with_select->select_number= ++thd->select_number;
   parse_status= parse_sql(thd, &parser_state, 0);
   if (parse_status)
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 3a161ce6d31..3472157dfcc 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -256,7 +256,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
   bool          reverse= FALSE;
   ORDER *order= (ORDER *) ((order_list && order_list->elements) ?
                            order_list->first : NULL);
-  SELECT_LEX   *select_lex= &thd->lex->select_lex;
+  SELECT_LEX   *select_lex= thd->lex->first_select_lex();
   killed_state killed_status= NOT_KILLED;
   THD::enum_binlog_query_type query_type= THD::ROW_QUERY_TYPE;
   bool with_select= !select_lex->item_list.is_empty();
@@ -291,7 +291,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
   }
   THD_STAGE_INFO(thd, stage_init);
   table->map=1;
-  query_plan.select_lex= &thd->lex->select_lex;
+  query_plan.select_lex= thd->lex->first_select_lex();
   query_plan.table= table;
   query_plan.updating_a_view= MY_TEST(table_list->view);
 
@@ -323,7 +323,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
 	  setup_order(thd, select_lex->ref_pointer_array, &tables,
                     fields, all_fields, order))
     {
-      free_underlaid_joins(thd, &thd->lex->select_lex);
+      free_underlaid_joins(thd, thd->lex->first_select_lex());
       DBUG_RETURN(TRUE);
     }
   }
@@ -807,14 +807,16 @@ l
                            bool *delete_while_scanning)
 {
   Item *fake_conds= 0;
-  SELECT_LEX *select_lex= &thd->lex->select_lex;
+  SELECT_LEX *select_lex= thd->lex->first_select_lex();
   DBUG_ENTER("mysql_prepare_delete");
   List<Item> all_fields;
 
   *delete_while_scanning= true;
   thd->lex->allow_sum_func= 0;
-  if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
-                                    &thd->lex->select_lex.top_join_list,
+  if (setup_tables_and_check_access(thd,
+                                    &thd->lex->first_select_lex()->context,
+                                    &thd->lex->first_select_lex()->
+                                      top_join_list,
                                     table_list, 
                                     select_lex->leaf_tables, FALSE, 
                                     DELETE_ACL, SELECT_ACL, TRUE))
@@ -886,21 +888,23 @@ int mysql_multi_delete_prepare(THD *thd)
 
     lex->query_tables also point on local list of DELETE SELECT_LEX
   */
-  if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
-                                    &thd->lex->select_lex.top_join_list,
+  if (setup_tables_and_check_access(thd,
+                                    &thd->lex->first_select_lex()->context,
+                                    &thd->lex->first_select_lex()->
+                                      top_join_list,
                                     lex->query_tables,
-                                    lex->select_lex.leaf_tables, FALSE, 
-                                    DELETE_ACL, SELECT_ACL, FALSE))
+                                    lex->first_select_lex()->leaf_tables,
+                                    FALSE, DELETE_ACL, SELECT_ACL, FALSE))
     DBUG_RETURN(TRUE);
 
-  if (lex->select_lex.handle_derived(thd->lex, DT_MERGE))  
+  if (lex->first_select_lex()->handle_derived(thd->lex, DT_MERGE))
     DBUG_RETURN(TRUE);
 
   /*
     Multi-delete can't be constructed over-union => we always have
     single SELECT on top and have to check underlying SELECTs of it
   */
-  lex->select_lex.exclude_from_table_unique_test= TRUE;
+  lex->first_select_lex()->exclude_from_table_unique_test= TRUE;
   /* Fix tables-to-be-deleted-from list to point at opened tables */
   for (target_tbl= (TABLE_LIST*) aux_tables;
        target_tbl;
@@ -942,8 +946,8 @@ int mysql_multi_delete_prepare(THD *thd)
     Reset the exclude flag to false so it doesn't interfare
     with further calls to unique_table
   */
-  lex->select_lex.exclude_from_table_unique_test= FALSE;
-  
+  lex->first_select_lex()->exclude_from_table_unique_test= FALSE;
+
   if (lex->save_prep_leaf_tables())
     DBUG_RETURN(TRUE);
   
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index b857dc8d2ec..c7d5f2d88bb 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -99,7 +99,8 @@ mysql_handle_derived(LEX *lex, uint phases)
         processed normally.
       */
       if (phases == DT_MERGE_FOR_INSERT &&
-          cursor && cursor->top_table()->select_lex != &lex->select_lex)
+          cursor && (cursor->top_table()->select_lex !=
+                     lex->first_select_lex()))
         continue;
       for (;
 	   cursor && !res;
diff --git a/sql/sql_do.cc b/sql/sql_do.cc
index a25bdef3d9d..192c31af37a 100644
--- a/sql/sql_do.cc
+++ b/sql/sql_do.cc
@@ -33,7 +33,7 @@ bool mysql_do(THD *thd, List<Item> &values)
     DBUG_RETURN(TRUE);
   while ((value = li++))
     (void) value->is_null();
-  free_underlaid_joins(thd, &thd->lex->select_lex);
+  free_underlaid_joins(thd, thd->lex->first_select_lex());
 
   if (thd->is_error())
   {
diff --git a/sql/sql_error.cc b/sql/sql_error.cc
index b1c7481bb8c..84bfa241535 100644
--- a/sql/sql_error.cc
+++ b/sql/sql_error.cc
@@ -782,7 +782,7 @@ bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
   List<Item> field_list;
   MEM_ROOT *mem_root= thd->mem_root;
   const Sql_condition *err;
-  SELECT_LEX *sel= &thd->lex->select_lex;
+  SELECT_LEX *sel= thd->lex->first_select_lex();
   SELECT_LEX_UNIT *unit= &thd->lex->unit;
   ulonglong idx= 0;
   Protocol *protocol=thd->protocol;
diff --git a/sql/sql_help.cc b/sql/sql_help.cc
index 4ccaa6a055f..2bb5a124e0d 100644
--- a/sql/sql_help.cc
+++ b/sql/sql_help.cc
@@ -87,7 +87,7 @@ enum enum_used_fields
 static bool init_fields(THD *thd, TABLE_LIST *tables,
 			struct st_find_field *find_fields, uint count)
 {
-  Name_resolution_context *context= &thd->lex->select_lex.context;
+  Name_resolution_context *context= &thd->lex->first_select_lex()->context;
   DBUG_ENTER("init_fields");
   context->resolve_in_table_list_only(tables);
   for (; count-- ; find_fields++)
@@ -723,10 +723,11 @@ static bool mysqld_help_internal(THD *thd, const char *mask)
     Init tables and fields to be usable from items
     tables do not contain VIEWs => we can pass 0 as conds
   */
-  thd->lex->select_lex.context.table_list=
-    thd->lex->select_lex.context.first_name_resolution_table= &tables[0];
-  if (setup_tables(thd, &thd->lex->select_lex.context,
-                   &thd->lex->select_lex.top_join_list,
+  thd->lex->first_select_lex()->context.table_list=
+    thd->lex->first_select_lex()->context.first_name_resolution_table=
+    &tables[0];
+  if (setup_tables(thd, &thd->lex->first_select_lex()->context,
+                   &thd->lex->first_select_lex()->top_join_list,
                    tables, leaves, FALSE, FALSE))
     goto error;
   memcpy((char*) used_fields, (char*) init_used_fields, sizeof(used_fields));
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 4ae66dcd32f..02508924123 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -241,7 +241,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
   }
   else
   {						// Part field list
-    SELECT_LEX *select_lex= &thd->lex->select_lex;
+    SELECT_LEX *select_lex= thd->lex->first_select_lex();
     Name_resolution_context *context= &select_lex->context;
     Name_resolution_context_state ctx_state;
     int res;
@@ -272,7 +272,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
 
     /* Restore the current context. */
     ctx_state.restore_state(context, table_list);
-    thd->lex->select_lex.no_wrap_view_item= FALSE;
+    thd->lex->first_select_lex()->no_wrap_view_item= FALSE;
 
     if (res)
       DBUG_RETURN(-1);
@@ -656,7 +656,7 @@ static void save_insert_query_plan(THD* thd, TABLE_LIST *table_list)
   bool skip= MY_TEST(table_list->view);
 
   /* Save subquery children */
-  for (SELECT_LEX_UNIT *unit= thd->lex->select_lex.first_inner_unit();
+  for (SELECT_LEX_UNIT *unit= thd->lex->first_select_lex()->first_inner_unit();
        unit;
        unit= unit->next_unit())
   {
@@ -777,7 +777,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
   /* mysql_prepare_insert sets table_list->table if it was not set */
   table= table_list->table;
 
-  context= &thd->lex->select_lex.context;
+  context= &thd->lex->first_select_lex()->context;
   /*
     These three asserts test the hypothesis that the resetting of the name
     resolution context below is not necessary at all since the list of local
@@ -1064,7 +1064,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
   } while (bulk_parameters_iterations(thd));
 
 values_loop_end:
-  free_underlaid_joins(thd, &thd->lex->select_lex);
+  free_underlaid_joins(thd, thd->lex->first_select_lex());
   joins_freed= TRUE;
 
   /*
@@ -1250,7 +1250,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
     table->file->ha_release_auto_increment();
 
   if (!joins_freed)
-    free_underlaid_joins(thd, &thd->lex->select_lex);
+    free_underlaid_joins(thd, thd->lex->first_select_lex());
   thd->abort_on_warning= 0;
   DBUG_RETURN(retval);
 }
@@ -1280,7 +1280,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
 
 static bool check_view_insertability(THD * thd, TABLE_LIST *view)
 {
-  uint num= view->view->select_lex.item_list.elements;
+  uint num= view->view->first_select_lex()->item_list.elements;
   TABLE *table= view->table;
   Field_translator *trans_start= view->field_translation,
 		   *trans_end= trans_start + num;
@@ -1380,10 +1380,12 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
      than INSERT.
   */
 
-  if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
-                                    &thd->lex->select_lex.top_join_list,
+  if (setup_tables_and_check_access(thd,
+                                    &thd->lex->first_select_lex()->context,
+                                    &thd->lex->first_select_lex()->
+                                      top_join_list,
                                     table_list,
-                                    thd->lex->select_lex.leaf_tables,
+                                    thd->lex->first_select_lex()->leaf_tables,
                                     select_insert, INSERT_ACL, SELECT_ACL,
                                     TRUE))
     DBUG_RETURN(TRUE);
@@ -1391,7 +1393,7 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
   if (insert_into_view && !fields.elements)
   {
     thd->lex->empty_field_list_on_rset= 1;
-    if (!thd->lex->select_lex.leaf_tables.head()->table ||
+    if (!thd->lex->first_select_lex()->leaf_tables.head()->table ||
         table_list->is_multitable())
     {
       my_error(ER_VIEW_NO_INSERT_FIELD_LIST, MYF(0),
@@ -1465,7 +1467,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
                           enum_duplicates duplic, COND **where,
                           bool select_insert)
 {
-  SELECT_LEX *select_lex= &thd->lex->select_lex;
+  SELECT_LEX *select_lex= thd->lex->first_select_lex();
   Name_resolution_context *context= &select_lex->context;
   Name_resolution_context_state ctx_state;
   bool insert_into_view= (table_list->view != 0);
@@ -3436,7 +3438,7 @@ bool Delayed_insert::handle_inserts(void)
 bool mysql_insert_select_prepare(THD *thd)
 {
   LEX *lex= thd->lex;
-  SELECT_LEX *select_lex= &lex->select_lex;
+  SELECT_LEX *select_lex= lex->first_select_lex();
   DBUG_ENTER("mysql_insert_select_prepare");
 
 
@@ -3525,7 +3527,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
     select, LEX::current_select should point to the first select while
     we are fixing fields from insert list.
   */
-  lex->current_select= &lex->select_lex;
+  lex->current_select= lex->first_select_lex();
 
   res= (setup_fields(thd, Ref_ptr_array(), values, MARK_COLUMNS_READ, 0, 0) ||
         check_insert_fields(thd, table_list, *fields, values,
@@ -3541,7 +3543,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
 
   if (info.handle_duplicates == DUP_UPDATE && !res)
   {
-    Name_resolution_context *context= &lex->select_lex.context;
+    Name_resolution_context *context= &lex->first_select_lex()->context;
     Name_resolution_context_state ctx_state;
 
     /* Save the state of the current name resolution context. */
@@ -3551,7 +3553,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
     table_list->next_local= 0;
     context->resolve_in_table_list_only(table_list);
 
-    lex->select_lex.no_wrap_view_item= TRUE;
+    lex->first_select_lex()->no_wrap_view_item= TRUE;
     res= res ||
       check_update_fields(thd, context->table_list,
                           *info.update_fields, *info.update_values,
@@ -3562,15 +3564,15 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
                            */
                           true,
                           &map);
-    lex->select_lex.no_wrap_view_item= FALSE;
+    lex->first_select_lex()->no_wrap_view_item= FALSE;
     /*
       When we are not using GROUP BY and there are no ungrouped aggregate functions 
       we can refer to other tables in the ON DUPLICATE KEY part.
       We use next_name_resolution_table descructively, so check it first (views?)
     */
     DBUG_ASSERT (!table_list->next_name_resolution_table);
-    if (lex->select_lex.group_list.elements == 0 &&
-        !lex->select_lex.with_sum_func)
+    if (lex->first_select_lex()->group_list.elements == 0 &&
+        !lex->first_select_lex()->with_sum_func)
       /*
         We must make a single context out of the two separate name resolution contexts :
         the INSERT table and the tables in the SELECT part of INSERT ... SELECT.
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 16995f215e8..83fee4ff128 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -182,7 +182,7 @@ init_lex_with_single_table(THD *thd, TABLE *table, LEX *lex)
 {
   TABLE_LIST *table_list;
   Table_ident *table_ident;
-  SELECT_LEX *select_lex= &lex->select_lex;
+  SELECT_LEX *select_lex= lex->first_select_lex();
   Name_resolution_context *context= &select_lex->context;
   /*
     We will call the parser to create a part_info struct based on the
@@ -680,15 +680,19 @@ void LEX::start(THD *thd_arg)
   DBUG_ASSERT(!explain);
 
   context_stack.empty();
+  //empty select_stack
+  select_stack_top= 0;
   unit.init_query();
-  select_lex.linkage= UNSPECIFIED_TYPE;
+  builtin_select.set_linkage(UNSPECIFIED_TYPE);
+  builtin_select.distinct= TRUE;
   /* 'parent_lex' is used in init_query() so it must be before it. */
-  select_lex.parent_lex= this;
-  select_lex.init_query();
+  builtin_select.parent_lex= this;
+  builtin_select.init_query();
   curr_with_clause= 0;
   with_clauses_list= 0;
   with_clauses_list_last_next= &with_clauses_list;
   create_view= NULL;
+  field_list.empty();
   value_list.empty();
   update_list.empty();
   set_var_list.empty();
@@ -702,17 +706,17 @@ void LEX::start(THD *thd_arg)
   auxiliary_table_list.empty();
   unit.next= unit.master= unit.link_next= unit.return_to= 0;
   unit.prev= unit.link_prev= 0;
-  unit.slave= current_select= all_selects_list= &select_lex;
-  select_lex.master= &unit;
-  select_lex.prev= &unit.slave;
-  select_lex.link_next= select_lex.slave= select_lex.next= 0;
-  select_lex.link_prev= (st_select_lex_node**)&(all_selects_list);
-  select_lex.options= 0;
-  select_lex.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED;
-  select_lex.init_order();
-  select_lex.group_list.empty();
-  if (select_lex.group_list_ptrs)
-    select_lex.group_list_ptrs->clear();
+  unit.slave= current_select= all_selects_list= &builtin_select;
+  builtin_select.master= &unit;
+  builtin_select.prev= &unit.slave;
+  builtin_select.link_next= builtin_select.slave= builtin_select.next= 0;
+  builtin_select.link_prev= (st_select_lex_node**)&(all_selects_list);
+  builtin_select.options= 0;
+  builtin_select.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED;
+  builtin_select.init_order();
+  builtin_select.group_list.empty();
+  if (builtin_select.group_list_ptrs)
+    builtin_select.group_list_ptrs->clear();
   describe= 0;
   analyze_stmt= 0;
   explain_json= false;
@@ -722,14 +726,14 @@ void LEX::start(THD *thd_arg)
   safe_to_cache_query= 1;
   parsing_options.reset();
   empty_field_list_on_rset= 0;
-  select_lex.select_number= 1;
+  builtin_select.select_number= 1;
   part_info= 0;
-  select_lex.in_sum_expr=0;
-  select_lex.ftfunc_list_alloc.empty();
-  select_lex.ftfunc_list= &select_lex.ftfunc_list_alloc;
-  select_lex.group_list.empty();
-  select_lex.order_list.empty();
-  select_lex.gorder_list.empty();
+  builtin_select.in_sum_expr=0;
+  builtin_select.ftfunc_list_alloc.empty();
+  builtin_select.ftfunc_list= &builtin_select.ftfunc_list_alloc;
+  builtin_select.group_list.empty();
+  builtin_select.order_list.empty();
+  builtin_select.gorder_list.empty();
   m_sql_cmd= NULL;
   duplicates= DUP_ERROR;
   ignore= 0;
@@ -750,7 +754,7 @@ void LEX::start(THD *thd_arg)
   event_parse_data= NULL;
   profile_options= PROFILE_NONE;
   nest_level=0 ;
-  select_lex.nest_level_base= &unit;
+  builtin_select.nest_level_base= &unit;
   allow_sum_func= 0;
   in_sum_func= NULL;
 
@@ -772,6 +776,11 @@ void LEX::start(THD *thd_arg)
   win_spec= NULL;
 
   is_lex_started= TRUE;
+
+  braces_depth= 0;
+  next_is_main= FALSE;
+  next_is_down= FALSE;
+
   DBUG_VOID_RETURN;
 }
 
@@ -1845,7 +1854,7 @@ static int lex_one_token(YYSTYPE *yylval, THD *thd)
       return(TEXT_STRING);
     }
     case MY_LEX_COMMENT:			//  Comment
-      lex->select_lex.options|= OPTION_FOUND_COMMENT;
+      lex->builtin_select.options|= OPTION_FOUND_COMMENT;
       while ((c = lip->yyGet()) != '\n' && c) ;
       lip->yyUnget();                   // Safety against eof
       state = MY_LEX_START;		// Try again
@@ -1856,7 +1865,7 @@ static int lex_one_token(YYSTYPE *yylval, THD *thd)
 	state=MY_LEX_CHAR;		// Probable division
 	break;
       }
-      lex->select_lex.options|= OPTION_FOUND_COMMENT;
+      lex->builtin_select.options|= OPTION_FOUND_COMMENT;
       /* Reject '/' '*', since we might need to turn off the echo */
       lip->yyUnget();
 
@@ -2140,7 +2149,8 @@ void st_select_lex_node::init_query_common()
 {
   options= 0;
   sql_cache= SQL_CACHE_UNSPECIFIED;
-  linkage= UNSPECIFIED_TYPE;
+  set_linkage(UNSPECIFIED_TYPE);
+  distinct= TRUE;
   no_table_names_allowed= 0;
   uncacheable= 0;
 }
@@ -2148,7 +2158,7 @@ void st_select_lex_node::init_query_common()
 void st_select_lex_unit::init_query()
 {
   init_query_common();
-  linkage= GLOBAL_OPTIONS_TYPE;
+  set_linkage(GLOBAL_OPTIONS_TYPE);
   select_limit_cnt= HA_POS_ERROR;
   offset_limit_cnt= 0;
   union_distinct= 0;
@@ -2984,6 +2994,7 @@ LEX::LEX()
                       INITIAL_LEX_PLUGIN_LIST_SIZE, 0);
   reset_query_tables_list(TRUE);
   mi.init();
+  unit.slave= &builtin_select;
 }
 
 
@@ -3010,12 +3021,12 @@ bool LEX::can_be_merged()
   // TODO: do not forget implement case when select_lex.table_list.elements==0
 
   /* find non VIEW subqueries/unions */
-  bool selects_allow_merge= (select_lex.next_select() == 0 &&
-                             !(select_lex.uncacheable &
+  bool selects_allow_merge= (first_select_lex()->next_select() == 0 &&
+                             !(first_select_lex()->uncacheable &
                                UNCACHEABLE_RAND));
   if (selects_allow_merge)
   {
-    for (SELECT_LEX_UNIT *tmp_unit= select_lex.first_inner_unit();
+    for (SELECT_LEX_UNIT *tmp_unit= first_select_lex()->first_inner_unit();
          tmp_unit;
          tmp_unit= tmp_unit->next_unit())
     {
@@ -3032,12 +3043,12 @@ bool LEX::can_be_merged()
   }
 
   return (selects_allow_merge &&
-	  select_lex.group_list.elements == 0 &&
-	  select_lex.having == 0 &&
-          select_lex.with_sum_func == 0 &&
-	  select_lex.table_list.elements >= 1 &&
-	  !(select_lex.options & SELECT_DISTINCT) &&
-          select_lex.select_limit == 0);
+	  first_select_lex()->group_list.elements == 0 &&
+	  first_select_lex()->having == 0 &&
+          first_select_lex()->with_sum_func == 0 &&
+	  first_select_lex()->table_list.elements >= 1 &&
+	  !(first_select_lex()->options & SELECT_DISTINCT) &&
+          first_select_lex()->select_limit == 0);
 }
 
 
@@ -3393,7 +3404,7 @@ void LEX::set_trg_event_type_for_tables()
     Do not iterate over sub-selects, only the tables in the outermost
     SELECT_LEX can be modified, if any.
   */
-  TABLE_LIST *tables= select_lex.get_table_list();
+  TABLE_LIST *tables= first_select_lex()->get_table_list();
 
   while (tables)
   {
@@ -3449,12 +3460,13 @@ TABLE_LIST *LEX::unlink_first_table(bool *link_to_local)
     /*
       and from local list if it is not empty
     */
-    if ((*link_to_local= MY_TEST(select_lex.table_list.first)))
+    if ((*link_to_local= MY_TEST(first_select_lex()->table_list.first)))
     {
-      select_lex.context.table_list= 
-        select_lex.context.first_name_resolution_table= first->next_local;
-      select_lex.table_list.first= first->next_local;
-      select_lex.table_list.elements--;	//safety
+      first_select_lex()->context.table_list=
+        first_select_lex()->context.first_name_resolution_table=
+        first->next_local;
+      first_select_lex()->table_list.first= first->next_local;
+      first_select_lex()->table_list.elements--;	//safety
       first->next_local= 0;
       /*
         Ensure that the global list has the same first table as the local
@@ -3485,7 +3497,7 @@ TABLE_LIST *LEX::unlink_first_table(bool *link_to_local)
 
 void LEX::first_lists_tables_same()
 {
-  TABLE_LIST *first_table= select_lex.table_list.first;
+  TABLE_LIST *first_table= first_select_lex()->table_list.first;
   if (query_tables != first_table && first_table != 0)
   {
     TABLE_LIST *next;
@@ -3535,10 +3547,10 @@ void LEX::link_first_table_back(TABLE_LIST *first,
 
     if (link_to_local)
     {
-      first->next_local= select_lex.table_list.first;
-      select_lex.context.table_list= first;
-      select_lex.table_list.first= first;
-      select_lex.table_list.elements++;	//safety
+      first->next_local= first_select_lex()->table_list.first;
+      first_select_lex()->context.table_list= first;
+      first_select_lex()->table_list.first= first;
+      first_select_lex()->table_list.elements++;	//safety
     }
   }
 }
@@ -3567,19 +3579,19 @@ void LEX::cleanup_after_one_table_open()
     NOTE: all units will be connected to thd->lex->select_lex, because we
     have not UNION on most upper level.
     */
-  if (all_selects_list != &select_lex)
+  if (all_selects_list != first_select_lex())
   {
     derived_tables= 0;
-    select_lex.exclude_from_table_unique_test= false;
+    first_select_lex()->exclude_from_table_unique_test= false;
     /* cleunup underlying units (units of VIEW) */
-    for (SELECT_LEX_UNIT *un= select_lex.first_inner_unit();
+    for (SELECT_LEX_UNIT *un= first_select_lex()->first_inner_unit();
          un;
          un= un->next_unit())
       un->cleanup();
     /* reduce all selects list to default state */
-    all_selects_list= &select_lex;
+    all_selects_list= first_select_lex();
     /* remove underlying units (units of VIEW) subtree */
-    select_lex.cut_subtree();
+    first_select_lex()->cut_subtree();
   }
 }
 
@@ -4428,7 +4440,7 @@ void st_select_lex::set_explain_type(bool on_the_fly)
       using_materialization= TRUE;
   }
 
-  if (&master_unit()->thd->lex->select_lex == this)
+  if (master_unit()->thd->lex->first_select_lex() == this)
   {
      type= is_primary ? "PRIMARY" : "SIMPLE";
   }
@@ -4622,8 +4634,8 @@ bool LEX::save_prep_leaf_tables()
   Query_arena *arena= thd->stmt_arena, backup;
   arena= thd->activate_stmt_arena_if_needed(&backup);
   //It is used for DETETE/UPDATE so top level has only one SELECT
-  DBUG_ASSERT(select_lex.next_select() == NULL);
-  bool res= select_lex.save_prep_leaf_tables(thd);
+  DBUG_ASSERT(first_select_lex()->next_select() == NULL);
+  bool res= first_select_lex()->save_prep_leaf_tables(thd);
 
   if (arena)
     thd->restore_active_arena(arena, &backup);
@@ -4952,8 +4964,13 @@ bool LEX::is_partition_management() const
 
 SELECT_LEX *LEX::exclude_last_select()
 {
-  DBUG_ENTER("SELECT_LEX::exclude_last_select");
-  SELECT_LEX *exclude= current_select;
+  return exclude_not_first_select(current_select);
+}
+
+SELECT_LEX *LEX::exclude_not_first_select(SELECT_LEX *exclude)
+{
+  DBUG_ENTER("LEX::exclude_not_first_select");
+  DBUG_PRINT("enter", ("exclude %p #%u", exclude, exclude->select_number));
   SELECT_LEX_UNIT *unit= exclude->master_unit();
   SELECT_LEX *sl;
   DBUG_ASSERT(unit->first_select() != exclude);
@@ -4964,13 +4981,382 @@ SELECT_LEX *LEX::exclude_last_select()
   DBUG_PRINT("info", ("excl: %p  unit: %p  prev: %p", exclude, unit, sl));
   if (!sl)
     DBUG_RETURN(NULL);
-  DBUG_ASSERT(exclude->next_select() == NULL);
-  exclude->exclude_from_tree();
+  DBUG_ASSERT(&sl->next == exclude->prev);
+
+  exclude->prev= NULL;
+
   current_select= sl;
   DBUG_RETURN(exclude);
 }
 
 
+/*
+     SELECT_1 -> SELECT_EXCL -> SELECT_3 ...
+
+     SELECT_1 -> NULL
+        |
+        V
+        SELECT_EXCL -> SELECT_3
+*/
+
+
+SELECT_LEX *LEX::shift_selects_down(SELECT_LEX *exclude_start)
+{
+  SELECT_LEX_UNIT *unit= exclude_start->master_unit();
+  SELECT_LEX *prev_select;
+  DBUG_ENTER("LEX::schift_selects_down");
+
+  for (prev_select= unit->first_select();
+       prev_select && prev_select->next_select() != exclude_start;
+       prev_select= prev_select->next_select()) ;
+  if (!prev_select)
+    DBUG_RETURN(NULL);
+
+  prev_select->next= NULL;
+  current_select= prev_select;
+
+  SELECT_LEX *sl= exclude_start;
+  bool down= TRUE;
+  do{
+    SELECT_LEX *next= sl->next_select();
+    if (mysql_new_select(this, down, sl))
+      DBUG_RETURN(NULL);
+    down= FALSE;
+    DBUG_ASSERT(sl->outer_select() == prev_select);
+    sl= next;
+  } while (sl);
+
+  DBUG_ASSERT(unit != exclude_start->master_unit());
+  unit->fix_distinct(exclude_start->master_unit());
+
+  current_select= prev_select;
+  DBUG_RETURN(prev_select);
+}
+
+
+SELECT_LEX_UNIT *LEX::alloc_unit()
+{
+  SELECT_LEX_UNIT *unit;
+  DBUG_ENTER("LEX::alloc_unit");
+  if (!(unit= new (thd->mem_root) SELECT_LEX_UNIT()))
+    DBUG_RETURN(NULL);
+
+  unit->init_query();
+  /* TODO: reentrant problem */
+  unit->thd= thd;
+  unit->link_next= 0;
+  unit->link_prev= 0;
+  /* TODO: remove return_to */
+  unit->return_to= NULL;
+  DBUG_RETURN(unit);
+}
+
+
+SELECT_LEX *LEX::alloc_select(bool select)
+{
+  SELECT_LEX *select_lex;
+  DBUG_ENTER("LEX::alloc_select");
+  if (!(select_lex= new (thd->mem_root) SELECT_LEX()))
+    DBUG_RETURN(NULL);
+  DBUG_PRINT("info", ("Allocate select %p #%u",
+                      select_lex, thd->select_number));
+  select_lex->select_number= ++thd->select_number;
+  select_lex->parent_lex= this; /* Used in init_query. */
+  select_lex->init_query();
+  if (select)
+    select_lex->init_select();
+  select_lex->nest_level_base= &this->unit;
+  select_lex->include_global((st_select_lex_node**)&all_selects_list);
+  select_lex->context.resolve_in_select_list= TRUE;
+  DBUG_RETURN(select_lex);
+}
+
+SELECT_LEX_UNIT *
+LEX::create_unit(SELECT_LEX *first_sel)
+{
+  SELECT_LEX_UNIT *unit;
+  DBUG_ENTER("LEX::create_unit");
+
+  if (!(unit= alloc_unit()))
+    DBUG_RETURN(NULL);
+
+  unit->register_select_chain(first_sel);
+  if (first_sel->next_select())
+  {
+    unit->reset_distinct();
+    DBUG_ASSERT(!unit->fake_select_lex);
+    if (!unit->add_fake_select_lex(thd))
+      DBUG_RETURN(NULL);
+  }
+  DBUG_RETURN(unit);
+}
+
+SELECT_LEX_UNIT *
+SELECT_LEX::attach_selects_chain(SELECT_LEX *first_sel,
+                                 Name_resolution_context *context)
+{
+  SELECT_LEX_UNIT *unit;
+  DBUG_ENTER("SELECT_LEX::attach_select_chain");
+
+  if (!(unit= parent_lex->alloc_unit()))
+    DBUG_RETURN(NULL);
+
+  unit->register_select_chain(first_sel);
+  register_unit(unit, context);
+  if (first_sel->next_select())
+  {
+    unit->reset_distinct();
+    DBUG_ASSERT(!unit->fake_select_lex);
+    if (unit->add_fake_select_lex(parent_lex->thd))
+      DBUG_RETURN(NULL);
+  }
+
+  DBUG_RETURN(unit);
+}
+
+SELECT_LEX *
+LEX::wrap_unit_into_derived(SELECT_LEX_UNIT *unit)
+{
+  SELECT_LEX *wrapping_sel;
+  Table_ident *ti;
+  DBUG_ENTER("LEX::wrap_unit_into_derived");
+
+  if (!(wrapping_sel= alloc_select(TRUE)))
+    DBUG_RETURN(NULL);
+  Name_resolution_context *context= &wrapping_sel->context;
+  context->init();
+  wrapping_sel->automatic_brackets= FALSE;
+
+  wrapping_sel->register_unit(unit, context);
+
+  /* stuff dummy SELECT * FROM (...) */
+
+  if (push_select(wrapping_sel)) // for Items & TABLE_LIST
+    DBUG_RETURN(NULL);
+
+  /* add SELECT list*/
+  {
+    Item *item= new (thd->mem_root)
+      Item_field(thd, context, NULL, NULL, &star_clex_str);
+    if (item == NULL)
+      goto err;
+    if (add_item_to_list(thd, item))
+      goto err;
+    (wrapping_sel->with_wild)++;
+  }
+
+  unit->first_select()->set_linkage(DERIVED_TABLE_TYPE);
+
+  ti= new (thd->mem_root) Table_ident(unit);
+  if (ti == NULL)
+    goto err;
+  {
+    char buff[10];
+    TABLE_LIST *table_list;
+    LEX_CSTRING alias;
+    alias.length= my_snprintf(buff, sizeof(buff),
+                              "__%u", wrapping_sel->select_number);
+    alias.str= thd->strmake(buff, alias.length);
+    if (!alias.str)
+      goto err;
+
+    if (!(table_list= wrapping_sel->add_table_to_list(thd, ti, &alias,
+                                                      0, TL_READ,
+                                                      MDL_SHARED_READ)))
+      goto err;
+
+    context->resolve_in_table_list_only(table_list);
+    wrapping_sel->add_joined_table(table_list);
+  }
+
+  pop_select();
+
+  derived_tables|= DERIVED_SUBQUERY;
+
+  /* TODO: count from the other end */
+  if (wrapping_sel->set_nest_level(1))
+    DBUG_RETURN(NULL);
+
+  DBUG_RETURN(wrapping_sel);
+
+err:
+  pop_select();
+  DBUG_RETURN(NULL);
+}
+
+SELECT_LEX *LEX::link_selects_chain_down(SELECT_LEX *sel)
+{
+  SELECT_LEX *dummy_select;
+  SELECT_LEX_UNIT *unit;
+  Table_ident *ti;
+  DBUG_ENTER("LEX::link_selects_chain_down");
+ 
+  if (!(dummy_select= alloc_select(TRUE)))
+     DBUG_RETURN(NULL);
+  Name_resolution_context *context= &dummy_select->context;
+  dummy_select->automatic_brackets= FALSE;
+ 
+  if (!(unit= dummy_select->attach_selects_chain(sel, context)))
+    DBUG_RETURN(NULL);
+ 
+  /* stuff dummy SELECT * FROM (...) */
+ 
+  if (push_select(dummy_select)) // for Items & TABLE_LIST
+    DBUG_RETURN(NULL); 
+
+  /* add SELECT list*/
+  {
+    Item *item= new (thd->mem_root)
+      Item_field(thd, context, NULL, NULL, &star_clex_str);
+    if (item == NULL)
+      goto err;
+    if (add_item_to_list(thd, item))
+      goto err;
+    (dummy_select->with_wild)++;
+  }
+ 
+  sel->set_linkage(DERIVED_TABLE_TYPE);
+ 
+  ti= new (thd->mem_root) Table_ident(unit);
+  if (ti == NULL)
+    goto err;
+  {
+    char buff[10];
+    TABLE_LIST *table_list;
+    LEX_CSTRING alias;
+    alias.length= my_snprintf(buff, sizeof(buff),
+                              "__%u", dummy_select->select_number);
+    alias.str= thd->strmake(buff, alias.length);
+    if (!alias.str)
+      goto err;
+ 
+    if (!(table_list= dummy_select->add_table_to_list(thd, ti, &alias,
+                                                      0, TL_READ,
+                                                      MDL_SHARED_READ)))
+      goto err;
+ 
+    context->resolve_in_table_list_only(table_list);
+    dummy_select->add_joined_table(table_list);
+  }
+ 
+  pop_select();
+
+  derived_tables|= DERIVED_SUBQUERY;
+ 
+   /* TODO: count from the other end */
+  if (dummy_select->set_nest_level(1))
+     DBUG_RETURN(NULL);
+ 
+  DBUG_RETURN(dummy_select);
+ 
+err:
+  pop_select();
+  DBUG_RETURN(NULL);
+}
+
+SELECT_LEX *LEX::push_selects_down(SELECT_LEX *exclude_start,
+                                   SELECT_LEX *exclude_end, bool automatic)
+{
+  SELECT_LEX_UNIT *unit= exclude_start->master_unit();
+  SELECT_LEX *dummy_select;
+  int old_nest_level= exclude_start->nest_level;
+  DBUG_ENTER("LEX::push_selects_down");
+
+  /* prepare dummy select */
+  if (!(dummy_select= alloc_select(TRUE)))
+    DBUG_RETURN(NULL);
+  current_select->braces_depth= get_braces_depth();
+
+  dummy_select->context.outer_context= exclude_start->context.outer_context;
+  dummy_select->set_linkage(exclude_start->linkage);
+  /* cut out the chain and put dummy_select instaed */
+  exclude_start->prev[0]= dummy_select;
+  dummy_select->prev= exclude_start->prev;
+  dummy_select->master= unit;
+  if ((dummy_select->next= exclude_end))
+  {
+    exclude_end->prev[0]= NULL;
+    exclude_end->prev= &dummy_select->next;
+  }
+
+  //current_select= dummy_select;
+  //mysql_init_select(this);
+  if (make_select_in_brackets(dummy_select, exclude_start, automatic))
+      DBUG_RETURN(NULL);
+
+  DBUG_ASSERT(unit != exclude_start->master_unit());
+  unit->fix_distinct(exclude_start->master_unit());
+
+  current_select= dummy_select;
+  if (dummy_select->set_nest_level(old_nest_level))
+    DBUG_RETURN(NULL);
+  DBUG_PRINT("info", ("Dummy returned: %p", dummy_select));
+  DBUG_RETURN(dummy_select);
+}
+
+/*
+SELECT_LEX *LEX::push_selects_down(SELECT_LEX *exclude_start)
+{
+  DBUG_ENTER("LEX::push_selects_down");
+  SELECT_LEX_UNIT *unit= exclude_start->master_unit();
+
+
+  if (unit->first_select() == exclude_start)
+  {
+    SELECT_LEX *dummy_select;
+    SELECT_LEX *distinct= unit->union_distinct;
+    int old_nest_level= exclude_start->nest_level;
+    unit->union_distinct= NULL;
+    unit->slave= NULL;
+
+    if (!(dummy_select= new (thd->mem_root) SELECT_LEX()))
+      DBUG_RETURN(NULL);
+    dummy_select->select_number= ++thd->select_number;
+    dummy_select->parent_lex= this;
+    dummy_select->init_query();
+    dummy_select->init_select();
+    current_select->braces_depth= get_braces_depth();
+    dummy_select->nest_level_base= &this->unit;
+
+    dummy_select->include_down(unit);
+    dummy_select->context.outer_context= exclude_start->context.outer_context;
+    dummy_select->
+      include_global((st_select_lex_node**)&all_selects_list);
+    current_select= dummy_select;
+    dummy_select->context.resolve_in_select_list= TRUE;
+
+    mysql_init_select(this);
+    current_select->set_linkage(exclude_start->linkage);
+
+    if (make_select_in_brackets(dummy_select, exclude_start, FALSE))
+      DBUG_RETURN(NULL);
+
+    DBUG_ASSERT(unit != exclude_start->master_unit());
+    exclude_start->master_unit()->union_distinct= distinct;
+
+    current_select= dummy_select;
+    //lex->nest_level++;
+    if (dummy_select->set_nest_level(old_nest_level))
+      DBUG_RETURN(NULL);
+    DBUG_PRINT("info", ("Dummy returned: %p", dummy_select));
+    DBUG_RETURN(dummy_select);
+  }
+
+  if (!exclude_not_first_select(exclude_start) ||
+      add_unit_in_brackets(exclude_start))
+    DBUG_RETURN(NULL);
+  if (unit->union_distinct && unit != unit->union_distinct->master_unit())
+  {
+    SELECT_LEX *distinct_sel= unit->union_distinct;
+    distinct_sel->master_unit()->union_distinct= distinct_sel;
+    unit->union_distinct= NULL;
+  }
+  DBUG_PRINT("info", ("Current outer returned: %p",
+             current_select->master_unit()->outer_select()));
+  DBUG_RETURN(current_select->master_unit()->outer_select());
+}
+*/
+
 /**
   Put given (new) SELECT_LEX level below after currect (last) SELECT
 
@@ -4993,13 +5379,43 @@ SELECT_LEX *LEX::exclude_last_select()
 bool LEX::add_unit_in_brackets(SELECT_LEX *nselect)
 {
   DBUG_ENTER("LEX::add_unit_in_brackets");
-  bool distinct= nselect->master_unit()->union_distinct == nselect;
-  bool rc= add_select_to_union_list(distinct, nselect->linkage, 0);
-  if (rc)
+  SELECT_LEX_UNIT *unit= nselect->master_unit();
+  int old_nest_level= nselect->nest_level;
+  bool distinct= unit->union_distinct == nselect;
+  if (add_select_to_union_list(distinct, nselect->linkage, 0))
     DBUG_RETURN(TRUE);
-  SELECT_LEX* dummy_select= current_select;
-  dummy_select->automatic_brackets= TRUE;
-  dummy_select->linkage= nselect->linkage;
+
+  SELECT_LEX *dummy= current_select;
+  dummy->next= NULL;
+  if (make_select_in_brackets(current_select, nselect, FALSE))
+    DBUG_RETURN(TRUE);
+
+  if (!distinct && nselect->master_unit()->union_distinct)
+  {
+    // move distinct pointer
+    if (unit->union_distinct->master_unit() != unit)
+    {
+      unit->union_distinct->master_unit()->union_distinct= unit->union_distinct;
+      unit->union_distinct= NULL;
+    }
+  }
+  else if (distinct)
+    unit->union_distinct= NULL;// distinkt was moved by add_select_to_union_list
+
+  dummy->set_nest_level(old_nest_level);
+  DBUG_RETURN(FALSE);
+}
+
+
+bool LEX::make_select_in_brackets(SELECT_LEX* dummy_select,
+                                  SELECT_LEX *nselect, bool automatic)
+{
+  DBUG_ENTER("LEX::make_select_in_brackets");
+
+  int old_nest_level= nselect->nest_level;
+  dummy_select->automatic_brackets= automatic;
+  dummy_select->set_linkage(nselect->linkage);
+  current_select= dummy_select; // for mysql_new_select & Items
 
   /* stuff dummy SELECT * FROM (...) */
   Name_resolution_context *context= &dummy_select->context;
@@ -5014,12 +5430,19 @@ bool LEX::add_unit_in_brackets(SELECT_LEX *nselect)
     DBUG_RETURN(TRUE);
   (dummy_select->with_wild)++;
 
-  rc= mysql_new_select(this, 1, nselect);
-  nselect->linkage= DERIVED_TABLE_TYPE;
-  DBUG_ASSERT(nselect->outer_select() == dummy_select);
+  nselect->set_linkage(DERIVED_TABLE_TYPE);
+  SELECT_LEX *sl= nselect;
+  bool down= TRUE;
+  do{
+    SELECT_LEX *next= sl->next_select();
+    if (mysql_new_select(this, down, sl))
+      DBUG_RETURN(TRUE);
+    down= FALSE;
+    DBUG_ASSERT(sl->outer_select() == dummy_select);
+    sl= next;
+  } while (sl);
 
   current_select= dummy_select;
-  current_select->nest_level--;
 
   SELECT_LEX_UNIT *unit= nselect->master_unit();
   Table_ident *ti= new (thd->mem_root) Table_ident(unit);
@@ -5043,12 +5466,39 @@ bool LEX::add_unit_in_brackets(SELECT_LEX *nselect)
 
   derived_tables|= DERIVED_SUBQUERY;
 
+  if (dummy_select->set_nest_level(old_nest_level))
+    DBUG_RETURN(TRUE);
+
   current_select= nselect;
-  current_select->nest_level++;
-  DBUG_RETURN(rc);
+  //current_select->nest_level++;
+  DBUG_RETURN(FALSE);
+}
+
+bool LEX::push_new_select(SELECT_LEX *last)
+{
+  DBUG_ENTER("LEX::push_select_new");
+  DBUG_PRINT("info", ("Push last select: %p (%d)",
+                       last, last->select_number));
+  bool res= last_select_stack.push_front(last, thd->mem_root);
+  DBUG_RETURN(res);
 }
 
 
+SELECT_LEX *LEX::pop_new_select_and_wrap()
+{
+  SELECT_LEX *sel;
+  SELECT_LEX *last= pop_new_select();
+  SELECT_LEX *first= last->next_select();
+  last->cut_next();
+  enum sub_select_type op= first->linkage;
+  bool ds= first->distinct;
+  if (!(sel= link_selects_chain_down(first)))
+      return NULL;
+  last->link_neighbour(sel);
+  sel->set_linkage_and_distinct(op, ds);
+  return last;
+}
+
 /**
   Checks if we need finish "automatic brackets" mode
 
@@ -7062,6 +7512,40 @@ Item *st_select_lex::build_cond_for_grouping_fields(THD *thd, Item *cond,
 }
 
 
+bool st_select_lex::set_nest_level(int new_nest_level)
+{
+  DBUG_ENTER("st_select_lex::set_nest_level");
+  DBUG_PRINT("enter", ("select #%d %p nest level: %d",
+                       select_number, this, new_nest_level));
+  if (new_nest_level > (int) MAX_SELECT_NESTING)
+  {
+    my_error(ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT, MYF(0));
+    DBUG_RETURN(TRUE);
+  }
+  nest_level= new_nest_level;
+  new_nest_level++;
+  for (SELECT_LEX_UNIT *u= first_inner_unit(); u; u= u->next_unit())
+  {
+    if (u->set_nest_level(new_nest_level))
+      DBUG_RETURN(TRUE);
+  }
+  DBUG_RETURN(FALSE);
+}
+
+bool st_select_lex_unit::set_nest_level(int new_nest_level)
+{
+  DBUG_ENTER("st_select_lex_unit::set_nest_level");
+  for(SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
+  {
+    if (sl->set_nest_level(new_nest_level))
+      DBUG_RETURN(TRUE);
+  }
+  if (fake_select_lex &&
+      fake_select_lex->set_nest_level(new_nest_level))
+    DBUG_RETURN(TRUE);
+  DBUG_RETURN(FALSE);
+}
+
 int set_statement_var_if_exists(THD *thd, const char *var_name,
                                 size_t var_name_length, ulonglong value)
 {
@@ -7114,10 +7598,10 @@ bool LEX::create_or_alter_view_finalize(THD *thd, Table_ident *table_ident)
 {
   sql_command= SQLCOM_CREATE_VIEW;
   /* first table in list is target VIEW name */
-  if (!select_lex.add_table_to_list(thd, table_ident, NULL,
-                                    TL_OPTION_UPDATING,
-                                    TL_IGNORE,
-                                    MDL_EXCLUSIVE))
+  if (!first_select_lex()->add_table_to_list(thd, table_ident, NULL,
+                                             TL_OPTION_UPDATING,
+                                             TL_IGNORE,
+                                             MDL_EXCLUSIVE))
     return true;
   query_tables->open_strategy= TABLE_LIST::OPEN_STUB;
   return false;
@@ -7206,3 +7690,194 @@ Item *LEX::make_item_func_replace(THD *thd,
     new (thd->mem_root) Item_func_replace_oracle(thd, org, find, replace) :
     new (thd->mem_root) Item_func_replace(thd, org, find, replace);
 }
+
+
+bool st_select_lex_unit::automatic_op_precedence()
+{
+  bool high_prec= TRUE;
+
+  for(SELECT_LEX *start= first_select();
+      start->next_select();
+      start= start->next_select())
+  {
+    if (start->next_select()->linkage != INTERSECT_TYPE)
+      high_prec= FALSE;
+    else if (!high_prec)
+    {
+      SELECT_LEX *end= start->next_select()->next_select();
+      while (end && end->linkage == INTERSECT_TYPE)
+      {
+        end= end->next_select();
+      }
+      if (!(start= start->parent_lex->push_selects_down(start, end, TRUE)))
+        return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+void st_select_lex_unit::reset_distinct()
+{
+  union_distinct= NULL;
+  for(SELECT_LEX *sl= first_select()->next_select();
+      sl;
+      sl= sl->next_select())
+  {
+    if (sl->distinct)
+    {
+      union_distinct= sl;
+      return;
+    }
+  }
+}
+
+
+void st_select_lex_unit::fix_distinct(st_select_lex_unit *new_unit)
+{
+  if (union_distinct)
+  {
+    if (this != union_distinct->master_unit())
+    {
+      DBUG_ASSERT(new_unit == union_distinct->master_unit());
+      new_unit->union_distinct= union_distinct;
+      reset_distinct();
+    }
+    else
+      new_unit->reset_distinct();
+  }
+}
+
+
+void st_select_lex_unit::register_select_chain(SELECT_LEX *first_sel)
+{
+  DBUG_ASSERT(first_sel != 0);
+  slave= first_sel;
+  for(SELECT_LEX *sel=first_sel; sel; sel= sel->next_select())
+  {
+    sel->master= (st_select_lex_node *)this;
+    uncacheable|= sel->uncacheable;
+  }
+}
+
+
+void st_select_lex::register_unit(SELECT_LEX_UNIT *unit,
+                                  Name_resolution_context *outer_context)
+{
+  if ((unit->next= slave))
+    slave->prev= &unit->next;
+  unit->prev= &slave;
+  slave= unit;
+  unit->master= this;
+  uncacheable|= unit->uncacheable;
+
+  for(SELECT_LEX *sel= unit->first_select();sel; sel= sel->next_select())
+  {
+    sel->context.outer_context= &context;
+  }
+}
+
+bool LEX::main_select_push()
+{
+  DBUG_ENTER("LEX::main_select_push");
+  if (push_select(&builtin_select))
+    DBUG_RETURN(TRUE);
+  DBUG_RETURN(FALSE);
+}
+
+void LEX::main_select_cut()
+{
+  DBUG_ENTER("LEX::main_select_cut");
+  if (thd->is_main_lex(this))
+    thd->select_number= 0;
+  unit.cut_subtree();
+  all_selects_list= 0;
+  builtin_select.link_prev= NULL; // indicator of removel
+  DBUG_VOID_RETURN;
+}
+
+bool LEX::new_main_select_anker(SELECT_LEX *sel)
+{
+  DBUG_ENTER("LEX::new_main_select_anker");
+  if (sel->set_nest_level(1))
+    DBUG_RETURN(TRUE);
+  unit.register_select_chain(sel);
+  sel->options|= builtin_select.options;
+
+  DBUG_RETURN(FALSE);
+}
+
+bool Lex_order_limit_lock::set_to(SELECT_LEX *sel)
+{
+  if (sel->master_unit()->first_select()->next_select())
+    sel= sel->master_unit()->fake_select_lex;
+  if (lock.defined_lock && sel == sel->master_unit()->fake_select_lex)
+    return TRUE;
+  sel->explicit_limit= limit.explicit_limit;
+  sel->select_limit= limit.select_limit;
+  sel->offset_limit= limit.offset_limit;
+  if (order_list)
+  {
+    if (sel->linkage != GLOBAL_OPTIONS_TYPE &&
+        sel->olap != UNSPECIFIED_OLAP_TYPE &&
+        (sel->linkage != UNION_TYPE || sel->braces))
+    {
+      my_error(ER_WRONG_USAGE, MYF(0),
+          "CUBE/ROLLUP", "ORDER BY");
+      return TRUE;
+    }
+    sel->order_list= *(order_list);
+  }
+  /*TODO: lock */
+  return FALSE;
+}
+
+
+static void change_item_list_context(List<Item> *list,
+                                     Name_resolution_context *context)
+{
+  List_iterator_fast<Item> it (*list);
+  Item *item;
+  while((item= it++))
+  {
+    item->walk(&Item::change_context_processor, FALSE, (void *)context);
+  }
+}
+
+
+bool LEX::insert_select_hack(SELECT_LEX *sel)
+{
+  DBUG_ENTER("LEX::insert_select_hack");
+
+  DBUG_ASSERT(first_select_lex() == &builtin_select);
+  DBUG_ASSERT(sel != NULL);
+  DBUG_ASSERT(sel->next_select() == NULL);
+
+
+  if (builtin_select.link_prev)
+  {
+    if ((*builtin_select.link_prev= builtin_select.link_next))
+      ((st_select_lex *)builtin_select.link_next)->link_prev=
+        builtin_select.link_prev;
+    builtin_select.link_prev= NULL; // indicator of removal
+  }
+
+  if (new_main_select_anker(sel))
+    DBUG_RETURN(TRUE);
+
+  DBUG_ASSERT(builtin_select.table_list.elements == 1);
+  TABLE_LIST *insert_table= builtin_select.table_list.first;
+
+  if (!(insert_table->next_local= sel->table_list.first))
+  {
+    sel->table_list.next= &insert_table->next_local;
+  }
+  sel->table_list.first= insert_table;
+  sel->table_list.elements++;
+  insert_table->select_lex= sel;
+
+  change_item_list_context(&field_list, &sel->context);
+  change_item_list_context(&update_list, &sel->context);
+  change_item_list_context(&value_list, &sel->context);
+
+  DBUG_RETURN(FALSE);
+}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 245e995bc2d..3af7a8b9641 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -73,6 +73,14 @@ enum sub_select_type
   UNION_TYPE, INTERSECT_TYPE, EXCEPT_TYPE,
   GLOBAL_OPTIONS_TYPE, DERIVED_TABLE_TYPE, OLAP_TYPE
 };
+
+inline int cmp_unit_op(enum sub_select_type op1, enum sub_select_type op2)
+{
+  DBUG_ASSERT(op1 >= UNION_TYPE && op1 <= EXCEPT_TYPE);
+  DBUG_ASSERT(op2 >= UNION_TYPE && op2 <= EXCEPT_TYPE);
+  return (op1 == INTERSECT_TYPE ? 1 : 0) - (op2 == INTERSECT_TYPE ? 1 : 0);
+}
+
 enum unit_common_op {OP_MIX, OP_UNION, OP_INTERSECT, OP_EXCEPT};
 
 enum enum_view_suid
@@ -201,6 +209,7 @@ struct LEX_TYPE
   additional "partitions" column even if partitioning is not compiled in.
 */
 #define DESCRIBE_PARTITIONS	4
+#define DESCRIBE_EXTENDED2	8
 
 #ifdef MYSQL_SERVER
 
@@ -420,9 +429,9 @@ class Index_hint : public Sql_alloc
   }
 
   void print(THD *thd, String *str);
-}; 
+};
 
-/* 
+/*
   The state of the lex parsing for selects 
    
    master and slaves are pointers to select_lex.
@@ -432,7 +441,7 @@ class Index_hint : public Sql_alloc
    unit is container of either
      - One SELECT
      - UNION of selects
-   select_lex and unit are both inherited form select_lex_node
+   select_lex and unit are both inherited form st_select_lex_node
    neighbors are two select_lex or units on the same level
 
    All select describing structures linked with following pointers:
@@ -574,6 +583,7 @@ class st_select_lex_node {
   */
   uint8 uncacheable;
   enum sub_select_type linkage;
+  bool distinct;
   bool no_table_names_allowed; /* used for global order by */
 
   static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
@@ -594,6 +604,14 @@ class st_select_lex_node {
   void include_down(st_select_lex_node *upper);
   void add_slave(st_select_lex_node *slave_arg);
   void include_neighbour(st_select_lex_node *before);
+  void link_neighbour(st_select_lex_node *neighbour)
+  {
+    DBUG_ASSERT(next == NULL);
+    DBUG_ASSERT(neighbour != NULL);
+    next= neighbour;
+    neighbour->prev= &next;
+  }
+  void cut_next() { next= NULL; }
   void include_standalone(st_select_lex_node *sel, st_select_lex_node **ref);
   void include_global(st_select_lex_node **plink);
   void exclude();
@@ -612,6 +630,22 @@ class st_select_lex_node {
   }
   st_select_lex_node *insert_chain_before(st_select_lex_node **ptr_pos_to_insert,
                                           st_select_lex_node *end_chain_node);
+  void set_linkage(enum sub_select_type l)
+  {
+    DBUG_ENTER("st_select_lex_node::set_linkage");
+    DBUG_PRINT("info", ("node: %p  linkage: %d->%d", this, linkage, l));
+    linkage= l;
+    DBUG_VOID_RETURN;
+  }
+  /*
+    This method created for reiniting LEX in mysql_admin_table() and can be
+    used only if you are going remove all SELECT_LEX & units except belonger
+    to LEX (LEX::unit & LEX::select, for other purposes there are
+    SELECT_LEX_UNIT::exclude_level & SELECT_LEX_UNIT::exclude_tree.
+
+    It is also used in parsing to detach builtin select.
+  */
+  void cut_subtree() { slave= 0; }
   friend class st_select_lex_unit;
   friend bool mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *sel);
   friend bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
@@ -621,6 +655,8 @@ class st_select_lex_node {
   friend bool mysql_derived_merge(THD *thd, LEX *lex,
                                   TABLE_LIST *orig_table_list);
   friend bool TABLE_LIST::init_derived(THD *thd, bool init_view);
+
+  friend class st_select_lex;
 private:
   void fast_exclude();
 };
@@ -797,6 +833,16 @@ class st_select_lex_unit: public st_select_lex_node {
   int save_union_explain(Explain_query *output);
   int save_union_explain_part2(Explain_query *output);
   unit_common_op common_op();
+
+  bool automatic_op_precedence();
+  void reset_distinct();
+  void fix_distinct(st_select_lex_unit *new_unit);
+
+  void register_select_chain(SELECT_LEX *first_sel);
+
+  bool set_nest_level(int new_nest_level);
+
+  friend class st_select_lex;
 };
 
 typedef class st_select_lex_unit SELECT_LEX_UNIT;
@@ -935,6 +981,7 @@ class st_select_lex: public st_select_lex_node
   */
   SELECT_LEX_UNIT *nest_level_base;
   int nest_level;     /* nesting level of select */
+  uint braces_depth;  /* used for parsing and differ from above */
   Item_sum *inner_sum_func_list; /* list of sum func in nested selects */ 
   uint with_wild; /* item list contain '*' */
   bool braces;    /* SELECT ... UNION (SELECT ... ) <- this braces */
@@ -1248,6 +1295,30 @@ class st_select_lex: public st_select_lex_node
     DBUG_ASSERT(this != sel);
     select_n_where_fields+= sel->select_n_where_fields;
   }
+  inline void set_linkage_and_distinct(enum sub_select_type l, bool d)
+  {
+    DBUG_ENTER("SELECT_LEX::set_linkage_and_distinct");
+    DBUG_PRINT("info", ("select: %p  distinct %d", this, d));
+    set_linkage(l);
+    DBUG_ASSERT(l == UNION_TYPE ||
+                l == INTERSECT_TYPE ||
+                l == EXCEPT_TYPE);
+    if (d && master_unit() && !master_unit()->union_distinct)
+      master_unit()->union_distinct= this;
+    distinct= d;
+    DBUG_VOID_RETURN;
+  }
+  bool set_nest_level(int new_nest_level);
+  void mark_select()
+  {
+    DBUG_ENTER("st_select_lex::mark_select()");
+    DBUG_PRINT("info", ("Select #%d", select_number));
+    DBUG_VOID_RETURN;
+  }
+  void register_unit(SELECT_LEX_UNIT *unit,
+                     Name_resolution_context *outer_context);
+  SELECT_LEX_UNIT *attach_selects_chain(SELECT_LEX *sel,
+                                        Name_resolution_context *context);
 };
 typedef class st_select_lex SELECT_LEX;
 
@@ -2612,7 +2683,8 @@ class Query_arena_memroot;
 struct LEX: public Query_tables_list
 {
   SELECT_LEX_UNIT unit;                         /* most upper unit */
-  SELECT_LEX select_lex;                        /* first SELECT_LEX */
+  inline SELECT_LEX *first_select_lex() {return unit.first_select();}
+  SELECT_LEX builtin_select;
   /* current SELECT_LEX in parsing */
   SELECT_LEX *current_select;
   /* list of all SELECT_LEX */
@@ -2693,7 +2765,24 @@ struct LEX: public Query_tables_list
   bool sp_for_loop_condition(THD *thd, const Lex_for_loop_st &loop);
   bool sp_for_loop_increment(THD *thd, const Lex_for_loop_st &loop);
 
+  uint braces_depth;
+
 public:
+  inline void braces_start()
+  {
+    DBUG_ENTER("braces_start");
+    braces_depth++;
+    DBUG_PRINT("info",("now depth is %u <", braces_depth));
+    DBUG_VOID_RETURN;
+  }
+  inline void braces_end()
+  {
+    DBUG_ENTER("braces_end");
+    braces_depth--;
+    DBUG_PRINT("info",("now depth is %u >", braces_depth));
+    DBUG_VOID_RETURN;
+  }
+  inline uint get_braces_depth() { return braces_depth; }
   inline bool is_arena_for_set_stmt() {return arena_for_set_stmt != 0;}
   bool set_arena_for_set_stmt(Query_arena *backup);
   void reset_arena_for_set_stmt(Query_arena *backup);
@@ -2719,6 +2808,9 @@ struct LEX: public Query_tables_list
     required a local context, the parser pops the top-most context.
   */
   List<Name_resolution_context> context_stack;
+  List<SELECT_LEX> last_select_stack;
+  SELECT_LEX *select_stack[MAX_SELECT_NESTING];
+  uint select_stack_top;
 
   SQL_I_List<ORDER> proc_list;
   SQL_I_List<TABLE_LIST> auxiliary_table_list, save_list;
@@ -2812,6 +2904,8 @@ struct LEX: public Query_tables_list
   enum enum_yes_no_unknown tx_chain, tx_release;
   bool safe_to_cache_query;
   bool subqueries, ignore;
+  bool next_is_main; // use "main" SELECT_LEX for nrxt allocation;
+  bool next_is_down; // use "main" SELECT_LEX for nrxt allocation;
   st_parsing_options parsing_options;
   Alter_info alter_info;
   /*
@@ -3002,13 +3096,16 @@ struct LEX: public Query_tables_list
     SELECT_LEX *sl;
     SELECT_LEX_UNIT *un;
     for (sl= current_select, un= sl->master_unit();
-	 un != &unit;
-	 sl= sl->outer_select(), un= sl->master_unit())
+	 un && un != &unit;
+	 sl= sl->outer_select(), un= (sl ? sl->master_unit() : NULL))
     {
       sl->uncacheable|= cause;
       un->uncacheable|= cause;
     }
-    select_lex.uncacheable|= cause;
+    if (sl)
+      sl->uncacheable|= cause;
+    if (first_select_lex())
+      first_select_lex()->uncacheable|= cause;
   }
   void set_trg_event_type_for_tables();
 
@@ -3054,12 +3151,112 @@ struct LEX: public Query_tables_list
 
   bool push_context(Name_resolution_context *context, MEM_ROOT *mem_root)
   {
-    return context_stack.push_front(context, mem_root);
+    DBUG_ENTER("LEX::push_context");
+    DBUG_PRINT("info", ("Context: %p Select: %p (%d)",
+                         context, context->select_lex,
+                         (context->select_lex ?
+                          context->select_lex->select_number:
+                          0)));
+    bool res= context_stack.push_front(context, mem_root);
+    DBUG_RETURN(res);
+  }
+
+  void pop_context(const char *str)
+  {
+    DBUG_ENTER("LEX::pop_context");
+    DBUG_PRINT("info", ("Context: '%s'", str));
+    Name_resolution_context *context= context_stack.pop();
+    DBUG_PRINT("info", ("Context: '%s' %p Select: %p (%d)",
+                         str,
+                         context, context->select_lex,
+                         (context->select_lex ?
+                          context->select_lex->select_number:
+                          0)));
+    DBUG_VOID_RETURN;
+  }
+
+  bool push_new_select(SELECT_LEX *last);
+
+  SELECT_LEX *pop_new_select()
+  {
+    DBUG_ENTER("LEX::pop_select_new");
+    SELECT_LEX* last= last_select_stack.pop();
+    DBUG_PRINT("info", ("Pop last elect: %p (%d)",
+                         last, last->select_number));
+    DBUG_RETURN(last);
+  }
+
+  SELECT_LEX *select_stack_head()
+  {
+    if (likely(select_stack_top))
+      return select_stack[select_stack_top - 1];
+    return NULL;
+  }
+
+
+  bool push_select(SELECT_LEX *select_lex)
+  {
+    DBUG_ENTER("LEX::push_select");
+    DBUG_PRINT("info", ("Top Select was %p (%d)  depth: %u  pushed: %p (%d)",
+                        select_stack_head(),
+                        select_stack_top,
+                        (select_stack_top ?
+                         select_stack_head()->select_number :
+                         0),
+                        select_lex, select_lex->select_number));
+    if (unlikely(select_stack_top == MAX_SELECT_NESTING))
+    {
+      my_error(ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT, MYF(0));
+      DBUG_RETURN(TRUE);
+    }
+    select_stack[select_stack_top++]= select_lex;
+    current_select= select_lex;
+    DBUG_RETURN(FALSE);
   }
 
-  void pop_context()
+  SELECT_LEX *pop_select()
   {
-    context_stack.pop();
+    DBUG_ENTER("LEX::pop_select");
+    SELECT_LEX *select_lex;
+    if (likely(select_stack_top))
+      select_lex= select_stack[--select_stack_top];
+    else
+      select_lex= 0;
+    DBUG_PRINT("info", ("Top Select is %p (%d)  depth: %u  poped: %p (%d)",
+                        select_stack_head(),
+                        select_stack_top,
+                        (select_stack_top ?
+                         select_stack_head()->select_number :
+                         0),
+                        select_lex,
+                        (select_lex ? select_lex->select_number : 0)));
+    DBUG_ASSERT(select_lex);
+
+    if (unlikely(!select_stack_top))
+    {
+      current_select= first_select_lex();
+      DBUG_PRINT("info", ("Top Select is empty, current set to main"));
+    }
+    else
+      current_select= select_stack[select_stack_top - 1];
+
+    DBUG_RETURN(select_lex);
+  }
+
+  bool push_select_and_context(SELECT_LEX *sel, MEM_ROOT *mem_root)
+  {
+    DBUG_ENTER("LEX::push_select_and_context");
+    bool res= (push_select(sel) ||
+               push_context(&sel->context, mem_root));
+    DBUG_RETURN(res);
+  }
+
+  SELECT_LEX *pop_select_and_context()
+  {
+    DBUG_ENTER("LEX::pop_select_and_context");
+    pop_context("Tail of select");
+    SELECT_LEX *res= pop_select();
+    DBUG_RETURN(res);
   }
 
   bool copy_db_to(const char **p_db, size_t *p_db_length) const;
@@ -3093,7 +3290,7 @@ struct LEX: public Query_tables_list
       on its top. So select_lex (as the first added) will be at the tail 
       of the list.
     */ 
-    if (&select_lex == all_selects_list && !sroutines.records)
+    if (first_select_lex() == all_selects_list && !sroutines.records)
     {
       DBUG_ASSERT(!all_selects_list->next_select_in_list());
       return TRUE;
@@ -3640,6 +3837,7 @@ struct LEX: public Query_tables_list
   bool if_exists() const { return create_info.if_exists(); }
 
   SELECT_LEX *exclude_last_select();
+  SELECT_LEX *exclude_not_first_select(SELECT_LEX *exclude);
   bool add_unit_in_brackets(SELECT_LEX *nselect);
   void check_automatic_up(enum sub_select_type type);
   bool create_or_alter_view_finalize(THD *thd, Table_ident *table_ident);
@@ -3648,9 +3846,24 @@ struct LEX: public Query_tables_list
   bool add_create_view(THD *thd, DDL_options_st ddl,
                        uint16 algorithm, enum_view_suid suid,
                        Table_ident *table_ident);
-
   bool add_grant_command(THD *thd, enum_sql_command sql_command_arg,
                          stored_procedure_type type_arg);
+  SELECT_LEX *push_selects_down(SELECT_LEX *exclude_start,
+                                SELECT_LEX *exclude_end, bool automatic);
+  bool make_select_in_brackets(SELECT_LEX* dummy_select,
+                               SELECT_LEX *nselect, bool automatic);
+  SELECT_LEX *shift_selects_down(SELECT_LEX *exclude_start);
+
+  SELECT_LEX_UNIT *alloc_unit();
+  SELECT_LEX *alloc_select(bool is_select);
+  SELECT_LEX_UNIT *create_unit(SELECT_LEX*);
+  SELECT_LEX *wrap_unit_into_derived(SELECT_LEX_UNIT *unit);
+  SELECT_LEX *link_selects_chain_down(SELECT_LEX *sel);
+  bool main_select_push();
+  void main_select_cut();
+  bool new_main_select_anker(SELECT_LEX *sel);
+  bool insert_select_hack(SELECT_LEX *sel);
+  SELECT_LEX *pop_new_select_and_wrap();
 };
 
 
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 6cd0b76c66d..0c649d0e150 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -329,10 +329,13 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
   if (mysql_handle_single_derived(thd->lex, table_list, DT_MERGE_FOR_INSERT) ||
       mysql_handle_single_derived(thd->lex, table_list, DT_PREPARE))
     DBUG_RETURN(TRUE);
-  if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context,
-                                    &thd->lex->select_lex.top_join_list,
+  if (setup_tables_and_check_access(thd,
+                                    &thd->lex->first_select_lex()->context,
+                                    &thd->lex->first_select_lex()->
+                                      top_join_list,
                                     table_list,
-                                    thd->lex->select_lex.leaf_tables, FALSE,
+                                    thd->lex->first_select_lex()->leaf_tables,
+                                    FALSE,
                                     INSERT_ACL | UPDATE_ACL,
                                     INSERT_ACL | UPDATE_ACL, FALSE))
      DBUG_RETURN(-1);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 82794367b74..969d49a17a2 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1978,10 +1978,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
       Init TABLE_LIST members necessary when the undelrying
       table is view.
     */
-    table_list.select_lex= &(thd->lex->select_lex);
+    table_list.select_lex= thd->lex->first_select_lex();
     thd->lex->
-      select_lex.table_list.link_in_list(&table_list,
-                                         &table_list.next_local);
+      first_select_lex()->table_list.link_in_list(&table_list,
+                                                  &table_list.next_local);
     thd->lex->add_to_query_tables(&table_list);
 
     if (is_infoschema_db(table_list.db, table_list.db_length))
@@ -2545,21 +2545,21 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
     {
       LEX_STRING db;
       size_t dummy;
-      if (lex->select_lex.db == NULL &&
-          lex->copy_db_to(&lex->select_lex.db, &dummy))
+      if (lex->first_select_lex()->db == NULL &&
+          lex->copy_db_to(&lex->first_select_lex()->db, &dummy))
       {
         DBUG_RETURN(1);
       }
       schema_select_lex= new (thd->mem_root) SELECT_LEX();
       schema_select_lex->table_list.first= NULL;
       if (lower_case_table_names == 1)
-        lex->select_lex.db= thd->strdup(lex->select_lex.db);
-      schema_select_lex->db= lex->select_lex.db;
+        lex->first_select_lex()->db= thd->strdup(lex->first_select_lex()->db);
+      schema_select_lex->db= lex->first_select_lex()->db;
       /*
         check_db_name() may change db.str if lower_case_table_names == 1,
         but that's ok as the db is allocted above in this case.
       */
-      db.str= (char*) lex->select_lex.db;
+      db.str= (char*) lex->first_select_lex()->db;
       db.length= strlen(db.str);
       if (check_db_name(&db))
       {
@@ -3192,7 +3192,7 @@ mysql_execute_command(THD *thd)
   int  up_result= 0;
   LEX  *lex= thd->lex;
   /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
-  SELECT_LEX *select_lex= &lex->select_lex;
+  SELECT_LEX *select_lex= lex->first_select_lex();
   /* first table of first SELECT_LEX */
   TABLE_LIST *first_table= select_lex->table_list.first;
   /* list of all tables in query */
@@ -7547,7 +7547,7 @@ mysql_init_select(LEX *lex)
   SELECT_LEX *select_lex= lex->current_select;
   select_lex->init_select();
   lex->wild= 0;
-  if (select_lex == &lex->select_lex)
+  if (select_lex == lex->first_select_lex())
   {
     DBUG_ASSERT(lex->result == 0);
     lex->exchange= 0;
@@ -7572,6 +7572,7 @@ mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *select_lex)
 {
   THD *thd= lex->thd;
   bool new_select= select_lex == NULL;
+  int old_nest_level= lex->current_select->nest_level;
   DBUG_ENTER("mysql_new_select");
 
   if (new_select)
@@ -7582,28 +7583,21 @@ mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *select_lex)
     select_lex->parent_lex= lex; /* Used in init_query. */
     select_lex->init_query();
     select_lex->init_select();
+    lex->current_select->braces_depth= lex->get_braces_depth();
   }
-  lex->nest_level++;
-  if (lex->nest_level > (int) MAX_SELECT_NESTING)
-  {
-    my_error(ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT, MYF(0));
-    DBUG_RETURN(1);
-  }
-  select_lex->nest_level= lex->nest_level;
   select_lex->nest_level_base= &thd->lex->unit;
   if (move_down)
   {
+    lex->nest_level++;
+    if (select_lex->set_nest_level(old_nest_level + 1))
+      DBUG_RETURN(1);
     SELECT_LEX_UNIT *unit;
     lex->subqueries= TRUE;
     /* first select_lex of subselect or derived table */
-    if (!(unit= new (thd->mem_root) SELECT_LEX_UNIT()))
+    if (!(unit= lex->alloc_unit()))
       DBUG_RETURN(1);
 
-    unit->init_query();
-    unit->thd= thd;
     unit->include_down(lex->current_select);
-    unit->link_next= 0;
-    unit->link_prev= 0;
     unit->return_to= lex->current_select;
     select_lex->include_down(unit);
     /*
@@ -7638,14 +7632,18 @@ mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *select_lex)
       DBUG_RETURN(TRUE);
     }
     // SELECT 1 FROM t1 ORDER BY 1 UNION SELECT 1 FROM t1 -- not possible
-    DBUG_ASSERT(!lex->current_select->order_list.first ||
-                lex->current_select->braces);
+    //DBUG_ASSERT(!lex->current_select->order_list.first ||
+    //            lex->current_select->braces);
     // SELECT 1 FROM t1 LIMIT 1 UNION SELECT 1 FROM t1;   -- not possible
-    DBUG_ASSERT(!lex->current_select->explicit_limit ||
-                lex->current_select->braces);
+    //DBUG_ASSERT(!lex->current_select->explicit_limit ||
+    //            lex->current_select->braces);
 
+    SELECT_LEX_NODE *save_slave= select_lex->slave;
     select_lex->include_neighbour(lex->current_select);
-    SELECT_LEX_UNIT *unit= select_lex->master_unit();                              
+    select_lex->slave= save_slave;
+    SELECT_LEX_UNIT *unit= select_lex->master_unit();
+    if (select_lex->set_nest_level(old_nest_level))
+      DBUG_RETURN(1);
     if (!unit->fake_select_lex && unit->add_fake_select_lex(lex->thd))
       DBUG_RETURN(1);
     select_lex->context.outer_context= 
@@ -7701,9 +7699,10 @@ void mysql_init_multi_delete(LEX *lex)
 {
   lex->sql_command=  SQLCOM_DELETE_MULTI;
   mysql_init_select(lex);
-  lex->select_lex.select_limit= 0;
+  lex->first_select_lex()->select_limit= 0;
   lex->unit.select_limit_cnt= HA_POS_ERROR;
-  lex->select_lex.table_list.save_and_clear(&lex->auxiliary_table_list);
+  lex->first_select_lex()->table_list.
+    save_and_clear(&lex->auxiliary_table_list);
   lex->query_tables= 0;
   lex->query_tables_last= &lex->query_tables;
 }
@@ -7985,7 +7984,7 @@ bool mysql_test_parse_for_slave(THD *thd, char *rawbuf, uint length)
     thd->reset_for_next_command();
 
     if (!parse_sql(thd, & parser_state, NULL, true) &&
-        all_tables_not_ok(thd, lex->select_lex.table_list.first))
+        all_tables_not_ok(thd, lex->first_select_lex()->table_list.first))
       error= 1;                  /* Ignore question */
     thd->end_statement();
   }
@@ -8067,6 +8066,9 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
   const char *alias_str;
   LEX *lex= thd->lex;
   DBUG_ENTER("add_table_to_list");
+  DBUG_PRINT("enter", ("Table '%s'  Select %p (%u)",
+                        (alias ? alias->str : table->table.str),
+                        this, select_number));
 
   if (!table)
     DBUG_RETURN(0);				// End of memory
@@ -8160,7 +8162,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
     ptr->schema_table_name= ptr->table_name;
     ptr->schema_table= schema_table;
   }
-  ptr->select_lex=  lex->current_select;
+  ptr->select_lex= this;
   /*
     We can't cache internal temporary tables between prepares as the
     table may be deleted before next exection.
@@ -8265,7 +8267,6 @@ bool st_select_lex::init_nested_join(THD *thd)
   nested_join= ptr->nested_join=
     ((NESTED_JOIN*) ((uchar*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST))));
 
-  join_list->push_front(ptr, thd->mem_root);
   ptr->embedding= embedding;
   ptr->join_list= join_list;
   ptr->alias= (char*) "(nested_join)";
@@ -8371,7 +8372,6 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
         ptr->join_using_fields= prev_join_using;
     }
   }
-  join_list->push_front(ptr, thd->mem_root);
   nested_join->used_tables= nested_join->not_null_tables= (table_map) 0;
   DBUG_RETURN(ptr);
 }
@@ -8563,7 +8563,7 @@ void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
 bool st_select_lex_unit::add_fake_select_lex(THD *thd_arg)
 {
   SELECT_LEX *first_sl= first_select();
-  DBUG_ENTER("add_fake_select_lex");
+  DBUG_ENTER("st_select_lex_unit::add_fake_select_lex");
   DBUG_ASSERT(!fake_select_lex);
 
   if (!(fake_select_lex= new (thd_arg->mem_root) SELECT_LEX()))
@@ -8573,7 +8573,7 @@ bool st_select_lex_unit::add_fake_select_lex(THD *thd_arg)
   fake_select_lex->select_number= INT_MAX;
   fake_select_lex->parent_lex= thd_arg->lex; /* Used in init_query. */
   fake_select_lex->make_empty_select();
-  fake_select_lex->linkage= GLOBAL_OPTIONS_TYPE;
+  fake_select_lex->set_linkage(GLOBAL_OPTIONS_TYPE);
   fake_select_lex->select_limit= 0;
 
   fake_select_lex->context.outer_context=first_sl->context.outer_context;
@@ -8582,7 +8582,8 @@ bool st_select_lex_unit::add_fake_select_lex(THD *thd_arg)
   fake_select_lex->context.select_lex= fake_select_lex;  
 
   fake_select_lex->nest_level_base= first_select()->nest_level_base;
-  fake_select_lex->nest_level=first_select()->nest_level;
+  if (fake_select_lex->set_nest_level(first_select()->nest_level))
+    DBUG_RETURN(1);
 
   if (!is_unit_op())
   {
@@ -8595,7 +8596,7 @@ bool st_select_lex_unit::add_fake_select_lex(THD *thd_arg)
     fake_select_lex->no_table_names_allowed= 1;
     thd_arg->lex->current_select= fake_select_lex;
   }
-  thd_arg->lex->pop_context();
+  thd_arg->lex->pop_context("add fake");
   DBUG_RETURN(0);
 }
 
@@ -8986,7 +8987,7 @@ bool check_simple_select()
 {
   THD *thd= current_thd;
   LEX *lex= thd->lex;
-  if (lex->current_select != &lex->select_lex)
+  if (lex->first_select_lex())
   {
     char command[80];
     Lex_input_stream *lip= & thd->m_parser_state->m_lip;
@@ -9086,7 +9087,7 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
   const char *msg= 0;
   TABLE_LIST *table;
   LEX *lex= thd->lex;
-  SELECT_LEX *select_lex= &lex->select_lex;
+  SELECT_LEX *select_lex= lex->first_select_lex();
   DBUG_ENTER("multi_update_precheck");
 
   if (select_lex->item_list.elements != lex->value_list.elements)
@@ -9122,7 +9123,7 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
   /*
     Is there tables of subqueries?
   */
-  if (&lex->select_lex != lex->all_selects_list)
+  if (lex->first_select_lex() != lex->all_selects_list)
   {
     DBUG_PRINT("info",("Checking sub query list"));
     for (table= tables; table; table= table->next_global)
@@ -9165,7 +9166,7 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables)
 
 bool multi_delete_precheck(THD *thd, TABLE_LIST *tables)
 {
-  SELECT_LEX *select_lex= &thd->lex->select_lex;
+  SELECT_LEX *select_lex= thd->lex->first_select_lex();
   TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first;
   TABLE_LIST **save_query_tables_own_last= thd->lex->query_tables_own_last;
   DBUG_ENTER("multi_delete_precheck");
@@ -9282,7 +9283,7 @@ static TABLE_LIST *multi_delete_table_match(LEX *lex, TABLE_LIST *tbl,
 
 bool multi_delete_set_locks_and_link_aux_tables(LEX *lex)
 {
-  TABLE_LIST *tables= lex->select_lex.table_list.first;
+  TABLE_LIST *tables= lex->first_select_lex()->table_list.first;
   TABLE_LIST *target_tbl;
   DBUG_ENTER("multi_delete_set_locks_and_link_aux_tables");
 
@@ -9327,7 +9328,8 @@ bool multi_delete_set_locks_and_link_aux_tables(LEX *lex)
 bool update_precheck(THD *thd, TABLE_LIST *tables)
 {
   DBUG_ENTER("update_precheck");
-  if (thd->lex->select_lex.item_list.elements != thd->lex->value_list.elements)
+  if (thd->lex->first_select_lex()->item_list.elements !=
+      thd->lex->value_list.elements)
   {
     my_message(ER_WRONG_VALUE_COUNT, ER_THD(thd, ER_WRONG_VALUE_COUNT), MYF(0));
     DBUG_RETURN(TRUE);
@@ -9410,7 +9412,7 @@ void create_table_set_open_action_and_adjust_tables(LEX *lex)
   else
     create_table->open_type= OT_BASE_ONLY;
 
-  if (!lex->select_lex.item_list.elements)
+  if (!lex->first_select_lex()->item_list.elements)
   {
     /*
       Avoid opening and locking target table for ordinary CREATE TABLE
@@ -9441,7 +9443,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
                            TABLE_LIST *create_table)
 {
   LEX *lex= thd->lex;
-  SELECT_LEX *select_lex= &lex->select_lex;
+  SELECT_LEX *select_lex= lex->first_select_lex();
   ulong want_priv;
   bool error= TRUE;                                 // Error message is given
   DBUG_ENTER("create_table_precheck");
@@ -9950,6 +9952,7 @@ bool parse_sql(THD *thd, Parser_state *parser_state,
          ((thd->variables.sql_mode & MODE_ORACLE) ?
           ORAparse(thd) :
           MYSQLparse(thd)) != 0;
+  thd->lex->current_select= thd->lex->first_select_lex();
 
   /*
     Check that if MYSQLparse() failed either thd->is_error() is set, or an
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 9fc67272bfa..5385386349d 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -917,7 +917,8 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
     goto end;
   table->get_fields_in_item_tree= true;
 
-  func_expr->walk(&Item::change_context_processor, 0, &lex.select_lex.context);
+  func_expr->walk(&Item::change_context_processor, 0,
+                  &lex.first_select_lex()->context);
   thd->where= "partition function";
   /*
     In execution we must avoid the use of thd->change_item_tree since
diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc
index 0c1c9fb02de..2b069d06551 100644
--- a/sql/sql_partition_admin.cc
+++ b/sql/sql_partition_admin.cc
@@ -51,7 +51,7 @@ bool Sql_cmd_alter_table_exchange_partition::execute(THD *thd)
   /* Moved from mysql_execute_command */
   LEX *lex= thd->lex;
   /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
-  SELECT_LEX *select_lex= &lex->select_lex;
+  SELECT_LEX *select_lex= lex->first_select_lex();
   /* first table of first SELECT_LEX */
   TABLE_LIST *first_table= (TABLE_LIST*) select_lex->table_list.first;
   /*
@@ -739,7 +739,7 @@ bool Sql_cmd_alter_table_truncate_partition::execute(THD *thd)
   int error;
   ha_partition *partition;
   ulong timeout= thd->variables.lock_wait_timeout;
-  TABLE_LIST *first_table= thd->lex->select_lex.table_list.first;
+  TABLE_LIST *first_table= thd->lex->first_select_lex()->table_list.first;
   Alter_info *alter_info= &thd->lex->alter_info;
   uint table_counter, i;
   List<String> partition_names_list;
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index b81d1f7542b..f09ee450e17 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1400,7 +1400,7 @@ static int mysql_test_update(Prepared_statement *stmt,
   int res;
   THD *thd= stmt->thd;
   uint table_count= 0;
-  SELECT_LEX *select= &stmt->lex->select_lex;
+  SELECT_LEX *select= stmt->lex->first_select_lex();
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
   uint          want_privilege;
 #endif
@@ -1454,10 +1454,10 @@ static int mysql_test_update(Prepared_statement *stmt,
   table_list->table->grant.want_privilege= want_privilege;
   table_list->register_want_access(want_privilege);
 #endif
-  thd->lex->select_lex.no_wrap_view_item= TRUE;
+  thd->lex->first_select_lex()->no_wrap_view_item= TRUE;
   res= setup_fields(thd, Ref_ptr_array(),
                     select->item_list, MARK_COLUMNS_READ, 0, 0);
-  thd->lex->select_lex.no_wrap_view_item= FALSE;
+  thd->lex->first_select_lex()->no_wrap_view_item= FALSE;
   if (res)
     goto error;
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -1522,10 +1522,10 @@ static bool mysql_test_delete(Prepared_statement *stmt,
     goto error;
   }
 
-  DBUG_RETURN(mysql_prepare_delete(thd, table_list, 
-                                   lex->select_lex.with_wild, 
-                                   lex->select_lex.item_list,
-                                   &lex->select_lex.where,
+  DBUG_RETURN(mysql_prepare_delete(thd, table_list,
+                                   lex->first_select_lex()->with_wild,
+                                   lex->first_select_lex()->item_list,
+                                   &lex->first_select_lex()->where,
                                    &delete_while_scanning));
 error:
   DBUG_RETURN(TRUE);
@@ -1557,7 +1557,7 @@ static int mysql_test_select(Prepared_statement *stmt,
   SELECT_LEX_UNIT *unit= &lex->unit;
   DBUG_ENTER("mysql_test_select");
 
-  lex->select_lex.context.resolve_in_select_list= TRUE;
+  lex->first_select_lex()->context.resolve_in_select_list= TRUE;
 
   ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL;
   if (check_dependencies_in_with_clauses(lex->with_clauses_list))
@@ -1593,7 +1593,7 @@ static int mysql_test_select(Prepared_statement *stmt,
   if (!lex->describe && !thd->lex->analyze_stmt && !stmt->is_sql_prepare())
   {
     /* Make copy of item list, as change_columns may change it */
-    List<Item> fields(lex->select_lex.item_list);
+    List<Item> fields(lex->first_select_lex()->item_list);
 
     /* Change columns if a procedure like analyse() */
     if (unit->last_procedure && unit->last_procedure->change_columns(thd, fields))
@@ -1751,7 +1751,7 @@ static bool select_like_stmt_test(Prepared_statement *stmt,
   THD *thd= stmt->thd;
   LEX *lex= stmt->lex;
 
-  lex->select_lex.context.resolve_in_select_list= TRUE;
+  lex->first_select_lex()->context.resolve_in_select_list= TRUE;
 
   if (specific_prepare && (*specific_prepare)(thd))
     DBUG_RETURN(TRUE);
@@ -1819,7 +1819,7 @@ static bool mysql_test_create_table(Prepared_statement *stmt)
   DBUG_ENTER("mysql_test_create_table");
   THD *thd= stmt->thd;
   LEX *lex= stmt->lex;
-  SELECT_LEX *select_lex= &lex->select_lex;
+  SELECT_LEX *select_lex= lex->first_select_lex();
   bool res= FALSE;
   bool link_to_local;
   TABLE_LIST *create_table= lex->query_tables;
@@ -2142,7 +2142,7 @@ static bool mysql_test_multidelete(Prepared_statement *stmt,
 {
   THD *thd= stmt->thd;
 
-  thd->lex->current_select= &thd->lex->select_lex;
+  thd->lex->current_select= thd->lex->first_select_lex();
   if (add_item_to_list(thd, new (thd->mem_root)
                        Item_null(thd)))
   {
@@ -2181,13 +2181,14 @@ static bool mysql_test_multidelete(Prepared_statement *stmt,
 
 static int mysql_insert_select_prepare_tester(THD *thd)
 {
-  SELECT_LEX *first_select= &thd->lex->select_lex;
+  SELECT_LEX *first_select= thd->lex->first_select_lex();
   TABLE_LIST *second_table= first_select->table_list.first->next_local;
 
   /* Skip first table, which is the table we are inserting in */
   first_select->table_list.first= second_table;
-  thd->lex->select_lex.context.table_list=
-    thd->lex->select_lex.context.first_name_resolution_table= second_table;
+  thd->lex->first_select_lex()->context.table_list=
+    thd->lex->first_select_lex()->context.first_name_resolution_table=
+    second_table;
 
   return mysql_insert_select_prepare(thd);
 }
@@ -2225,7 +2226,7 @@ static bool mysql_test_insert_select(Prepared_statement *stmt,
     return 1;
 
   /* store it, because mysql_insert_select_prepare_tester change it */
-  first_local_table= lex->select_lex.table_list.first;
+  first_local_table= lex->first_select_lex()->table_list.first;
   DBUG_ASSERT(first_local_table != 0);
 
   res=
@@ -2233,7 +2234,7 @@ static bool mysql_test_insert_select(Prepared_statement *stmt,
                                     &mysql_insert_select_prepare_tester,
                                     OPTION_SETUP_TABLES_DONE);
   /* revert changes  made by mysql_insert_select_prepare_tester */
-  lex->select_lex.table_list.first= first_local_table;
+  lex->first_select_lex()->table_list.first= first_local_table;
   return res;
 }
 
@@ -2259,7 +2260,7 @@ static int mysql_test_handler_read(Prepared_statement *stmt,
   SQL_HANDLER *ha_table;
   DBUG_ENTER("mysql_test_handler_read");
 
-  lex->select_lex.context.resolve_in_select_list= TRUE;
+  lex->first_select_lex()->context.resolve_in_select_list= TRUE;
 
   /*
     We don't have to test for permissions as this is already done during
@@ -2268,7 +2269,7 @@ static int mysql_test_handler_read(Prepared_statement *stmt,
   if (!(ha_table= mysql_ha_read_prepare(thd, tables, lex->ha_read_mode,
                                         lex->ident.str,
                                         lex->insert_list,
-                                        lex->select_lex.where)))
+                                        lex->first_select_lex()->where)))
     DBUG_RETURN(1);
 
   if (!stmt->is_sql_prepare())
@@ -2309,7 +2310,7 @@ static bool check_prepared_statement(Prepared_statement *stmt)
 {
   THD *thd= stmt->thd;
   LEX *lex= stmt->lex;
-  SELECT_LEX *select_lex= &lex->select_lex;
+  SELECT_LEX *select_lex= lex->first_select_lex();
   TABLE_LIST *tables;
   enum enum_sql_command sql_command= lex->sql_command;
   int res= 0;
@@ -2321,7 +2322,7 @@ static bool check_prepared_statement(Prepared_statement *stmt)
   tables= lex->query_tables;
 
   /* set context for commands which do not use setup_tables */
-  lex->select_lex.context.resolve_in_table_list_only(select_lex->
+  lex->first_select_lex()->context.resolve_in_table_list_only(select_lex->
                                                      get_table_list());
 
   /* Reset warning count for each query that uses tables */
@@ -3004,7 +3005,7 @@ void reinit_stmt_before_use(THD *thd, LEX *lex)
   {
     tables->reinit_before_use(thd);
   }
-  lex->current_select= &lex->select_lex;
+  lex->current_select= lex->first_select_lex();
 
 
   if (lex->result)
@@ -4521,8 +4522,8 @@ bool Prepared_statement::validate_metadata(Prepared_statement *copy)
   if (is_sql_prepare() || lex->describe)
     return FALSE;
 
-  if (lex->select_lex.item_list.elements !=
-      copy->lex->select_lex.item_list.elements)
+  if (lex->first_select_lex()->item_list.elements !=
+      copy->lex->first_select_lex()->item_list.elements)
   {
     /** Column counts mismatch, update the client */
     thd->server_status|= SERVER_STATUS_METADATA_CHANGED;
diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc
index c1a13ebd210..a605f7f6bc4 100644
--- a/sql/sql_profile.cc
+++ b/sql/sql_profile.cc
@@ -110,7 +110,7 @@ int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table)
   };
 
   ST_FIELD_INFO *field_info;
-  Name_resolution_context *context= &thd->lex->select_lex.context;
+  Name_resolution_context *context= &thd->lex->first_select_lex()->context;
   int i;
 
   for (i= 0; schema_table->fields_info[i].field_name != NULL; i++)
@@ -403,7 +403,7 @@ bool PROFILING::show_profiles()
   QUERY_PROFILE *prof;
   List<Item> field_list;
   MEM_ROOT *mem_root= thd->mem_root;
-  SELECT_LEX *sel= &thd->lex->select_lex;
+  SELECT_LEX *sel= thd->lex->first_select_lex();
   SELECT_LEX_UNIT *unit= &thd->lex->unit;
   ha_rows idx= 0;
   Protocol *protocol= thd->protocol;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index ba3d2e7da2f..a73c8377aa0 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -347,7 +347,7 @@ bool handle_select(THD *thd, LEX *lex, select_result *result,
                    ulong setup_tables_done_option)
 {
   bool res;
-  register SELECT_LEX *select_lex = &lex->select_lex;
+  register SELECT_LEX *select_lex= lex->first_select_lex();
   DBUG_ENTER("handle_select");
   MYSQL_SELECT_START(thd->query());
 
@@ -12380,7 +12380,8 @@ void JOIN::join_free()
       !(select_options & SELECT_NO_UNLOCK) &&
       !select_lex->subquery_in_having &&
       (select_lex == (thd->lex->unit.fake_select_lex ?
-                      thd->lex->unit.fake_select_lex : &thd->lex->select_lex)))
+                      thd->lex->unit.fake_select_lex :
+                      thd->lex->first_select_lex())))
   {
     /*
       TODO: unlock tables even if the join isn't top level select in the
@@ -18067,7 +18068,7 @@ create_internal_tmp_table_from_heap(THD *thd, TABLE *table,
   new_table.no_rows= table->no_rows;
   if (create_internal_tmp_table(&new_table, table->key_info, start_recinfo,
                                 recinfo,
-                                thd->lex->select_lex.options | 
+                                thd->lex->builtin_select.options |
 			        thd->variables.option_bits))
     goto err2;
   if (open_tmp_table(&new_table))
@@ -24544,7 +24545,8 @@ void JOIN_TAB::save_explain_data(Explain_table_access *eta,
     */
     if (real_table->merged_for_insert)
     {
-      TABLE_LIST *view_child= real_table->view->select_lex.table_list.first;
+      TABLE_LIST *view_child=
+        real_table->view->first_select_lex()->table_list.first;
       for (;view_child; view_child= view_child->next_local)
       {
         if (view_child->table == table)
@@ -25605,6 +25607,18 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type)
   {
     str->append("/* select#");
     str->append_ulonglong(select_number);
+    if (thd->lex->describe & DESCRIBE_EXTENDED2)
+    {
+      str->append("/");
+      str->append_ulonglong(nest_level);
+
+      if (master_unit()->fake_select_lex &&
+          master_unit()->first_select() == this)
+      {
+        str->append(" Filter Select: ");
+        master_unit()->fake_select_lex->print(thd, str, query_type);
+      }
+    }
     str->append(" */ ");
   }
 
diff --git a/sql/sql_sequence.cc b/sql/sql_sequence.cc
index 53c9c160593..18c76d7446d 100644
--- a/sql/sql_sequence.cc
+++ b/sql/sql_sequence.cc
@@ -220,8 +220,8 @@ bool check_sequence_fields(LEX *lex, List<Create_field> *fields)
 
 err:
   my_error(ER_SEQUENCE_INVALID_TABLE_STRUCTURE, MYF(0),
-           lex->select_lex.table_list.first->db,
-           lex->select_lex.table_list.first->table_name, reason);
+           lex->first_select_lex()->table_list.first->db,
+           lex->first_select_lex()->table_list.first->table_name, reason);
   DBUG_RETURN(TRUE);
 }
 
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 68ded844938..27e061fca45 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -3936,8 +3936,9 @@ bool get_lookup_field_values(THD *thd, COND *cond, TABLE_LIST *tables,
   case SQLCOM_SHOW_TABLE_STATUS:
   case SQLCOM_SHOW_TRIGGERS:
   case SQLCOM_SHOW_EVENTS:
-    thd->make_lex_string(&lookup_field_values->db_value, 
-                         lex->select_lex.db, strlen(lex->select_lex.db));
+    thd->make_lex_string(&lookup_field_values->db_value,
+                         lex->first_select_lex()->db,
+                         strlen(lex->first_select_lex()->db));
     if (wild)
     {
       thd->make_lex_string(&lookup_field_values->table_value, 
@@ -4330,10 +4331,10 @@ fill_schema_table_by_open(THD *thd, bool is_show_fields_or_keys,
     temporary LEX. The latter is required to correctly open views and
     produce table describing their structure.
   */
-  if (make_table_list(thd, &lex->select_lex, &db_name, &table_name))
+  if (make_table_list(thd, lex->first_select_lex(), &db_name, &table_name))
     goto end;
 
-  table_list= lex->select_lex.table_list.first;
+  table_list= lex->first_select_lex()->table_list.first;
 
   if (is_show_fields_or_keys)
   {
@@ -6380,7 +6381,7 @@ static int get_schema_views_record(THD *thd, TABLE_LIST *tables,
           & 'field_translation_end' are uninitialized is this
           case.
         */
-        List<Item> *fields= &tables->view->select_lex.item_list;
+        List<Item> *fields= &tables->view->first_select_lex()->item_list;
         List_iterator<Item> it(*fields);
         Item *item;
         Item_field *field;
@@ -7354,7 +7355,7 @@ int fill_open_tables(THD *thd, TABLE_LIST *tables, COND *cond)
   TABLE *table= tables->table;
   CHARSET_INFO *cs= system_charset_info;
   OPEN_TABLE_LIST *open_list;
-  if (!(open_list=list_open_tables(thd,thd->lex->select_lex.db, wild))
+  if (!(open_list=list_open_tables(thd, thd->lex->first_select_lex()->db, wild))
             && thd->is_fatal_error)
     DBUG_RETURN(1);
 
@@ -7768,7 +7769,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
   tmp_table_param->table_charset= cs;
   tmp_table_param->field_count= field_count;
   tmp_table_param->schema_table= 1;
-  SELECT_LEX *select_lex= thd->lex->current_select;
+  SELECT_LEX *select_lex= table_list->select_lex;
   bool keep_row_order= sql_command_flags[thd->lex->sql_command] & CF_STATUS_COMMAND;
   if (!(table= create_tmp_table(thd, tmp_table_param,
                                 field_list, (ORDER*) 0, 0, 0, 
@@ -7805,7 +7806,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
 static int make_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
 {
   ST_FIELD_INFO *field_info= schema_table->fields_info;
-  Name_resolution_context *context= &thd->lex->select_lex.context;
+  Name_resolution_context *context= &thd->lex->first_select_lex()->context;
   for (; field_info->field_name; field_info++)
   {
     if (field_info->old_name)
@@ -7865,14 +7866,14 @@ int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
   char tmp[128];
   String buffer(tmp,sizeof(tmp), thd->charset());
   LEX *lex= thd->lex;
-  Name_resolution_context *context= &lex->select_lex.context;
+  Name_resolution_context *context= &lex->first_select_lex()->context;
   ST_FIELD_INFO *field_info= &schema_table->fields_info[2];
   LEX_CSTRING field_name= {field_info->field_name,
                            strlen(field_info->field_name) };
 
   buffer.length(0);
   buffer.append(field_info->old_name);
-  buffer.append(lex->select_lex.db);
+  buffer.append(lex->first_select_lex()->db);
   if (lex->wild && lex->wild->ptr())
   {
     buffer.append(STRING_WITH_LEN(" ("));
@@ -7905,7 +7906,7 @@ int make_columns_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
   int fields_arr[]= {3, 15, 14, 6, 16, 5, 17, 18, 19, -1};
   int *field_num= fields_arr;
   ST_FIELD_INFO *field_info;
-  Name_resolution_context *context= &thd->lex->select_lex.context;
+  Name_resolution_context *context= &thd->lex->first_select_lex()->context;
 
   for (; *field_num >= 0; field_num++)
   {
@@ -7936,7 +7937,7 @@ int make_character_sets_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
   int fields_arr[]= {0, 2, 1, 3, -1};
   int *field_num= fields_arr;
   ST_FIELD_INFO *field_info;
-  Name_resolution_context *context= &thd->lex->select_lex.context;
+  Name_resolution_context *context= &thd->lex->first_select_lex()->context;
 
   for (; *field_num >= 0; field_num++)
   {
@@ -7963,7 +7964,7 @@ int make_proc_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
   int fields_arr[]= {2, 3, 4, 27, 24, 23, 22, 26, 28, 29, 30, -1};
   int *field_num= fields_arr;
   ST_FIELD_INFO *field_info;
-  Name_resolution_context *context= &thd->lex->select_lex.context;
+  Name_resolution_context *context= &thd->lex->first_select_lex()->context;
 
   for (; *field_num >= 0; field_num++)
   {
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 9c746e470f7..8255aeb34d1 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -4673,7 +4673,7 @@ int create_table_impl(THD *thd,
         /*
           Restart statement transactions for the case of CREATE ... SELECT.
         */
-        if (thd->lex->select_lex.item_list.elements &&
+        if (thd->lex->first_select_lex()->item_list.elements &&
             restart_trans_for_tables(thd, thd->lex->query_tables))
           goto err;
       }
@@ -9758,8 +9758,8 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
       Filesort_tracker dummy_tracker(false);
       Filesort fsort(order, HA_POS_ERROR, true, NULL);
 
-      if (thd->lex->select_lex.setup_ref_array(thd, order_num) ||
-          setup_order(thd, thd->lex->select_lex.ref_pointer_array,
+      if (thd->lex->first_select_lex()->setup_ref_array(thd, order_num) ||
+          setup_order(thd, thd->lex->first_select_lex()->ref_pointer_array,
                       &tables, fields, all_fields, order))
         goto err;
 
diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc
index 1d6edbc5fc9..3fcab7c1bd8 100644
--- a/sql/sql_truncate.cc
+++ b/sql/sql_truncate.cc
@@ -493,7 +493,7 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref)
 bool Sql_cmd_truncate_table::execute(THD *thd)
 {
   bool res= TRUE;
-  TABLE_LIST *first_table= thd->lex->select_lex.table_list.first;
+  TABLE_LIST *first_table= thd->lex->first_select_lex()->table_list.first;
   DBUG_ENTER("Sql_cmd_truncate_table::execute");
 
   if (check_one_table_access(thd, DROP_ACL, first_table))
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 362837834f2..5e7f871d472 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -1393,7 +1393,7 @@ bool st_select_lex_unit::exec()
         union_result->change_select();
       if (fake_select_lex)
       {
-        if (sl != &thd->lex->select_lex)
+        if (sl != thd->lex->first_select_lex())
           fake_select_lex->uncacheable|= sl->uncacheable;
         else
           fake_select_lex->uncacheable= 0;
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 3f39765b531..d8050b1ec77 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -272,7 +272,7 @@ int mysql_update(THD *thd,
   SQL_SELECT	*select= NULL;
   SORT_INFO     *file_sort= 0;
   READ_RECORD	info;
-  SELECT_LEX    *select_lex= &thd->lex->select_lex;
+  SELECT_LEX    *select_lex= thd->lex->first_select_lex();
   ulonglong     id;
   List<Item> all_fields;
   killed_state killed_status= NOT_KILLED;
@@ -321,7 +321,7 @@ int mysql_update(THD *thd,
   table->covering_keys= table->s->keys_in_use;
   table->quick_keys.clear_all();
 
-  query_plan.select_lex= &thd->lex->select_lex;
+  query_plan.select_lex= thd->lex->first_select_lex();
   query_plan.table= table;
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
   /* Force privilege re-checking for views after they have been opened. */
@@ -1076,7 +1076,7 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
   TABLE *table= table_list->table;
 #endif
   List<Item> all_fields;
-  SELECT_LEX *select_lex= &thd->lex->select_lex;
+  SELECT_LEX *select_lex= thd->lex->first_select_lex();
   DBUG_ENTER("mysql_prepare_update");
 
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -1353,7 +1353,7 @@ int mysql_multi_update_prepare(THD *thd)
   LEX *lex= thd->lex;
   TABLE_LIST *table_list= lex->query_tables;
   TABLE_LIST *tl;
-  List<Item> *fields= &lex->select_lex.item_list;
+  List<Item> *fields= &lex->first_select_lex()->item_list;
   table_map tables_for_update;
   bool update_view= 0;
   /*
@@ -1394,14 +1394,15 @@ int mysql_multi_update_prepare(THD *thd)
   if (mysql_handle_derived(lex, DT_PREPARE))
     DBUG_RETURN(TRUE);
 
-  if (setup_tables_and_check_access(thd, &lex->select_lex.context,
-                                    &lex->select_lex.top_join_list,
+  if (setup_tables_and_check_access(thd,
+                                    &lex->first_select_lex()->context,
+                                    &lex->first_select_lex()->top_join_list,
                                     table_list,
-                                    lex->select_lex.leaf_tables, FALSE,
-                                    UPDATE_ACL, SELECT_ACL, FALSE))
+                                    lex->first_select_lex()->leaf_tables,
+                                    FALSE, UPDATE_ACL, SELECT_ACL, FALSE))
     DBUG_RETURN(TRUE);
 
-  if (lex->select_lex.handle_derived(thd->lex, DT_MERGE))  
+  if (lex->first_select_lex()->handle_derived(thd->lex, DT_MERGE))
     DBUG_RETURN(TRUE);
 
   if (setup_fields_with_no_wrap(thd, Ref_ptr_array(),
@@ -1424,13 +1425,14 @@ int mysql_multi_update_prepare(THD *thd)
 
   thd->table_map_for_update= tables_for_update= get_table_map(fields);
 
-  if (unsafe_key_update(lex->select_lex.leaf_tables, tables_for_update))
+  if (unsafe_key_update(lex->first_select_lex()->leaf_tables,
+                        tables_for_update))
     DBUG_RETURN(true);
 
   /*
     Setup timestamp handling and locking mode
   */
-  List_iterator<TABLE_LIST> ti(lex->select_lex.leaf_tables);
+  List_iterator<TABLE_LIST> ti(lex->first_select_lex()->leaf_tables);
   while ((tl= ti++))
   {
     TABLE *table= tl->table;
@@ -1523,7 +1525,7 @@ int mysql_multi_update_prepare(THD *thd)
     Check that we are not using table that we are updating, but we should
     skip all tables of UPDATE SELECT itself
   */
-  lex->select_lex.exclude_from_table_unique_test= TRUE;
+  lex->first_select_lex()->exclude_from_table_unique_test= TRUE;
   /* We only need SELECT privilege for columns in the values list */
   ti.rewind();
   while ((tl= ti++))
@@ -1555,7 +1557,7 @@ int mysql_multi_update_prepare(THD *thd)
     Set exclude_from_table_unique_test value back to FALSE. It is needed for
     further check in multi_update::prepare whether to use record cache.
   */
-  lex->select_lex.exclude_from_table_unique_test= FALSE;
+  lex->first_select_lex()->exclude_from_table_unique_test= FALSE;
 
   if (lex->save_prep_leaf_tables())
     DBUG_RETURN(TRUE);
@@ -1584,7 +1586,7 @@ bool mysql_multi_update(THD *thd,
   DBUG_ENTER("mysql_multi_update");
   
   if (!(*result= new (thd->mem_root) multi_update(thd, table_list,
-                                 &thd->lex->select_lex.leaf_tables,
+                                 &thd->lex->first_select_lex()->leaf_tables,
                                  fields, values,
                                  handle_duplicates, ignore)))
   {
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 26941e9d6e7..36fe34efe3a 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -254,7 +254,7 @@ bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view,
   LEX *lex= thd->lex;
   /* first table in list is target VIEW name => cut off it */
   TABLE_LIST *tbl;
-  SELECT_LEX *select_lex= &lex->select_lex;
+  SELECT_LEX *select_lex= lex->first_select_lex();
   SELECT_LEX *sl;
   bool res= TRUE;
   DBUG_ENTER("create_view_precheck");
@@ -324,7 +324,7 @@ bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view,
     }
   }
 
-  if (&lex->select_lex != lex->all_selects_list)
+  if (lex->first_select_lex() != lex->all_selects_list)
   {
     /* check tables of subqueries */
     for (tbl= tables; tbl; tbl= tbl->next_global)
@@ -400,7 +400,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
   TABLE_LIST *view= lex->unlink_first_table(&link_to_local);
   TABLE_LIST *tables= lex->query_tables;
   TABLE_LIST *tbl;
-  SELECT_LEX *select_lex= &lex->select_lex;
+  SELECT_LEX *select_lex= lex->first_select_lex();
   SELECT_LEX *sl;
   SELECT_LEX_UNIT *unit= &lex->unit;
   bool res= FALSE;
@@ -982,7 +982,7 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
                               view->algorithm != VIEW_ALGORITHM_TMPTABLE)))
   {
     /* TODO: change here when we will support UNIONs */
-    for (TABLE_LIST *tbl= lex->select_lex.table_list.first;
+    for (TABLE_LIST *tbl= lex->first_select_lex()->table_list.first;
 	 tbl;
 	 tbl= tbl->next_local)
     {
@@ -1100,8 +1100,8 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
     UNION
   */
   if (view->updatable_view &&
-      !lex->select_lex.master_unit()->is_unit_op() &&
-      !(lex->select_lex.table_list.first)->next_local &&
+      !lex->first_select_lex()->master_unit()->is_unit_op() &&
+      !(lex->first_select_lex()->table_list.first)->next_local &&
       find_table_in_global_list(lex->query_tables->next_global,
 				lex->query_tables->db,
 				lex->query_tables->table_name))
@@ -1349,8 +1349,6 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
       goto end;
 
     lex_start(thd);
-    view_select= &lex->select_lex;
-    view_select->select_number= ++thd->select_number;
 
     sql_mode_t saved_mode= thd->variables.sql_mode;
     /* switch off modes which can prevent normal parsing of VIEW
@@ -1385,6 +1383,9 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
 
     parse_status= parse_sql(thd, & parser_state, table->view_creation_ctx);
 
+    view_select= lex->first_select_lex();
+    //view_select->select_number= ++thd->select_number;
+
     lex->number_of_selects=
       (thd->select_number - view_select->select_number) + 1;
 
@@ -1537,7 +1538,7 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
         This may change in future, for example if we enable merging of
         views with subqueries in select list.
       */
-      view_main_select_tables= lex->select_lex.table_list.first;
+      view_main_select_tables= lex->first_select_lex()->table_list.first;
 
       /*
         Let us set proper lock type for tables of the view's main
@@ -1565,7 +1566,7 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
 
       /* Fields in this view can be used in upper select in case of merge.  */
       if (table->select_lex)
-        table->select_lex->add_where_field(&lex->select_lex);
+        table->select_lex->add_where_field(lex->first_select_lex());
     }
     /*
       This method has a dependency on the proper lock type being set,
@@ -1587,8 +1588,8 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
     old_lex->safe_to_cache_query= (old_lex->safe_to_cache_query &&
 				   lex->safe_to_cache_query);
     /* move SQL_CACHE to whole query */
-    if (view_select->options & OPTION_TO_QUERY_CACHE)
-      old_lex->select_lex.options|= OPTION_TO_QUERY_CACHE;
+    if (lex->builtin_select.options & OPTION_TO_QUERY_CACHE)
+      old_lex->builtin_select.options|= OPTION_TO_QUERY_CACHE;
 
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
     if (table->view_suid)
@@ -1670,9 +1671,10 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
         tbl->grant.want_privilege= top_view->grant.orig_want_privilege;
 
       /* prepare view context */
-      lex->select_lex.context.resolve_in_table_list_only(view_main_select_tables);
-      lex->select_lex.context.outer_context= 0;
-      lex->select_lex.select_n_having_items+=
+      lex->first_select_lex()->
+        context.resolve_in_table_list_only(view_main_select_tables);
+      lex->first_select_lex()->context.outer_context= 0;
+      lex->first_select_lex()->select_n_having_items+=
         table->select_lex->select_n_having_items;
 
       table->where= view_select->where;
@@ -1683,12 +1685,13 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
       */
       if (!table->select_lex->master_unit()->is_unit_op() &&
           table->select_lex->order_list.elements == 0)
-        table->select_lex->order_list.push_back(&lex->select_lex.order_list);
+        table->select_lex->order_list.
+          push_back(&lex->first_select_lex()->order_list);
       else
       {
         if (old_lex->sql_command == SQLCOM_SELECT &&
             (old_lex->describe & DESCRIBE_EXTENDED) &&
-            lex->select_lex.order_list.elements &&
+            lex->first_select_lex()->order_list.elements &&
             !table->select_lex->master_unit()->is_unit_op())
         {
           push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
@@ -1905,7 +1908,7 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view)
   */
   if ((!view->view && !view->belong_to_view) ||
       thd->lex->sql_command == SQLCOM_INSERT ||
-      thd->lex->select_lex.select_limit == 0)
+      thd->lex->first_select_lex()->select_limit == 0)
     DBUG_RETURN(FALSE); /* it is normal table or query without LIMIT */
   table= view->table;
   view= view->top_table();
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index e4555ddeb11..e33e99220c5 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -506,6 +506,7 @@ bool LEX::add_select_to_union_list(bool is_union_distinct,
 {
   const char *type_name= (type == INTERSECT_TYPE ? "INTERSECT" :
                      (type == EXCEPT_TYPE ? "EXCEPT" : "UNION"));
+  DBUG_ENTER("LEX::add_select_to_union_list");
   /*
      Only the last SELECT can have INTO. Since the grammar won't allow INTO in
      a nested SELECT, we make this check only when creating a top-level SELECT.
@@ -513,28 +514,28 @@ bool LEX::add_select_to_union_list(bool is_union_distinct,
   if (is_top_level && result)
   {
     my_error(ER_WRONG_USAGE, MYF(0), type_name, "INTO");
-    return TRUE;
+    DBUG_RETURN(TRUE);
   }
   if (current_select->order_list.first && !current_select->braces)
   {
     my_error(ER_WRONG_USAGE, MYF(0), type_name, "ORDER BY");
-    return TRUE;
+    DBUG_RETURN(TRUE);
   }
 
   if (current_select->explicit_limit && !current_select->braces)
   {
     my_error(ER_WRONG_USAGE, MYF(0), type_name, "LIMIT");
-    return TRUE;
+    DBUG_RETURN(TRUE);
   }
   if (current_select->linkage == GLOBAL_OPTIONS_TYPE)
   {
     thd->parse_error();
-    return TRUE;
+    DBUG_RETURN(TRUE);
   }
   if (!is_union_distinct && (type == INTERSECT_TYPE || type == EXCEPT_TYPE))
   {
     my_error(ER_WRONG_USAGE, MYF(0), type_name, "ALL");
-    return TRUE;
+    DBUG_RETURN(TRUE);
   }
   /*
     Priority implementation, but also trying to keep things as flat
@@ -549,27 +550,26 @@ bool LEX::add_select_to_union_list(bool is_union_distinct,
     */
     SELECT_LEX *prev= exclude_last_select();
     if (add_unit_in_brackets(prev))
-      return TRUE;
-    return add_select_to_union_list(is_union_distinct, type, 0);
+      DBUG_RETURN(TRUE);
+    bool res= add_select_to_union_list(is_union_distinct, type, 0);
+    DBUG_RETURN(res);
   }
   else
   {
     check_automatic_up(type);
   }
-  /* This counter shouldn't be incremented for UNION parts */
-  nest_level--;
   if (mysql_new_select(this, 0, NULL))
-    return TRUE;
+    DBUG_RETURN(TRUE);
   mysql_init_select(this);
-  current_select->linkage= type;
+  current_select->set_linkage(type);
   if (is_union_distinct) /* UNION DISTINCT - remember position */
   {
     current_select->master_unit()->union_distinct=
       current_select;
   }
-  else
-    DBUG_ASSERT(type == UNION_TYPE);
-  return FALSE;
+  //else
+  //  DBUG_ASSERT(type == UNION_TYPE);
+  DBUG_RETURN(FALSE);
 }
 
 
@@ -777,6 +777,18 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr)
     LEX_CSTRING name;
     uint offset;
   } sp_cursor_name_and_offset;
+  struct
+  {
+    enum sub_select_type unit_type;
+    bool distinct;
+  } unit_operation;
+  struct
+  {
+    SELECT_LEX *first;
+    SELECT_LEX *prev_last;
+  } select_list;
+  Lex_select_lock select_lock;
+  Lex_select_limit select_limit;
 
   /* pointers */
   Create_field *create_field;
@@ -818,18 +830,20 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr)
   class sp_variable *spvar;
   class With_clause *with_clause;
   class Virtual_column_info *virtual_column;
+  SQL_I_List<ORDER> *select_order;
 
   handlerton *db_type;
   st_select_lex *select_lex;
+  st_select_lex_unit *select_lex_unit;
   struct p_elem_val *p_elem_value;
   class Window_frame *window_frame;
   class Window_frame_bound *window_frame_bound;
   udf_func *udf;
   st_trg_execution_order trg_execution_order;
+  Lex_order_limit_lock *order_limit_lock;
 
   /* enums */
   enum enum_view_suid view_suid;
-  enum sub_select_type unit_type;
   enum Condition_information_item::Name cond_info_item_name;
   enum enum_diag_condition_item_name diag_condition_item_name;
   enum Diagnostics_information::Which_area diag_area;
@@ -866,10 +880,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
 %parse-param { THD *thd }
 %lex-param { THD *thd }
 /*
-  Currently there are 102 shift/reduce conflicts.
+  Currently there are 103 shift/reduce conflicts.
   We should not introduce new conflicts any more.
 */
-%expect 102
+%expect 99
 
 /*
    Comments for TOKENS.
@@ -1608,6 +1622,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
 %right  NOT_SYM NOT2_SYM
 %right  BINARY COLLATE_SYM
 %left  INTERVAL_SYM
+%left  INTERSECT_SYM
+%left  UNION_SYM EXCEPT_SYM
+%left  ','
 
 %type <lex_str>
         IDENT IDENT_QUOTED DECIMAL_NUM FLOAT_NUM NUM LONG_NUM
@@ -1670,7 +1687,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
         opt_temporary all_or_any opt_distinct
         opt_ignore_leaves fulltext_options union_option
         opt_not
-        select_derived_init transaction_access_mode_types
+        transaction_access_mode_types
         opt_natural_language_mode opt_query_expansion
         opt_ev_status opt_ev_on_completion ev_on_completion opt_ev_comment
         ev_alter_on_schedule_completion opt_ev_rename_to opt_ev_sql_stmt
@@ -1781,9 +1798,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
         join_table_list  join_table
         table_factor table_ref esc_table_ref
         table_primary_ident table_primary_derived
-        select_derived derived_table_list
-        select_derived_union
-        derived_query_specification
+        derived_table_list table_reference_list_parens
+        nested_table_reference_list join_table_parens
 %type <date_time_type> date_time_type;
 %type <interval> interval
 
@@ -1823,12 +1839,25 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
 %type <variable> internal_variable_name
 
 %type <select_lex> subselect
-        get_select_lex get_select_lex_derived
+        select_part
+        select_term
+        select_expr
         query_specification
-        query_term_union_not_ready
-        query_term_union_ready
+        query_specification_parens
+        query_specification_with_opt_parens
+        query_specification_with_opt_tail
+        query_specification_with_opt_tail_parens
+        query_primary
+        query_expression_unit_parens
+
+%type <select_lex_unit> 
+        query_expression_unit_with_opt_parens
+        query_expression_unit_with_opt_tail
+        query_expression_unit_with_opt_tail_parens
         query_expression_body
-        select_paren_derived
+        query_expression
+
+%type <select_list> query_expression_unit
 
 %type <boolfunc2creator> comp_op
 
@@ -1840,11 +1869,21 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
 
 %type <virtual_column> opt_check_constraint check_constraint virtual_column_func
         column_default_expr
-%type <unit_type> unit_type_decl
+
+%type <unit_operation> unit_type_decl
+
+%type <select_lock> opt_select_lock_type_new select_lock_type_new
+        opt_lock_wait_timeout_new 
+
+%type <select_limit> opt_limit_clause_new limit_clause_new limit_options_new
+
+%type <select_order> order_clause_new order_list_new
+
+%type <order_limit_lock> order_or_limit_new select_dedicated_tail
 
 %type <NONE>
         analyze_stmt_command
-        query verb_clause create change select do drop insert replace insert2
+        query verb_clause create change select_new do drop insert replace insert2
         insert_values update delete truncate rename compound_statement
         show describe load alter optimize keycache preload flush
         reset purge begin commit rollback savepoint release
@@ -1880,9 +1919,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
         table_to_table_list table_to_table opt_table_list opt_as
         handler_rkey_function handler_read_or_scan
         single_multi table_wild_list table_wild_one opt_wild
-        union_clause union_list
-        subselect_start opt_and charset
-        subselect_end select_var_list select_var_list_init help 
+        opt_and charset
+        select_var_list select_var_list_init help 
         opt_extended_describe shutdown
         opt_format_json
         prepare prepare_src execute deallocate
@@ -2001,7 +2039,7 @@ query:
           END_OF_INPUT
           {
             if (!thd->bootstrap &&
-              (!(thd->lex->select_lex.options & OPTION_FOUND_COMMENT)))
+              (!(thd->lex->builtin_select.options & OPTION_FOUND_COMMENT)))
               my_yyabort_error((ER_EMPTY_QUERY, MYF(0)));
 
             thd->lex->sql_command= SQLCOM_EMPTY_QUERY;
@@ -2095,7 +2133,7 @@ statement:
         | revoke
         | rollback
         | savepoint
-        | select
+        | select_new
         | set
         | signal_stmt
         | show
@@ -2125,14 +2163,20 @@ deallocate_or_drop:
         ;
 
 prepare:
-          PREPARE_SYM ident FROM prepare_src
+          PREPARE_SYM
+          {
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
+          }
+          ident FROM prepare_src
           {
             LEX *lex= thd->lex;
             if (lex->table_or_sp_used())
               my_yyabort_error((ER_SUBQUERIES_NOT_SUPPORTED, MYF(0),
                                "PREPARE..FROM"));
             lex->sql_command= SQLCOM_PREPARE;
-            lex->prepared_stmt_name= $2;
+            lex->prepared_stmt_name= $3;
+            Lex->pop_select(); //main select
           }
         ;
 
@@ -2151,18 +2195,26 @@ execute:
             LEX *lex= thd->lex;
             lex->sql_command= SQLCOM_EXECUTE;
             lex->prepared_stmt_name= $2;
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
           }
           execute_using
-          {}
+          {
+            Lex->pop_select(); //main select
+          }
         | EXECUTE_SYM IMMEDIATE_SYM prepare_src
           {
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
             if (Lex->table_or_sp_used())
               my_yyabort_error((ER_SUBQUERIES_NOT_SUPPORTED, MYF(0),
                                "EXECUTE IMMEDIATE"));
             Lex->sql_command= SQLCOM_EXECUTE_IMMEDIATE;
           }
           execute_using
-          {}
+          {
+            Lex->pop_select(); //main select
+          }
         ;
 
 execute_using:
@@ -2451,11 +2503,13 @@ create:
           {
             LEX *lex= thd->lex;
             lex->create_info.init();
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
             if (lex->set_command_with_check(SQLCOM_CREATE_TABLE, $2, $1 | $4))
                MYSQL_YYABORT;
-            if (!lex->select_lex.add_table_to_list(thd, $5, NULL,
-                                                   TL_OPTION_UPDATING,
-                                                   TL_WRITE, MDL_EXCLUSIVE))
+            if (!lex->builtin_select.add_table_to_list(thd, $5, NULL,
+                                                       TL_OPTION_UPDATING,
+                                                       TL_WRITE, MDL_EXCLUSIVE))
               MYSQL_YYABORT;
             lex->alter_info.reset();
             /*
@@ -2470,7 +2524,7 @@ create:
           create_body
           {
             LEX *lex= thd->lex;
-            lex->current_select= &lex->select_lex; 
+            lex->current_select= &lex->builtin_select;
             if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) &&
                 !lex->create_info.db_type)
             {
@@ -2482,17 +2536,20 @@ create:
                                   $5->table.str);
             }
             create_table_set_open_action_and_adjust_tables(lex);
+            Lex->pop_select(); //main select
           }
        | create_or_replace opt_temporary SEQUENCE_SYM opt_if_not_exists table_ident
          {
            LEX *lex= thd->lex;
+           if (Lex->main_select_push())
+             MYSQL_YYABORT;
            lex->create_info.init();
            if (lex->set_command_with_check(SQLCOM_CREATE_SEQUENCE, $2, $1 | $4))
               MYSQL_YYABORT;
 
-           if (!lex->select_lex.add_table_to_list(thd, $5, NULL,
-                                                  TL_OPTION_UPDATING,
-                                                  TL_WRITE, MDL_EXCLUSIVE))
+           if (!lex->builtin_select.add_table_to_list(thd, $5, NULL,
+                                                      TL_OPTION_UPDATING,
+                                                      TL_WRITE, MDL_EXCLUSIVE))
              MYSQL_YYABORT;
 
                /*
@@ -2515,8 +2572,8 @@ create:
             if (lex->create_info.seq_create_info->check_and_adjust(1))
             {
               my_error(ER_SEQUENCE_INVALID_DATA, MYF(0),
-                       lex->select_lex.table_list.first->db,
-                       lex->select_lex.table_list.first->table_name);
+                       lex->builtin_select.table_list.first->db,
+                       lex->builtin_select.table_list.first->table_name);
               MYSQL_YYABORT;
             }
 
@@ -2528,7 +2585,7 @@ create:
 	    Lex->create_info.used_fields|= HA_CREATE_USED_SEQUENCE;
             Lex->create_info.sequence= 1;
 
-            lex->current_select= &lex->select_lex;
+            lex->current_select= &lex->builtin_select;
             if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) &&
                 !lex->create_info.db_type)
             {
@@ -2540,6 +2597,7 @@ create:
                                   $5->table.str);
             }
             create_table_set_open_action_and_adjust_tables(lex);
+            Lex->pop_select(); //main select
           }
         | create_or_replace opt_unique INDEX_SYM opt_if_not_exists ident
           opt_key_algorithm_clause
@@ -2549,9 +2607,14 @@ create:
               MYSQL_YYABORT;
             if (Lex->add_create_index($2, &$5, $6, $1 | $4))
               MYSQL_YYABORT;
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
           }
           '(' key_list ')' opt_lock_wait_timeout normal_key_options
-          opt_index_lock_algorithm { }
+          opt_index_lock_algorithm
+          {
+            Lex->pop_select(); //main select
+          }
         | create_or_replace fulltext INDEX_SYM opt_if_not_exists ident
           ON table_ident
           {
@@ -2559,9 +2622,14 @@ create:
               MYSQL_YYABORT;
             if (Lex->add_create_index($2, &$5, HA_KEY_ALG_UNDEF, $1 | $4))
               MYSQL_YYABORT;
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
           }
           '(' key_list ')' opt_lock_wait_timeout fulltext_key_options
-          opt_index_lock_algorithm { }
+          opt_index_lock_algorithm
+          {
+            Lex->pop_select(); //main select
+          }
         | create_or_replace spatial INDEX_SYM opt_if_not_exists ident
           ON table_ident
           {
@@ -2569,13 +2637,20 @@ create:
               MYSQL_YYABORT;
             if (Lex->add_create_index($2, &$5, HA_KEY_ALG_UNDEF, $1 | $4))
               MYSQL_YYABORT;
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
           }
           '(' key_list ')' opt_lock_wait_timeout spatial_key_options
-          opt_index_lock_algorithm { }
+          opt_index_lock_algorithm
+          {
+            Lex->pop_select(); //main select
+          }
         | create_or_replace DATABASE opt_if_not_exists ident
           {
             Lex->create_info.default_table_charset= NULL;
             Lex->create_info.used_fields= 0;
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
           }
           opt_create_database_options
           {
@@ -2583,51 +2658,94 @@ create:
             if (lex->set_command_with_check(SQLCOM_CREATE_DB, 0, $1 | $3))
                MYSQL_YYABORT;
             lex->name= $4;
+            Lex->pop_select(); //main select
           }
         | create_or_replace definer_opt opt_view_suid VIEW_SYM
           opt_if_not_exists table_ident
           {
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
             if (Lex->add_create_view(thd, $1 | $5,
                                      DTYPE_ALGORITHM_UNDEFINED, $3, $6))
               MYSQL_YYABORT;
           }
           view_list_opt AS view_select
-          { }
+          {
+            Lex->pop_select(); //main select
+          }
         | create_or_replace view_algorithm definer_opt opt_view_suid VIEW_SYM
           opt_if_not_exists table_ident
           {
             if (Lex->add_create_view(thd, $1 | $6, $2, $4, $7))
               MYSQL_YYABORT;
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
           }
           view_list_opt AS view_select
-          { }
+          {
+            Lex->pop_select(); //main select
+          }
         | create_or_replace definer_opt TRIGGER_SYM
-          { Lex->create_info.set($1); }
+          {
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
+            Lex->create_info.set($1);
+          }
           trigger_tail
-          { }
+          {
+            Lex->pop_select(); //main select
+          }
         | create_or_replace definer_opt PROCEDURE_SYM
-          { Lex->create_info.set($1); }
+          {
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
+            Lex->create_info.set($1);
+          }
           sp_tail
-          { }
+          {
+            Lex->pop_select(); //main select
+          }
         | create_or_replace definer_opt EVENT_SYM
-          { Lex->create_info.set($1); }
+          {
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
+            Lex->create_info.set($1);
+          }
           event_tail
-          { }
+          {
+            Lex->pop_select(); //main select
+          }
         | create_or_replace definer FUNCTION_SYM
-          { Lex->create_info.set($1); }
+          {
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
+            Lex->create_info.set($1);
+          }
           sf_tail
-          { }
+          {
+            Lex->pop_select(); //main select
+          }
         | create_or_replace no_definer FUNCTION_SYM
-          { Lex->create_info.set($1); }
+          {
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
+            Lex->create_info.set($1);
+          }
           create_function_tail
-          { }
+          {
+            Lex->pop_select(); //main select
+          }
         | create_or_replace no_definer AGGREGATE_SYM FUNCTION_SYM
           {
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
             Lex->create_info.set($1);
             Lex->udf.type= UDFTYPE_AGGREGATE;
           }
           udf_tail
-          { }
+          {
+            Lex->pop_select(); //main select
+          }
         | create_or_replace USER_SYM opt_if_not_exists clear_privileges grant_list
           opt_require_clause opt_resource_options
           {
@@ -2974,7 +3092,7 @@ clear_privileges:
            lex->columns.empty();
            lex->grant= lex->grant_tot_col= 0;
            lex->all_privileges= 0;
-           lex->select_lex.db= 0;
+           lex->builtin_select.db= 0;
            lex->ssl_type= SSL_TYPE_NOT_SPECIFIED;
            lex->ssl_cipher= lex->x509_subject= lex->x509_issuer= 0;
            bzero((char *)&(lex->mqh),sizeof(lex->mqh));
@@ -3356,7 +3474,7 @@ sp_cursor_stmt:
             DBUG_ASSERT(thd->free_list == NULL);
             Lex->sphead->reset_lex(thd, $1);
           }
-          select
+          select_new
           {
             DBUG_ASSERT(Lex == $1);
             if ($1->stmt_finalize(thd) ||
@@ -4800,16 +4918,18 @@ create_body:
           conflict that prevents the rule above from parsing a syntax like
           CREATE TABLE t1 (SELECT 1);
         */
+        /*
         | '(' create_select_query_specification ')'
         | '(' create_select_query_specification ')'
           { Select->set_braces(1);} union_list {}
         | '(' create_select_query_specification ')'
           { Select->set_braces(1);} union_order_or_limit {}
+        */
         | create_like
           {
 
             Lex->create_info.add(DDL_options_st::OPT_LIKE);
-            TABLE_LIST *src_table= Lex->select_lex.add_table_to_list(thd,
+            TABLE_LIST *src_table= Lex->builtin_select.add_table_to_list(thd,
                                         $1, NULL, 0, TL_READ, MDL_SHARED_READ);
             if (! src_table)
               MYSQL_YYABORT;
@@ -4829,6 +4949,33 @@ opt_create_select:
         ;
 
 create_select_query_expression:
+        opt_with_clause
+        select_expr select_dedicated_tail
+        {
+            LEX *lex= Lex;
+            lex->pop_select_and_context(); //push at the end of select_expr
+            if ($2->set_nest_level(1))
+              MYSQL_YYABORT;
+            lex->current_select= lex->first_select_lex();
+            if ($3)
+              $3->set_to($2);
+            if (lex->sql_command == SQLCOM_INSERT ||
+                lex->sql_command == SQLCOM_REPLACE)
+            {
+              lex->insert_select_hack($2);
+              if (lex->sql_command == SQLCOM_INSERT)
+                lex->sql_command= SQLCOM_INSERT_SELECT;
+              else
+                lex->sql_command= SQLCOM_REPLACE_SELECT;
+            }
+            else
+            {
+              lex->insert_select_hack($2);
+              lex->unit.cut_subtree();
+              lex->unit.register_select_chain($2);
+            }
+        }
+/*
           opt_with_clause SELECT_SYM create_select_part2 opt_table_expression
           create_select_part4
           { 
@@ -4847,6 +4994,7 @@ create_select_query_expression:
         | '(' create_select_query_specification ')'
           { Select->set_braces(1);} union_order_or_limit {}
         ;
+*/
 
 opt_create_partitioning:
           opt_partitioning
@@ -4932,12 +5080,17 @@ partition_entry:
               thd->parse_error(ER_PARTITION_ENTRY_ERROR);
               MYSQL_YYABORT;
             }
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
             /*
               We enter here when opening the frm file to translate
               partition info string into part_info data structure.
             */
           }
-          partition {}
+          partition
+          {
+            Lex->pop_select(); //main select
+          }
         ;
 
 partition:
@@ -5544,7 +5697,7 @@ opt_part_option:
 /*
  End of partition parser part
 */
-
+/*
 create_select_query_specification:
           opt_with_clause SELECT_SYM create_select_part2 create_select_part3
           create_select_part4
@@ -5552,7 +5705,6 @@ create_select_query_specification:
             Select->set_with_clause($1);
           }
         ;
-
 create_select_part2:
           {
             LEX *lex=Lex;
@@ -5560,10 +5712,12 @@ create_select_part2:
               lex->sql_command= SQLCOM_INSERT_SELECT;
             else if (lex->sql_command == SQLCOM_REPLACE)
               lex->sql_command= SQLCOM_REPLACE_SELECT;
+*/
             /*
               The following work only with the local list, the global list
               is created correctly in this case
             */
+/*
             lex->current_select->table_list.save_and_clear(&lex->save_list);
             mysql_init_select(lex);
             lex->current_select->parsing_place= SELECT_LIST;
@@ -5573,7 +5727,6 @@ create_select_part2:
             Select->parsing_place= NO_MATTER;
           }
         ;
-
 create_select_part3:
           opt_table_expression
         | create_select_part3_union_not_ready
@@ -5587,13 +5740,16 @@ create_select_part3_union_not_ready:
 create_select_part4:
           opt_select_lock_type
           {
+*/
             /*
               The following work only with the local list, the global list
               is created correctly in this case
             */
+/*
             Lex->current_select->table_list.push_front(&Lex->save_list);
           }
         ;
+*/
 
 opt_as:
           /* empty */ {}
@@ -5812,7 +5968,7 @@ create_table_option:
           }
         | UNION_SYM opt_equal
           {
-            Lex->select_lex.table_list.save_and_clear(&Lex->save_list);
+            Lex->builtin_select.table_list.save_and_clear(&Lex->save_list);
           }
           '(' opt_table_list ')'
           {
@@ -5821,8 +5977,8 @@ create_table_option:
               from the global list.
             */
             LEX *lex=Lex;
-            lex->create_info.merge_list= lex->select_lex.table_list;
-            lex->select_lex.table_list= lex->save_list;
+            lex->create_info.merge_list= lex->builtin_select.table_list;
+            lex->builtin_select.table_list= lex->save_list;
             /*
               When excluding union list from the global list we assume that
               elements of the former immediately follow elements which represent
@@ -6261,6 +6417,8 @@ parse_vcol_expr:
               Prevent the end user from invoking this command.
             */
             MYSQL_YYABORT_UNLESS(Lex->parse_vcol_expr);
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
           }
           expr
           {
@@ -6268,15 +6426,33 @@ parse_vcol_expr:
             if (!v)
               MYSQL_YYABORT;
             Lex->last_field->vcol_info= v;
+            Lex->pop_select(); //main select
           }
         ;
 
 parenthesized_expr:
-          subselect
+          select_expr select_dedicated_tail
           {
+            LEX *lex= Lex;
+            lex->pop_select_and_context(); //push at the end of select_expr
+            if (!lex->expr_allows_subselect ||
+               lex->sql_command == (int)SQLCOM_PURGE)
+            {
+              thd->parse_error();
+              MYSQL_YYABORT;
+            }
+            SELECT_LEX *sel= lex->select_stack_head();
+            SELECT_LEX_UNIT *unit=
+              sel->attach_selects_chain($1, &sel->context);
+            if (!unit)
+              MYSQL_YYABORT;
             $$= new (thd->mem_root) Item_singlerow_subselect(thd, $1);
             if ($$ == NULL)
               MYSQL_YYABORT;
+            //Lex->pop_context();
+            //Lex->current_select= sel;
+            if ($2)
+              $2->set_to($1);
           }
         | expr
         | expr ',' expr_list
@@ -7165,22 +7341,24 @@ alter:
             Lex->table_type= TABLE_TYPE_UNKNOWN;
             Lex->sql_command= SQLCOM_ALTER_TABLE;
             Lex->duplicates= DUP_ERROR; 
-            Lex->select_lex.init_order();
+            Lex->builtin_select.init_order();
             Lex->create_info.init();
             Lex->create_info.row_type= ROW_TYPE_NOT_USED;
             Lex->alter_info.reset();
             Lex->no_write_to_binlog= 0;
             Lex->create_info.storage_media= HA_SM_DEFAULT;
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
             DBUG_ASSERT(!Lex->m_sql_cmd);
           }
           alter_options TABLE_SYM table_ident opt_lock_wait_timeout
           {
-            if (!Lex->select_lex.add_table_to_list(thd, $5, NULL,
+            if (!Lex->builtin_select.add_table_to_list(thd, $5, NULL,
                                                    TL_OPTION_UPDATING,
                                                    TL_READ_NO_INSERT,
                                                    MDL_SHARED_UPGRADABLE))
               MYSQL_YYABORT;
-            Lex->select_lex.db= (Lex->select_lex.table_list.first)->db;
+            Lex->builtin_select.db= (Lex->builtin_select.table_list.first)->db;
             Lex->create_last_non_select_table= Lex->last_table();
           }
           alter_commands
@@ -7191,12 +7369,15 @@ alter:
               Lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_table();
               if (Lex->m_sql_cmd == NULL)
                 MYSQL_YYABORT;
+              Lex->pop_select(); //main select
             }
           }
         | ALTER DATABASE ident_or_empty
           {
             Lex->create_info.default_table_charset= NULL;
             Lex->create_info.used_fields= 0;
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
           }
           create_database_options
           {
@@ -7206,6 +7387,7 @@ alter:
             if (lex->name.str == NULL &&
                 lex->copy_db_to(&lex->name.str, &lex->name.length))
               MYSQL_YYABORT;
+            Lex->pop_select(); //main select
           }
         | ALTER DATABASE ident UPGRADE_SYM DATA_SYM DIRECTORY_SYM NAME_SYM
           {
@@ -7221,6 +7403,8 @@ alter:
 
             if (lex->sphead)
               my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "PROCEDURE"));
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
             lex->sp_chistics.init();
           }
           sp_a_chistics
@@ -7229,6 +7413,7 @@ alter:
 
             lex->sql_command= SQLCOM_ALTER_PROCEDURE;
             lex->spname= $3;
+            Lex->pop_select(); //main select
           }
         | ALTER FUNCTION_SYM sp_name
           {
@@ -7236,6 +7421,8 @@ alter:
 
             if (lex->sphead)
               my_yyabort_error((ER_SP_NO_DROP_SP, MYF(0), "FUNCTION"));
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
             lex->sp_chistics.init();
           }
           sp_a_chistics
@@ -7244,14 +7431,19 @@ alter:
 
             lex->sql_command= SQLCOM_ALTER_FUNCTION;
             lex->spname= $3;
+            Lex->pop_select(); //main select
           }
         | ALTER view_algorithm definer_opt opt_view_suid VIEW_SYM table_ident
           {
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
             if (Lex->add_alter_view(thd, $2, $4, $6))
               MYSQL_YYABORT;
           }
           view_list_opt AS view_select
-          {}
+          {
+            Lex->pop_select(); //main select
+          }
         | ALTER definer_opt opt_view_suid VIEW_SYM table_ident
           /*
             We have two separate rules for ALTER VIEW rather that
@@ -7259,14 +7451,20 @@ alter:
             with the ALTER EVENT below.
           */
           {
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
             if (Lex->add_alter_view(thd, VIEW_ALGORITHM_INHERIT, $3, $5))
               MYSQL_YYABORT;
           }
           view_list_opt AS view_select
-          {}
+          {
+            Lex->pop_select(); //main select
+          }
         | ALTER definer_opt remember_name EVENT_SYM sp_name
           {
-            /* 
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
+            /*
               It is safe to use Lex->spname because
               ALTER EVENT xxx RENATE TO yyy DO ALTER EVENT RENAME TO
               is not allowed. Lex->spname is used in the case of RENAME TO
@@ -7298,6 +7496,8 @@ alter:
             */
             Lex->sql_command= SQLCOM_ALTER_EVENT;
             Lex->stmt_definition_end= (char*)YYLIP->get_cpp_ptr();
+
+            Lex->pop_select(); //main select
           }
         | ALTER TABLESPACE alter_tablespace_info
           {
@@ -7341,15 +7541,17 @@ alter:
             lex->create_info.init();
             lex->no_write_to_binlog= 0;
             DBUG_ASSERT(!lex->m_sql_cmd);
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
           }
           table_ident
           {
             LEX *lex= Lex;
             if (!(lex->create_info.seq_create_info= new (thd->mem_root)
                                                      sequence_definition()) ||
-                !lex->select_lex.add_table_to_list(thd, $5, NULL,
-                                                   TL_OPTION_SEQUENCE,
-                                                   TL_WRITE, MDL_EXCLUSIVE))
+                !lex->builtin_select.add_table_to_list(thd, $5, NULL,
+                                                       TL_OPTION_SEQUENCE,
+                                                       TL_WRITE, MDL_EXCLUSIVE))
               MYSQL_YYABORT;
           }
           sequence_defs
@@ -7358,6 +7560,7 @@ alter:
             Lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_sequence();
             if (Lex->m_sql_cmd == NULL)
               MYSQL_YYABORT;
+            Lex->pop_select(); //main select
           }
         ;
 
@@ -7508,18 +7711,18 @@ alter_commands:
           {
             LEX *lex= thd->lex;
             size_t dummy;
-            lex->select_lex.db=$6->db.str;
-            if (lex->select_lex.db == NULL &&
-                lex->copy_db_to(&lex->select_lex.db, &dummy))
+            lex->builtin_select.db=$6->db.str;
+            if (lex->builtin_select.db == NULL &&
+                lex->copy_db_to(&lex->builtin_select.db, &dummy))
             {
               MYSQL_YYABORT;
             }
             lex->name= $6->table;
             lex->alter_info.flags|= Alter_info::ALTER_EXCHANGE_PARTITION;
-            if (!lex->select_lex.add_table_to_list(thd, $6, NULL,
-                                                   TL_OPTION_UPDATING,
-                                                   TL_READ_NO_INSERT,
-                                                   MDL_SHARED_NO_WRITE))
+            if (!lex->builtin_select.add_table_to_list(thd, $6, NULL,
+                                                       TL_OPTION_UPDATING,
+                                                       TL_READ_NO_INSERT,
+                                                       MDL_SHARED_NO_WRITE))
               MYSQL_YYABORT;
             DBUG_ASSERT(!lex->m_sql_cmd);
             lex->m_sql_cmd= new (thd->mem_root)
@@ -7770,9 +7973,9 @@ alter_list_item:
           {
             LEX *lex=Lex;
             size_t dummy;
-            lex->select_lex.db=$3->db.str;
-            if (lex->select_lex.db == NULL &&
-                lex->copy_db_to(&lex->select_lex.db, &dummy))
+            lex->builtin_select.db=$3->db.str;
+            if (lex->builtin_select.db == NULL &&
+                lex->copy_db_to(&lex->builtin_select.db, &dummy))
             {
               MYSQL_YYABORT;
             }
@@ -8046,9 +8249,13 @@ checksum:
             lex->sql_command = SQLCOM_CHECKSUM;
             /* Will be overridden during execution. */
             YYPS->m_lock_type= TL_UNLOCK;
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
           }
           table_list opt_checksum_type
-          {}
+          {
+            Lex->pop_select(); //main select
+          }
         ;
 
 opt_checksum_type:
@@ -8074,6 +8281,8 @@ repair:
             lex->alter_info.reset();
             /* Will be overridden during execution. */
             YYPS->m_lock_type= TL_UNLOCK;
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
           }
           repair_table_or_view
           {
@@ -8082,6 +8291,7 @@ repair:
             lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_repair_table();
             if (lex->m_sql_cmd == NULL)
               MYSQL_YYABORT;
+            Lex->pop_select(); //main select
           }
         ;
 
@@ -8240,6 +8450,8 @@ check:    CHECK_SYM
             lex->alter_info.reset();
             /* Will be overridden during execution. */
             YYPS->m_lock_type= TL_UNLOCK;
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
           }
           check_view_or_table
           {
@@ -8250,6 +8462,7 @@ check:    CHECK_SYM
             lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_check_table();
             if (lex->m_sql_cmd == NULL)
               MYSQL_YYABORT;
+            Lex->pop_select(); //main select
           }
         ;
 
@@ -8287,6 +8500,8 @@ optimize:
             lex->alter_info.reset();
             /* Will be overridden during execution. */
             YYPS->m_lock_type= TL_UNLOCK;
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
           }
           table_list opt_lock_wait_timeout
           {
@@ -8295,6 +8510,7 @@ optimize:
             lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_optimize_table();
             if (lex->m_sql_cmd == NULL)
               MYSQL_YYABORT;
+            Lex->pop_select(); //main select
           }
         ;
 
@@ -8308,9 +8524,13 @@ rename:
           RENAME table_or_tables
           {
             Lex->sql_command= SQLCOM_RENAME_TABLE;
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
           }
           table_to_table_list
-          {}
+          {
+            Lex->pop_select(); //main select
+          }
         | RENAME USER_SYM clear_privileges rename_list
           {
             Lex->sql_command = SQLCOM_RENAME_USER;
@@ -8404,9 +8624,13 @@ preload:
             LEX *lex=Lex;
             lex->sql_command=SQLCOM_PRELOAD_KEYS;
             lex->alter_info.reset();
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
           }
           preload_list_or_parts
-          {}
+          {
+            Lex->pop_select(); //main select
+          }
         ;
 
 preload_list_or_parts:
@@ -8449,8 +8673,8 @@ adm_partition:
 
 cache_keys_spec:
           {
-            Lex->select_lex.alloc_index_hints(thd);
-            Select->set_index_hint_type(INDEX_HINT_USE, 
+            Lex->builtin_select.alloc_index_hints(thd);
+            Select->set_index_hint_type(INDEX_HINT_USE,
                                         INDEX_HINT_MASK_ALL);
           }
           cache_key_list_or_empty
@@ -8470,8 +8694,7 @@ opt_ignore_leaves:
 /*
   Select : retrieve data from table
 */
-
-
+/*
 select:
           opt_with_clause select_init
           {
@@ -8480,120 +8703,478 @@ select:
             lex->current_select->set_with_clause($1);
           }
         ;
+*/
 
-select_init:
-          SELECT_SYM select_options_and_item_list select_init3
-        | '(' select_paren ')'
-        | '(' select_paren ')' union_list
-        | '(' select_paren ')' union_order_or_limit
-        ;
-
-union_list_part2:
-          SELECT_SYM select_options_and_item_list select_init3_union_query_term
-        | '(' select_paren_union_query_term ')'
-        | '(' select_paren_union_query_term ')' union_list
-        | '(' select_paren_union_query_term ')' union_order_or_limit
-        ;
-
-select_paren:
-          {
-            /*
-              In order to correctly parse UNION's global ORDER BY we need to
-              set braces before parsing the clause.
-            */
-            Lex->current_select->set_braces(true);
-          }
-          SELECT_SYM select_options_and_item_list select_part3
-          opt_select_lock_type
+select_new:
           {
-            DBUG_ASSERT(Lex->current_select->braces);
+            Lex->main_select_cut();
           }
-        | '(' select_paren ')'
-        ;
-
-select_paren_union_query_term:
+          opt_with_clause
+          select_expr
           {
-            /*
-              In order to correctly parse UNION's global ORDER BY we need to
-              set braces before parsing the clause.
-            */
-            Lex->current_select->set_braces(true);
+            LEX *lex= Lex;
+            lex->pop_select_and_context(); //push at the end of select_expr
+            if (lex->new_main_select_anker($3))
+              MYSQL_YYABORT;
+            //lex->current_select= lex->first_select_lex();
           }
-          SELECT_SYM select_options_and_item_list select_part3_union_query_term
-          opt_select_lock_type
+          select_new_global_tail
           {
-            DBUG_ASSERT(Lex->current_select->braces);
+            LEX *lex= Lex;
+            if (lex->unit.automatic_op_precedence())
+              YYABORT;
+            lex->sql_command= SQLCOM_SELECT;
+            if ($2)
+              $3->set_with_clause($2);
           }
-        | '(' select_paren_union_query_term ')'
         ;
 
-select_paren_view:
-          {
-            /*
-              In order to correctly parse UNION's global ORDER BY we need to
-              set braces before parsing the clause.
-            */
-            Lex->current_select->set_braces(true);
-          }
-          SELECT_SYM select_options_and_item_list select_part3_view
-          opt_select_lock_type
-          {
-            DBUG_ASSERT(Lex->current_select->braces);
-          }
-        | '(' select_paren_view ')'
+
+query_specification:
+         SELECT_SYM
+         {
+           SELECT_LEX *sel;
+           if (!(sel= Lex->alloc_select(TRUE)) ||
+               Lex->push_select(sel))
+             MYSQL_YYABORT;
+         }
+         select_options
+         select_item_list
+         opt_into
+         opt_from_clause
+         opt_where_clause
+         opt_group_clause
+         opt_having_clause
+         opt_window_clause
+         {
+           $$= Lex->pop_select();
+         }
+/*
+       | SELECT_SYM
+         {
+           SELECT_LEX *sel;
+           if (!(sel= Lex->alloc_select(TRUE)) ||
+               Lex->push_select(sel))
+             MYSQL_YYABORT;
+         }
+         select_options
+         select_item_list
+         opt_from_clause
+         opt_where_clause
+         opt_group_clause
+         opt_having_clause
+         opt_window_clause
+         {
+           $$= Lex->pop_select();
+         }
+*/
+      ;
+
+opt_from_clause:
+        /* Empty */
+        | from_clause
         ;
 
-/* The equivalent of select_paren for nested queries. */
-select_paren_derived:
-          {
-            Lex->current_select->set_braces(true);
-          }
-          SELECT_SYM select_part2_derived
-          opt_table_expression
-          opt_order_clause
-          opt_limit_clause
-          opt_select_lock_type
-          {
-            DBUG_ASSERT(Lex->current_select->braces);
-            $$= Lex->current_select->master_unit()->first_select();
-          }
-        | '(' select_paren_derived ')'  { $$= $2; }
+query_specification_parens:
+          '(' query_specification_parens ')'
+          { $$= $2; }
+        | '(' query_specification ')'
+          { $$= $2; }
         ;
 
-select_init3:
+
+query_specification_with_opt_parens:
+          query_specification_parens
+          { $$= $1; }
+        | query_specification
+          { $$= $1; }
+        ;
+
+
+query_specification_with_opt_tail:
+         query_specification_with_opt_parens
+         {
+           Lex->push_select($1);
+         }
+         opt_order_clause
+         opt_limit_clause
+         select_lock_type
+         {
+           Lex->pop_select();
+           $$= $1;
+         }
+       ;
+
+
+query_specification_with_opt_tail_parens:
+         '(' query_specification_with_opt_tail_parens ')'
+          { $$= $2; }
+       | '(' query_specification_with_opt_tail ')'
+          { $$= $2; }
+       ;
+
+query_primary:
+         query_specification_with_opt_parens
+         { $$= $1; }
+       | query_specification_with_opt_tail_parens
+         { $$= $1; }
+       | query_expression_unit_with_opt_tail_parens
+         { 
+           $$= Lex->wrap_unit_into_derived($1);
+           if ($$ == NULL)
+             YYABORT;
+         }        
+       ;
+
+query_expression_unit_with_opt_tail_parens:
+         '(' query_expression_unit_with_opt_tail_parens ')'
+          { $$= $2; }
+       | '(' query_expression_unit_with_opt_tail ')'
+          { $$= $2; }
+       ;
+
+query_expression_unit_with_opt_tail:
+         query_expression_unit_with_opt_parens
+         opt_order_clause
+         opt_limit_clause
+         opt_select_lock_type
+         {
+           Lex->pop_select();
+           $$= $1;
+         }
+       ;
+
+query_expression_unit_with_opt_parens:
+         query_expression_unit_parens
+         {
+           $$= Lex->create_unit($1);
+           if ($$ == NULL)
+             YYABORT;
+           Lex->push_select($1);
+         }
+       | query_expression_unit
+         {
+           SELECT_LEX *last= $1.prev_last->next_select();
+           int cmp= cmp_unit_op($1.first->next_select()->linkage,
+                                last->linkage);
+           if (cmp < 0)
+           {
+             if (Lex->pop_new_select_and_wrap() == NULL)
+               MYSQL_YYABORT;
+           }
+           $$= Lex->create_unit($1.first);
+           if ($$ == NULL)
+             YYABORT;
+           Lex->push_select($$->fake_select_lex);
+         }
+       ;
+
+query_expression_unit_parens:
+         '(' query_expression_unit_parens ')'
+          { $$= $2; }
+       | '(' query_expression_unit ')'
+         {
+           SELECT_LEX *sel;
+           SELECT_LEX *last= $2.prev_last->next_select();
+           int cmp= cmp_unit_op($2.first->next_select()->linkage,
+                                last->linkage);
+           if (cmp < 0)
+           {
+             if (Lex->pop_new_select_and_wrap() == NULL)
+               MYSQL_YYABORT;
+           }
+
+           if (!(sel= Lex->link_selects_chain_down($2.first)))
+              MYSQL_YYABORT;
+           $$= sel;
+         }
+       ;
+
+query_expression_unit:
+         query_primary  
+         unit_type_decl
+         query_primary
+         {
+           $1->link_neighbour($3);
+           $3->set_linkage_and_distinct($2.unit_type, $2.distinct);
+           $$.first= $1;
+           $$.prev_last= $1;
+         }
+       | query_expression_unit
+         unit_type_decl
+         query_primary
+         {
+           SELECT_LEX *last= $1.prev_last->next_select();
+           int cmp= cmp_unit_op($3->linkage, last->linkage);
+           if (cmp == 0)
+           {
+             //Lex->link_select(last, $3, $2);
+             last->link_neighbour($3);
+             $3->set_linkage_and_distinct($2.unit_type, $2.distinct);
+           }
+           else if (cmp > 0)
+           {
+             // Store beginning and continue...
+             if (Lex->push_new_select(last))
+               MYSQL_YYABORT;
+             last->link_neighbour($3);
+             $3->set_linkage_and_distinct($2.unit_type, $2.distinct);
+           }
+           else /* cmp < 0 */
+           {
+             if ((last= Lex->pop_new_select_and_wrap()) == NULL)
+               MYSQL_YYABORT;
+           }
+           $$.first= $1.first;
+           $$.prev_last= last;
+         }
+       ;
+
+query_expression_body:
+         query_primary
+         { 
+           $$= Lex->create_unit($1);
+           if ($$ == NULL)
+             YYABORT;
+         }
+       | query_expression_unit_with_opt_tail { $$= $1; }
+       ;
+
+query_expression:
+         opt_with_clause
+         query_expression_body
+          {
+            if ($1)
+             $2->set_with_clause($1);
+            $$= $2;
+          }
+        ;
+
+subselect:
+          query_expression
+          {
+            if (!Lex->expr_allows_subselect ||
+                Lex->sql_command == (int)SQLCOM_PURGE)
+            {
+              thd->parse_error();
+              MYSQL_YYABORT;
+            }
+            /* Collect statistics ... */
+            $$= $1->first_select();
+          }
+        ;
+         
+/* Chain of selects on top (have to be linked under unit */
+select_expr:
+          select_term unit_type_decl select_expr 
+          {
+            Lex->pop_select_and_context(); //push at the end of select_expr
+            DBUG_ASSERT($1->next_select() == NULL);
+            $1->link_neighbour($3);
+            $3->set_linkage_and_distinct($2.unit_type, $2.distinct);
+            //Lex->current_select= $$= $1;
+            Lex->push_select_and_context($1, thd->mem_root);
+          }
+        | select_term
+          {
+            Lex->push_select_and_context($1, thd->mem_root);
+            //Lex->current_select=$$= $1;
+          }
+        ;
+
+/* Single Select on top */
+select_term:
+          '('
+          select_expr
+          select_dedicated_tail
+          ')'
+          {
+            SELECT_LEX *sel= $2;
+            LEX *lex= Lex;
+            lex->pop_select_and_context(); //push at the end of select_expr
+            if (sel->next_select())
+            {
+              if (!(sel= lex->link_selects_chain_down(sel)))
+                MYSQL_YYABORT;
+
+              if (sel->first_inner_unit()->automatic_op_precedence())
+                YYABORT;
+            }
+            else
+            {
+              // just braces around select
+              sel->braces= TRUE;
+            }
+            $$= sel;
+            //lex->current_select= sel;
+
+            lex->nest_level= sel->nest_level;
+            if ($3)
+            {
+              lex->push_select(sel);
+              $3->set_to($$);
+              lex->pop_select();
+            }
+          }
+        | select_part
+          {
+            $$= $1;
+          }
+        ;
+
+/* Single Select on top */
+select_part:
+          SELECT_SYM
+          {
+            SELECT_LEX *sel;
+            if (!(sel= Lex->alloc_select(TRUE)))
+              MYSQL_YYABORT;
+            Lex->push_select(sel);
+          }
+          select_options_and_item_list opt_table_expression opt_select_lock_type
+
+          {
+            $$= Lex->pop_select();
+            Lex->pop_context("select_part");
+            /* initalisation */
+            $$->braces= FALSE;
+          }
+        ;
+/*
+select_init:
+          SELECT_SYM select_options_and_item_list select_init3
+        | '(' select_paren ')'
+        | '(' select_paren ')' union_list
+        | '(' select_paren ')' union_order_or_limit
+        ;
+        */
+/*
+union_list_part2:
+          SELECT_SYM select_options_and_item_list select_init3_union_query_term
+        | '(' select_paren_union_query_term ')'
+        | '(' select_paren_union_query_term ')' union_list
+        | '(' select_paren_union_query_term ')' union_order_or_limit
+        ;
+*/
+/*
+select_paren:
+          {
+*/
+            /*
+              In order to correctly parse UNION's global ORDER BY we need to
+              set braces before parsing the clause.
+            */
+/*
+            Lex->current_select->set_braces(true);
+          }
+          SELECT_SYM select_options_and_item_list select_part3
+          opt_select_lock_type
+          {
+            DBUG_ASSERT(Lex->current_select->braces);
+          }
+        | '(' select_paren ')'
+        ;
+*/
+/*
+select_paren_union_query_term:
+          {
+*/
+            /*
+              In order to correctly parse UNION's global ORDER BY we need to
+              set braces before parsing the clause.
+            */
+/*
+            Lex->current_select->set_braces(true);
+          }
+          SELECT_SYM select_options_and_item_list select_part3_union_query_term
+          opt_select_lock_type
+          {
+            DBUG_ASSERT(Lex->current_select->braces);
+          }
+        | '(' select_paren_union_query_term ')'
+        ;
+*/
+/*
+select_paren_view:
+          {
+*/
+            /*
+              In order to correctly parse UNION's global ORDER BY we need to
+              set braces before parsing the clause.
+            */
+/*
+            Lex->current_select->set_braces(true);
+          }
+          SELECT_SYM select_options_and_item_list select_part3_view
+          opt_select_lock_type
+          {
+            DBUG_ASSERT(Lex->current_select->braces);
+          }
+        | '(' select_paren_view ')'
+        ;
+*/
+
+/* The equivalent of select_paren for nested queries. */
+/*
+select_paren_derived:
+          {
+            Lex->current_select->set_braces(true);
+          }
+          SELECT_SYM select_part2_derived
+          opt_table_expression
+          opt_order_clause
+          opt_limit_clause
+          opt_select_lock_type
+          {
+            DBUG_ASSERT(Lex->current_select->braces);
+            $$= Lex->current_select->master_unit()->first_select();
+          }
+        | '(' select_paren_derived ')'  { $$= $2; }
+        ;
+*/
+/*
+select_init3:
           opt_table_expression
           opt_select_lock_type
           {
+            */
             /* Parentheses carry no meaning here */
+            /*
             Lex->current_select->set_braces(false);
           }
           union_clause
         | select_part3_union_not_ready
           opt_select_lock_type
           {
+            */
             /* Parentheses carry no meaning here */
+            /*
             Lex->current_select->set_braces(false);
           }
         ;
-
-
+*/
+/*
 select_init3_union_query_term:
           opt_table_expression
           opt_select_lock_type
           {
+*/
             /* Parentheses carry no meaning here */
+/*
             Lex->current_select->set_braces(false);
           }
           union_clause
         | select_part3_union_not_ready_noproc
           opt_select_lock_type
           {
+*/
             /* Parentheses carry no meaning here */
+/*
             Lex->current_select->set_braces(false);
           }
         ;
-
-
+*/
+/*
 select_init3_view:
           opt_table_expression opt_select_lock_type
           {
@@ -8613,16 +9194,18 @@ select_init3_view:
             Lex->current_select->set_braces(false);
           }
         ;
-
+*/
 /*
   The SELECT parts after select_item_list that cannot be followed by UNION.
 */
 
+/*
 select_part3:
           opt_table_expression
         | select_part3_union_not_ready
         ;
-
+*/
+/*
 select_part3_union_query_term:
           opt_table_expression
         | select_part3_union_not_ready_noproc
@@ -8633,13 +9216,49 @@ select_part3_view:
         | order_or_limit
         | table_expression order_or_limit
         ;
-
+*/
+/*
 select_part3_union_not_ready:
           select_part3_union_not_ready_noproc
         | table_expression procedure_clause
         | table_expression order_or_limit procedure_clause
         ;
+        */
+
+
+select_new_global_tail:
+          /* empty */
+        | global_select_on procedure_clause global_select_off
+        | global_select_on global_order_or_limit opt_select_lock_type procedure_clause global_select_off
+        | global_select_on global_order_or_limit opt_select_lock_type global_select_off
+        | global_select_on into opt_table_expression opt_order_clause opt_limit_clause opt_select_lock_type global_select_off
+        | global_select_on global_order_or_limit opt_select_lock_type into global_select_off
 
+select_dedicated_tail:
+          /* empty */
+          {
+            $$= NULL;
+          }
+        | order_or_limit_new opt_select_lock_type_new
+          {
+            if ($1)
+            {
+              $$= $1;
+              $$->lock= $2;
+            }
+            else if ($2.defined_lock)
+            {
+              $$= new(thd->mem_root) Lex_order_limit_lock;
+              if (!$$)
+                YYABORT;
+              $$->lock= $2;
+            }
+            else
+              $$= NULL;
+          }
+          ;
+
+/*
 select_part3_union_not_ready_noproc:
           order_or_limit
         | into opt_table_expression opt_order_clause opt_limit_clause
@@ -8647,7 +9266,7 @@ select_part3_union_not_ready_noproc:
         | table_expression order_or_limit
         | table_expression order_or_limit into
         ;
-
+*/
 select_options_and_item_list:
           {
             LEX *lex= Lex;
@@ -8719,16 +9338,16 @@ select_option:
               Allow this flag only on the first top-level SELECT statement, if
               SQL_CACHE wasn't specified, and only once per query.
              */
-            if (Lex->current_select != &Lex->select_lex)
+            if (Lex->first_select_lex())
               my_yyabort_error((ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_NO_CACHE"));
-            if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_CACHE)
+            if (Lex->builtin_select.sql_cache == SELECT_LEX::SQL_CACHE)
               my_yyabort_error((ER_WRONG_USAGE, MYF(0), "SQL_CACHE", "SQL_NO_CACHE"));
-            if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_NO_CACHE)
+            if (Lex->builtin_select.sql_cache == SELECT_LEX::SQL_NO_CACHE)
               my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "SQL_NO_CACHE"));
 
             Lex->safe_to_cache_query=0;
-            Lex->select_lex.options&= ~OPTION_TO_QUERY_CACHE;
-            Lex->select_lex.sql_cache= SELECT_LEX::SQL_NO_CACHE;
+            Lex->builtin_select.options&= ~OPTION_TO_QUERY_CACHE;
+            Lex->builtin_select.sql_cache= SELECT_LEX::SQL_NO_CACHE;
           }
         | SQL_CACHE_SYM
           {
@@ -8736,22 +9355,26 @@ select_option:
               Allow this flag only on the first top-level SELECT statement, if
               SQL_NO_CACHE wasn't specified, and only once per query.
              */
-            if (Lex->current_select != &Lex->select_lex)
+            if (Lex->first_select_lex())
               my_yyabort_error((ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_CACHE"));
-            if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_NO_CACHE)
+            if (Lex->builtin_select.sql_cache == SELECT_LEX::SQL_NO_CACHE)
               my_yyabort_error((ER_WRONG_USAGE, MYF(0), "SQL_NO_CACHE", "SQL_CACHE"));
-            if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_CACHE)
+            if (Lex->builtin_select.sql_cache == SELECT_LEX::SQL_CACHE)
               my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "SQL_CACHE"));
 
             Lex->safe_to_cache_query=1;
-            Lex->select_lex.options|= OPTION_TO_QUERY_CACHE;
-            Lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE;
+            Lex->builtin_select.options|= OPTION_TO_QUERY_CACHE;
+            Lex->builtin_select.sql_cache= SELECT_LEX::SQL_CACHE;
           }
         ;
 
 opt_select_lock_type:
           /* empty */
-        | FOR_SYM UPDATE_SYM opt_lock_wait_timeout
+        | select_lock_type
+        ;
+
+select_lock_type:
+          FOR_SYM UPDATE_SYM opt_lock_wait_timeout
           {
             LEX *lex=Lex;
             lex->current_select->lock_type= TL_WRITE;
@@ -8768,6 +9391,49 @@ opt_select_lock_type:
           }
         ;
 
+opt_select_lock_type_new:
+          /* empty */
+          {
+            $$.empty();
+          }
+        | select_lock_type_new
+          {
+            $$= $1;
+          }
+        ;
+
+select_lock_type_new:
+          FOR_SYM UPDATE_SYM opt_lock_wait_timeout_new
+          {
+            $$= $3;
+            $$.defined_lock= TRUE;
+            $$.update_lock= TRUE;
+          }
+        | LOCK_SYM IN_SYM SHARE_SYM MODE_SYM opt_lock_wait_timeout_new
+          {
+            $$= $5;
+            $$.defined_lock= TRUE;
+            $$.update_lock= TRUE;
+          }
+        ;
+
+opt_lock_wait_timeout_new:
+        /* empty */
+        {
+          $$.empty();
+        }
+        | WAIT_SYM ulong_num
+        {
+          $$.defined_timeout= TRUE;
+          $$.timeout= $2;
+        }
+        | NOWAIT_SYM
+        {
+          $$.defined_timeout= TRUE;
+          $$.timeout= 0;
+        }
+      ;
+
 select_item_list:
           select_item_list ',' select_item
         | select_item
@@ -10934,10 +11600,15 @@ esc_table_ref:
 /* Equivalent to <table reference list> in the SQL:2003 standard. */
 /* Warning - may return NULL in case of incomplete SELECT */
 derived_table_list:
-          esc_table_ref { $$=$1; }
+          esc_table_ref
+         {
+           $$=$1;
+           Select->add_joined_table($1);
+         }
         | derived_table_list ',' esc_table_ref
           {
             MYSQL_YYABORT_UNLESS($1 && ($$=$3));
+            Select->add_joined_table($3);
           }
         ;
 
@@ -10956,11 +11627,18 @@ join_table:
             left-associative joins.
           */
           table_ref normal_join table_ref %prec TABLE_REF_PRIORITY
-          { MYSQL_YYABORT_UNLESS($1 && ($$=$3)); $3->straight=$2; }
+          { 
+            MYSQL_YYABORT_UNLESS($1 && ($$=$3));
+            Select->add_joined_table($1);
+            Select->add_joined_table($3);
+            $3->straight=$2;
+          }
         | table_ref normal_join table_ref
           ON
           {
             MYSQL_YYABORT_UNLESS($1 && $3);
+            Select->add_joined_table($1);
+            Select->add_joined_table($3);
             /* Change the current name resolution context to a local context. */
             if (push_new_name_resolution_context(thd, $1, $3))
               MYSQL_YYABORT;
@@ -10970,13 +11648,15 @@ join_table:
           {
 	    $3->straight=$2;
             add_join_on(thd, $3, $6);
-            Lex->pop_context();
+            Lex->pop_context("ON normal join");
             Select->parsing_place= NO_MATTER;
           }
         | table_ref normal_join table_ref
           USING
           {
             MYSQL_YYABORT_UNLESS($1 && $3);
+            Select->add_joined_table($1);
+            Select->add_joined_table($3);
           }
           '(' using_list ')'
           { 
@@ -10987,6 +11667,8 @@ join_table:
         | table_ref NATURAL inner_join table_factor
           {
             MYSQL_YYABORT_UNLESS($1 && ($$=$4));
+            Select->add_joined_table($1);
+            Select->add_joined_table($4);
 	    $4->straight=$3;
             add_join_natural($1,$4,NULL,Select);
           }
@@ -10996,6 +11678,8 @@ join_table:
           ON
           {
             MYSQL_YYABORT_UNLESS($1 && $5);
+            Select->add_joined_table($1);
+            Select->add_joined_table($5);
             /* Change the current name resolution context to a local context. */
             if (push_new_name_resolution_context(thd, $1, $5))
               MYSQL_YYABORT;
@@ -11004,7 +11688,7 @@ join_table:
           expr
           {
             add_join_on(thd, $5, $8);
-            Lex->pop_context();
+            Lex->pop_context("ON left join");
             $5->outer_join|=JOIN_TYPE_LEFT;
             $$=$5;
             Select->parsing_place= NO_MATTER;
@@ -11012,6 +11696,8 @@ join_table:
         | table_ref LEFT opt_outer JOIN_SYM table_factor
           {
             MYSQL_YYABORT_UNLESS($1 && $5);
+            Select->add_joined_table($1);
+            Select->add_joined_table($5);
           }
           USING '(' using_list ')'
           { 
@@ -11022,6 +11708,8 @@ join_table:
         | table_ref NATURAL LEFT opt_outer JOIN_SYM table_factor
           {
             MYSQL_YYABORT_UNLESS($1 && $6);
+            Select->add_joined_table($1);
+            Select->add_joined_table($6);
             add_join_natural($1,$6,NULL,Select);
             $6->outer_join|=JOIN_TYPE_LEFT;
             $$=$6;
@@ -11032,6 +11720,8 @@ join_table:
           ON
           {
             MYSQL_YYABORT_UNLESS($1 && $5);
+            Select->add_joined_table($1);
+            Select->add_joined_table($5);
             /* Change the current name resolution context to a local context. */
             if (push_new_name_resolution_context(thd, $1, $5))
               MYSQL_YYABORT;
@@ -11043,12 +11733,14 @@ join_table:
             if (!($$= lex->current_select->convert_right_join()))
               MYSQL_YYABORT;
             add_join_on(thd, $$, $8);
-            Lex->pop_context();
+            Lex->pop_context("ON right join");
             Select->parsing_place= NO_MATTER;
           }
         | table_ref RIGHT opt_outer JOIN_SYM table_factor
           {
             MYSQL_YYABORT_UNLESS($1 && $5);
+            Select->add_joined_table($1);
+            Select->add_joined_table($5);
           }
           USING '(' using_list ')'
           {
@@ -11060,6 +11752,8 @@ join_table:
         | table_ref NATURAL RIGHT opt_outer JOIN_SYM table_factor
           {
             MYSQL_YYABORT_UNLESS($1 && $6);
+            Select->add_joined_table($1);
+            Select->add_joined_table($6);
             add_join_natural($6,$1,NULL,Select);
             LEX *lex= Lex;
             if (!($$= lex->current_select->convert_right_join()))
@@ -11101,33 +11795,77 @@ use_partition:
 
    I.e.
    <table factor> ::= <table primary> [ <sample clause> ]
-*/   
+*/
+   
 /* Warning - may return NULL in case of incomplete SELECT */
+/*
 table_factor:
           table_primary_ident
         | table_primary_derived
         ;
+*/
+table_factor:
+          table_primary_ident { $$= $1; }
+        | table_primary_derived { $$= $1; }
+        | join_table_parens { $$= $1; }
+        | table_reference_list_parens { $$= $1; }
+        ;
 
-table_primary_ident:
+table_reference_list_parens:
+          '(' table_reference_list_parens ')' { $$= $2; }
+        | '(' nested_table_reference_list ')'
           {
-            SELECT_LEX *sel= Select;
-            sel->table_join_options= 0;
+            if (!($$= Select->end_nested_join(thd)))
+              MYSQL_YYABORT;
+          }
+        ;
+
+nested_table_reference_list:
+          table_ref ',' table_ref
+          {
+            if (Select->init_nested_join(thd))
+              MYSQL_YYABORT;
+            Select->add_joined_table($1);
+            Select->add_joined_table($3);
+            $$= $1->embedding;
+          }
+        | nested_table_reference_list ',' table_ref
+          { 
+            Select->add_joined_table($3);
+            $$= $1;
           }
+        ; 
+
+join_table_parens:
+          '(' join_table_parens ')' { $$= $2; }
+        | '(' join_table ')' 
+          {
+            LEX *lex= Lex;
+            if (!($$= lex->current_select->nest_last_join(thd)))
+            {
+              thd->parse_error();
+              MYSQL_YYABORT;
+            }
+          }
+        ;
+
+
+table_primary_ident:
           table_ident opt_use_partition opt_table_alias opt_key_definition
           {
-            if (!($$= Select->add_table_to_list(thd, $2, $4,
+            SELECT_LEX *sel= Select;
+            sel->table_join_options= 0;
+            if (!($$= Select->add_table_to_list(thd, $1, $3,
                                                 Select->get_table_join_options(),
                                                 YYPS->m_lock_type,
                                                 YYPS->m_mdl_type,
                                                 Select->pop_index_hints(),
-                                                $3)))
+                                                $2)))
               MYSQL_YYABORT;
-            Select->add_joined_table($$);
           }
         ;
 
 
-
 /*
   Represents a flattening of the following rules from the SQL:2003
   standard. This sub-rule corresponds to the sub-rule
@@ -11145,24 +11883,53 @@ table_primary_ident:
 */
 
 table_primary_derived:
-          '(' get_select_lex select_derived_union ')' opt_table_alias
+          '('
+          select_expr select_dedicated_tail
+          ')' opt_table_alias
           {
+            LEX *lex=Lex;
+            lex->pop_select_and_context(); //push at the end of select_expr
+            lex->derived_tables|= DERIVED_SUBQUERY;
+            $2->linkage= DERIVED_TABLE_TYPE;
+            SELECT_LEX *sel= lex->select_stack_head();
+            SELECT_LEX_UNIT *unit=
+              sel->attach_selects_chain($2, NULL);
+            if(!unit)
+              MYSQL_YYABORT;
+            if (unit->set_nest_level(sel->nest_level + 1))
+              MYSQL_YYABORT;
+
+            if ($3)
+              $3->set_to($2);
+            DBUG_ASSERT(lex->current_select == sel);
+            Table_ident *ti= new (thd->mem_root) Table_ident(unit);
+            if (ti == NULL)
+              MYSQL_YYABORT;
+            if (!($$= sel->add_table_to_list(lex->thd,
+                                             ti, $5, 0,
+                                             TL_READ, MDL_SHARED_READ)))
+              MYSQL_YYABORT;
             /* Use $2 instead of Lex->current_select as derived table will
                alter value of Lex->current_select. */
+/*
             if (!($3 || $5) && $2->embedding &&
                 !$2->embedding->nested_join->join_list.elements)
             {
+*/
               /* we have a derived table ($3 == NULL) but no alias,
                  Since we are nested in further parentheses so we
                  can pass NULL to the outer level parentheses
                  Permits parsing of "((((select ...))) as xyz)" */
+/*
               $$= 0;
             }
             else if (!$3)
             {
+*/
               /* Handle case of derived table, alias may be NULL if there
                  are no outer parentheses, add_table_to_list() will throw
                  error in this case */
+/*
               LEX *lex=Lex;
               lex->check_automatic_up(UNSPECIFIED_TYPE);
               SELECT_LEX *sel= lex->current_select;
@@ -11176,56 +11943,94 @@ table_primary_derived:
                                                TL_READ, MDL_SHARED_READ)))
 
                 MYSQL_YYABORT;
-              sel->add_joined_table($$);
-              lex->pop_context();
+              lex->pop_context("derived");
               lex->nest_level--;
             }
             else if ($5 != NULL)
             {
+*/
               /*
                 Tables with or without joins within parentheses cannot
                 have aliases, and we ruled out derived tables above.
               */
+/*
               thd->parse_error();
               MYSQL_YYABORT;
             }
             else
             {
+*/
               /* nested join: FROM (t1 JOIN t2 ...),
                  nest_level is the same as in the outer query */
+/*
               $$= $3;
             }
+*/
             /*
               Fields in derived table can be used in upper select in
               case of merge. We do not add HAVING fields because we do
               not merge such derived. We do not add union because
               also do not merge them
             */
+/*
             if ($$ && $$->derived &&
                 !$$->derived->first_select()->next_select())
               $$->select_lex->add_where_field($$->derived->first_select());
+*/
           }
           /* Represents derived table with WITH clause */
-        | '(' get_select_lex subselect_start
-              with_clause query_expression_body
-              subselect_end ')' opt_table_alias
+        | '('
+          with_clause
+          select_expr select_dedicated_tail
+          ')' opt_table_alias
+          {
+            LEX *lex=Lex;
+            lex->pop_select_and_context(); //push at the end of select_expr
+            lex->derived_tables|= DERIVED_SUBQUERY;
+            $3->linkage= DERIVED_TABLE_TYPE;
+            SELECT_LEX *sel= lex->select_stack_head();
+            SELECT_LEX_UNIT *unit=
+              sel->attach_selects_chain($3, NULL);
+            if(!unit)
+              MYSQL_YYABORT;
+            if (unit->set_nest_level(sel->nest_level + 1))
+              MYSQL_YYABORT;
+
+            SELECT_LEX *first_sel= unit->first_select();
+            if ($4)
+              $4->set_to($3);
+            DBUG_ASSERT(lex->current_select == sel);
+            Table_ident *ti= new (thd->mem_root) Table_ident(unit);
+            if (ti == NULL)
+              MYSQL_YYABORT;
+            first_sel->set_with_clause($2);
+            if (!($$= sel->add_table_to_list(lex->thd,
+                                             ti, $6, 0,
+                                             TL_READ, MDL_SHARED_READ)))
+              MYSQL_YYABORT;
+          }
+/*
+        | '('
+          {
+
+            if (Select->init_nested_join(thd))
+              MYSQL_YYABORT;
+          }
+          derived_table_list
           {
-            LEX *lex=Lex;
-            SELECT_LEX *sel= $2;
-            SELECT_LEX_UNIT *unit= $5->master_unit();
-            Table_ident *ti= new (thd->mem_root) Table_ident(unit);
-            if (ti == NULL)
+            if (!($$= Select->end_nested_join(thd)) && $3)
               MYSQL_YYABORT;
-            $5->set_with_clause($4);
-            lex->current_select= sel;
-            if (!($$= sel->add_table_to_list(lex->thd,
-                                             ti, $8, 0,
-                                             TL_READ, MDL_SHARED_READ)))
+
+            if (!$3 && $$)
+            {
+              thd->parse_error();
               MYSQL_YYABORT;
-            sel->add_joined_table($$);
-          } 
+            }
+          }
+*/
         ;
 
+
 /*
   This rule accepts just about anything. The reason is that we have
   empty-producing rules in the beginning of rules, in this case
@@ -11245,6 +12050,7 @@ table_primary_derived:
   the from clause only. Top level select statements and other types of
   subqueries have their own union rules.
 */
+/*
 select_derived_union:
           select_derived
         | select_derived union_order_or_limit
@@ -11268,27 +12074,30 @@ select_derived_union:
         | derived_query_specification order_or_limit opt_select_lock_type
         | derived_query_specification opt_select_lock_type union_list_derived
        ;
-
+*/
+/*
 union_list_derived_part2:
-         query_term_union_not_ready { Lex->pop_context(); }
-       | query_term_union_ready     { Lex->pop_context(); }
-       | query_term_union_ready     { Lex->pop_context(); } union_list_derived
+         query_term_union_not_ready { Lex->pop_context("u1"); }
+       | query_term_union_ready     { Lex->pop_context("u2"); }
+       | query_term_union_ready     { Lex->pop_context("u3"); } union_list_derived
        ;
 
 union_list_derived:
          union_head_non_top union_list_derived_part2
        ;
-
+*/
 
 /* The equivalent of select_init2 for nested queries. */
+/*
 select_init2_derived:
           select_part2_derived
           {
             Select->set_braces(0);
           }
         ;
-
+*/
 /* The equivalent of select_part2 for nested queries. */
+/*
 select_part2_derived:
           {
             LEX *lex= Lex;
@@ -11302,15 +12111,17 @@ select_part2_derived:
             Select->parsing_place= NO_MATTER;
           }
         ;
-
+*/
 /* handle contents of parentheses in join expression */
+/*
 select_derived:
           get_select_lex_derived derived_table_list
           {
             LEX *lex= Lex;
+*/
             /* for normal joins, $2 != NULL and end_nested_join() != NULL,
                for derived tables, both must equal NULL */
-
+/*
             if (!($$= $1->end_nested_join(lex->thd)) && $2)
               MYSQL_YYABORT;
             if (!$2 && $$)
@@ -11320,12 +12131,13 @@ select_derived:
             }
           }
         ;
-
+*/
 /*
   Similar to query_specification, but for derived tables.
   Example: the inner parenthesized SELECT in this query:
     SELECT * FROM (SELECT * FROM t1);
 */
+/*
 derived_query_specification:
           SELECT_SYM select_derived_init select_derived2
           {
@@ -11334,7 +12146,8 @@ derived_query_specification:
             $$= NULL;
           }
         ;
-
+*/
+/*
 select_derived2:
           {
             LEX *lex= Lex;
@@ -11349,7 +12162,7 @@ select_derived2:
                 mysql_new_select(lex, 1, NULL))
               MYSQL_YYABORT;
             mysql_init_select(lex);
-            lex->current_select->linkage= DERIVED_TABLE_TYPE;
+            lex->current_select->set_linkage(DERIVED_TABLE_TYPE);
             lex->current_select->parsing_place= SELECT_LIST;
           }
           select_options select_item_list
@@ -11358,11 +12171,14 @@ select_derived2:
           }
           opt_table_expression
         ;
-
+*/
+/*
 get_select_lex:
-          /* Empty */ { $$= Select; }
+          { $$= Select; }
         ;
+*/
 
+/*
 get_select_lex_derived:
           get_select_lex
           {
@@ -11379,10 +12195,12 @@ select_derived_init:
             TABLE_LIST *embedding= lex->current_select->embedding;
             $$= embedding &&
                 !embedding->nested_join->join_list.elements;
+*/
             /* return true if we are deeply nested */
+/*
           }
         ;
-
+*/
 opt_outer:
           /* empty */ {}
         | OUTER {}
@@ -11865,6 +12683,29 @@ order_list:
           { if (add_order_to_list(thd, $1,(bool) $2)) MYSQL_YYABORT; }
         ;
 
+order_clause_new:
+          ORDER_SYM BY
+          order_list_new
+          {
+            $$= $3;
+          }
+         ;
+
+order_list_new:
+          order_list_new ',' order_ident order_dir
+          {
+            $$= $1;
+            if (add_to_list(thd, *$$, $3,(bool) $4))
+              MYSQL_YYABORT;
+          }
+        | order_ident order_dir
+          {
+            $$= new (thd->mem_root) SQL_I_List<ORDER>();
+            if (add_to_list(thd, *$$, $1, (bool) $2))
+              MYSQL_YYABORT;
+          }
+        ;
+
 order_dir:
           /* empty */ { $$ =  1; }
         | ASC  { $$ =1; }
@@ -11908,6 +12749,61 @@ limit_clause:
           }
         ;
 
+opt_limit_clause_new:
+          /* empty */
+          {
+            $$.empty();
+          }
+        | limit_clause_new
+          {
+            $$= $1;
+          }
+        ;
+
+limit_clause_new:
+          LIMIT limit_options_new
+          {
+            $$= $2;
+            if (!$$.select_limit->basic_const_item() ||
+                $$.select_limit->val_int() > 0)
+              Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT);
+          }
+        | LIMIT limit_options_new
+          ROWS_SYM EXAMINED_SYM limit_rows_option
+          {
+            $$= $2;
+            Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT);
+          }
+        | LIMIT ROWS_SYM EXAMINED_SYM limit_rows_option
+          {
+            $$.select_limit= 0;
+            $$.offset_limit= 0;
+            $$.explicit_limit= 1;
+            Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT);
+          }
+        ;
+
+limit_options_new:
+          limit_option
+          {
+            $$.select_limit= $1;
+            $$.offset_limit= 0;
+            $$.explicit_limit= 1;
+          }
+        | limit_option ',' limit_option
+          {
+            $$.select_limit= $3;
+            $$.offset_limit= $1;
+            $$.explicit_limit= 1;
+          }
+        | limit_option OFFSET_SYM limit_option
+          {
+            $$.select_limit= $1;
+            $$.offset_limit= $3;
+            $$.explicit_limit= 1;
+          }
+        ;
+
 limit_options:
           limit_option
           {
@@ -12076,7 +12972,7 @@ procedure_clause:
           {
             LEX *lex=Lex;
 
-            DBUG_ASSERT(&lex->select_lex == lex->current_select);
+            //DBUG_ASSERT(&lex->select_lex == lex->current_select);
 
             lex->proc_list.elements=0;
             lex->proc_list.first=0;
@@ -12183,6 +13079,10 @@ select_outvar:
           }
         ;
 
+opt_into:
+          /* empty */
+        | into
+        ;
 into:
           INTO into_destination
         ;
@@ -12230,10 +13130,13 @@ do:
             LEX *lex=Lex;
             lex->sql_command = SQLCOM_DO;
             mysql_init_select(lex);
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
           }
           expr_list
           {
             Lex->insert_list= $3;
+            Lex->pop_select(); //main select
           }
         ;
 
@@ -12450,16 +13353,20 @@ insert:
             LEX *lex= Lex;
             lex->sql_command= SQLCOM_INSERT;
             lex->duplicates= DUP_ERROR; 
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
             mysql_init_select(lex);
           }
           insert_lock_option
           opt_ignore insert2
           {
             Select->set_lock_for_tables($3);
-            Lex->current_select= &Lex->select_lex;
+            Lex->current_select= Lex->first_select_lex();
           }
           insert_field_spec opt_insert_update
-          {}
+          {
+            Lex->pop_select(); //main select
+          }
         ;
 
 replace:
@@ -12468,15 +13375,19 @@ replace:
             LEX *lex=Lex;
             lex->sql_command = SQLCOM_REPLACE;
             lex->duplicates= DUP_REPLACE;
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
             mysql_init_select(lex);
           }
           replace_lock_option insert2
           {
             Select->set_lock_for_tables($3);
-            Lex->current_select= &Lex->select_lex;
+            Lex->current_select= Lex->first_select_lex();
           }
           insert_field_spec
-          {}
+          {
+            Lex->pop_select(); //main select
+          }
         ;
 
 insert_lock_option:
@@ -12653,6 +13564,8 @@ update:
           UPDATE_SYM
           {
             LEX *lex= Lex;
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
             mysql_init_select(lex);
             lex->sql_command= SQLCOM_UPDATE;
             lex->duplicates= DUP_ERROR; 
@@ -12661,13 +13574,13 @@ update:
           SET update_list
           {
             LEX *lex= Lex;
-            if (lex->select_lex.table_list.elements > 1)
+            if (lex->builtin_select.table_list.elements > 1)
               lex->sql_command= SQLCOM_UPDATE_MULTI;
-            else if (lex->select_lex.get_table_list()->derived)
+            else if (lex->builtin_select.get_table_list()->derived)
             {
               /* it is single table update and it is update of derived table */
               my_error(ER_NON_UPDATABLE_TABLE, MYF(0),
-                       lex->select_lex.get_table_list()->alias, "UPDATE");
+                       lex->builtin_select.get_table_list()->alias, "UPDATE");
               MYSQL_YYABORT;
             }
             /*
@@ -12677,7 +13590,10 @@ update:
             */
             Select->set_lock_for_tables($3);
           }
-          opt_where_clause opt_order_clause delete_limit_clause {}
+          opt_where_clause opt_order_clause delete_limit_clause
+          {
+            Lex->pop_select(); //main select
+          }
         ;
 
 update_list:
@@ -12723,9 +13639,11 @@ delete:
             mysql_init_select(lex);
             YYPS->m_lock_type= TL_WRITE_DEFAULT;
             YYPS->m_mdl_type= MDL_SHARED_WRITE;
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
 
             lex->ignore= 0;
-            lex->select_lex.init_order();
+            lex->builtin_select.init_order();
           }
           opt_delete_options single_multi
         ;
@@ -12744,9 +13662,14 @@ single_multi:
           }
           opt_where_clause opt_order_clause
           delete_limit_clause {}
-          opt_select_expressions {}
+          opt_select_expressions
+          {
+            Lex->pop_select(); //main select
+          }
         | table_wild_list
           {
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
             mysql_init_multi_delete(Lex);
             YYPS->m_lock_type= TL_READ_DEFAULT;
             YYPS->m_mdl_type= MDL_SHARED_READ;
@@ -12755,9 +13678,12 @@ single_multi:
           {
             if (multi_delete_set_locks_and_link_aux_tables(Lex))
               MYSQL_YYABORT;
+            Lex->pop_select(); //main select
           }
         | FROM table_alias_ref_list
           {
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
             mysql_init_multi_delete(Lex);
             YYPS->m_lock_type= TL_READ_DEFAULT;
             YYPS->m_mdl_type= MDL_SHARED_READ;
@@ -12766,6 +13692,7 @@ single_multi:
           {
             if (multi_delete_set_locks_and_link_aux_tables(Lex))
               MYSQL_YYABORT;
+            Lex->pop_select(); //main select
           }
         ;
 
@@ -12829,10 +13756,12 @@ truncate:
           {
             LEX* lex= Lex;
             lex->sql_command= SQLCOM_TRUNCATE;
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
             lex->alter_info.reset();
-            lex->select_lex.options= 0;
-            lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED;
-            lex->select_lex.init_order();
+            lex->builtin_select.options= 0;
+            lex->builtin_select.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED;
+            lex->builtin_select.init_order();
             YYPS->m_lock_type= TL_WRITE;
             YYPS->m_mdl_type= MDL_EXCLUSIVE;
           }
@@ -12843,6 +13772,7 @@ truncate:
             lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_truncate_table();
             if (lex->m_sql_cmd == NULL)
               MYSQL_YYABORT;
+            Lex->pop_select(); //main select
           }
         ;
 
@@ -12917,6 +13847,8 @@ show:
             LEX *lex=Lex;
             lex->wild=0;
             lex->ident= null_clex_str;
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
             mysql_init_select(lex);
             lex->current_select->parsing_place= SELECT_LIST;
             lex->create_info.init();
@@ -12924,6 +13856,7 @@ show:
           show_param
           {
             Select->parsing_place= NO_MATTER;
+            Lex->pop_select(); //main select
           }
         ;
 
@@ -12939,7 +13872,7 @@ show_param:
            {
              LEX *lex= Lex;
              lex->sql_command= SQLCOM_SHOW_TABLES;
-             lex->select_lex.db= $3.str;
+             lex->builtin_select.db= $3.str;
              if (prepare_schema_table(thd, lex, 0, SCH_TABLE_NAMES))
                MYSQL_YYABORT;
            }
@@ -12947,7 +13880,7 @@ show_param:
            {
              LEX *lex= Lex;
              lex->sql_command= SQLCOM_SHOW_TRIGGERS;
-             lex->select_lex.db= $3.str;
+             lex->builtin_select.db= $3.str;
              if (prepare_schema_table(thd, lex, 0, SCH_TRIGGERS))
                MYSQL_YYABORT;
            }
@@ -12955,7 +13888,7 @@ show_param:
            {
              LEX *lex= Lex;
              lex->sql_command= SQLCOM_SHOW_EVENTS;
-             lex->select_lex.db= $2.str;
+             lex->builtin_select.db= $2.str;
              if (prepare_schema_table(thd, lex, 0, SCH_EVENTS))
                MYSQL_YYABORT;
            }
@@ -12963,7 +13896,7 @@ show_param:
            {
              LEX *lex= Lex;
              lex->sql_command= SQLCOM_SHOW_TABLE_STATUS;
-             lex->select_lex.db= $3.str;
+             lex->builtin_select.db= $3.str;
              if (prepare_schema_table(thd, lex, 0, SCH_TABLES))
                MYSQL_YYABORT;
            }
@@ -12971,7 +13904,7 @@ show_param:
           {
             LEX *lex= Lex;
             lex->sql_command= SQLCOM_SHOW_OPEN_TABLES;
-            lex->select_lex.db= $3.str;
+            lex->builtin_select.db= $3.str;
             if (prepare_schema_table(thd, lex, 0, SCH_OPEN_TABLES))
               MYSQL_YYABORT;
           }
@@ -13135,7 +14068,7 @@ show_param:
           {
             LEX *lex= Lex;
             lex->sql_command = SQLCOM_SHOW_CREATE;
-            if (!lex->select_lex.add_table_to_list(thd, $3, NULL,0))
+            if (!lex->builtin_select.add_table_to_list(thd, $3, NULL,0))
               MYSQL_YYABORT;
             lex->create_info.storage_media= HA_SM_DEFAULT;
           }
@@ -13143,7 +14076,7 @@ show_param:
           {
             LEX *lex= Lex;
             lex->sql_command = SQLCOM_SHOW_CREATE;
-            if (!lex->select_lex.add_table_to_list(thd, $3, NULL, 0))
+            if (!lex->builtin_select.add_table_to_list(thd, $3, NULL, 0))
               MYSQL_YYABORT;
             lex->table_type= TABLE_TYPE_VIEW;
           }
@@ -13151,7 +14084,7 @@ show_param:
           {
             LEX *lex= Lex;
             lex->sql_command = SQLCOM_SHOW_CREATE;
-            if (!lex->select_lex.add_table_to_list(thd, $3, NULL, 0))
+            if (!lex->builtin_select.add_table_to_list(thd, $3, NULL, 0))
               MYSQL_YYABORT;
             lex->table_type= TABLE_TYPE_SEQUENCE;
           }
@@ -13336,7 +14269,7 @@ describe:
             mysql_init_select(lex);
             lex->current_select->parsing_place= SELECT_LIST;
             lex->sql_command= SQLCOM_SHOW_FIELDS;
-            lex->select_lex.db= 0;
+            lex->builtin_select.db= 0;
             lex->verbose= 0;
             if (prepare_schema_table(thd, lex, $2, SCH_COLUMNS))
               MYSQL_YYABORT;
@@ -13350,12 +14283,12 @@ describe:
           explainable_command
           {
             LEX *lex=Lex;
-            lex->select_lex.options|= SELECT_DESCRIBE;
+            lex->builtin_select.options|= SELECT_DESCRIBE;
           }
         ;
 
 explainable_command:
-          select
+          select_new
         | insert
         | replace
         | update
@@ -13376,6 +14309,8 @@ analyze_stmt_command:
 
 opt_extended_describe:
           EXTENDED_SYM   { Lex->describe|= DESCRIBE_EXTENDED; }
+        | EXTENDED_SYM ALL
+          { Lex->describe|= DESCRIBE_EXTENDED | DESCRIBE_EXTENDED2; }
         | PARTITIONS_SYM { Lex->describe|= DESCRIBE_PARTITIONS; }
         | opt_format_json {}
         ;
@@ -13603,6 +14538,8 @@ purge_option:
           TO_SYM TEXT_STRING_sys
           {
             Lex->to_log = $2.str;
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
           }
         | BEFORE_SYM expr
           {
@@ -13610,6 +14547,8 @@ purge_option:
             lex->value_list.empty();
             lex->value_list.push_front($2, thd->mem_root);
             lex->sql_command= SQLCOM_PURGE_BEFORE;
+
+            Lex->pop_select(); //main select
           }
         ;
 
@@ -13670,7 +14609,7 @@ use:
           {
             LEX *lex=Lex;
             lex->sql_command=SQLCOM_CHANGE_DB;
-            lex->select_lex.db= $2.str;
+            lex->builtin_select.db= $2.str;
           }
         ;
 
@@ -13687,6 +14626,8 @@ load:
                        $2 == FILETYPE_CSV ? "LOAD DATA" : "LOAD XML");
               MYSQL_YYABORT;
             }
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
           }
           load_data_lock opt_local INFILE TEXT_STRING_filesystem
           {
@@ -13713,7 +14654,9 @@ load:
           opt_xml_rows_identified_by
           opt_field_term opt_line_term opt_ignore_lines opt_field_or_var_spec
           opt_load_data_set_spec
-          {}
+          {
+            Lex->pop_select(); //main select
+          }
           ;
 
 data_or_xml:
@@ -14123,7 +15066,7 @@ opt_with_clause:
 
 
 with_clause:
-        WITH opt_recursive
+          WITH opt_recursive
           {
              With_clause *with_clause=
              new With_clause($2, Lex->curr_with_clause);
@@ -14133,7 +15076,7 @@ with_clause:
              Lex->curr_with_clause= with_clause;
              with_clause->add_to_list(Lex->with_clauses_list_last_next);
           }
-        with_list
+          with_list
           {
             $$= Lex->curr_with_clause;
             Lex->curr_with_clause= Lex->curr_with_clause->pop();
@@ -15021,14 +15964,20 @@ set:
           SET
           {
             LEX *lex=Lex;
+            if (lex->main_select_push())
+              MYSQL_YYABORT;
             lex->set_stmt_init();
             lex->var_list.empty();
             sp_create_assignment_lex(thd, yychar == YYEMPTY);
           }
           start_option_value_list
-          {}
+          {
+            Lex->pop_select(); //main select
+          }
         | SET STATEMENT_SYM
           {
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
             Lex->set_stmt_init();
           }
           set_stmt_option_value_following_option_type_list
@@ -15038,6 +15987,7 @@ set:
               my_yyabort_error((ER_SUBQUERIES_NOT_SUPPORTED, MYF(0), "SET STATEMENT"));
             lex->stmt_var_list= lex->var_list;
             lex->var_list.empty();
+            Lex->pop_select(); //main select
           }
           FOR_SYM verb_clause
 	  {}
@@ -15445,9 +16395,13 @@ lock:
             if (lex->sphead)
               my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "LOCK"));
             lex->sql_command= SQLCOM_LOCK_TABLES;
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
           }
           table_lock_list opt_lock_wait_timeout
-          {}
+          {
+            Lex->pop_select(); //main select
+          }
         ;
 
 opt_lock_wait_timeout:
@@ -15512,9 +16466,13 @@ unlock:
             if (lex->sphead)
               my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "UNLOCK"));
             lex->sql_command= SQLCOM_UNLOCK_TABLES;
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
           }
           table_or_tables
-          {}
+          {
+            Lex->pop_select(); //main select
+          }
         ;
 
 /*
@@ -16192,47 +17150,52 @@ release:
 */
 
 unit_type_decl:
-          UNION_SYM
-          { $$= UNION_TYPE; }
+          UNION_SYM union_option
+          { $$.unit_type= UNION_TYPE; $$.distinct= $2; }
         | INTERSECT_SYM
-          { $$= INTERSECT_TYPE; }
+          { $$.unit_type= INTERSECT_TYPE; $$.distinct= 1; }
         | EXCEPT_SYM
-          { $$= EXCEPT_TYPE; }
-
+          { $$.unit_type= EXCEPT_TYPE; $$.distinct= 1; }
 
+/*
 union_clause:
-          /* empty */ {}
+          {}
         | union_list
         ;
 
 union_list:
-          unit_type_decl union_option
+          unit_type_decl
           {
-            if (Lex->add_select_to_union_list((bool)$2, $1, TRUE))
+            if (Lex->add_select_to_union_list($1.distinct, $1.unit_type,
+                                              TRUE))
               MYSQL_YYABORT;
           }
           union_list_part2
           {
+*/
             /*
               Remove from the name resolution context stack the context of the
               last select in the union.
             */
-            Lex->pop_context();
+/*
+            Lex->pop_context("union list");
           }
         ;
-
+*/
+/*
 union_list_view:
-          unit_type_decl union_option
+          unit_type_decl
           {
-            if (Lex->add_select_to_union_list((bool)$2, $1, TRUE))
+            if (Lex->add_select_to_union_list($1.distinct, $1.unit_type, TRUE))
               MYSQL_YYABORT;
           }
           query_expression_body_view
           {
-            Lex->pop_context();
+            Lex->pop_context("union view");
           }
         ;
-
+*/
+/*
 union_order_or_limit:
           {
             LEX *lex= thd->lex;
@@ -16245,6 +17208,12 @@ union_order_or_limit:
               fake->no_table_names_allowed= 1;
               lex->current_select= fake;
             }
+            else if (sel->braces)
+            {
+              //thd->parse_error(ER_SYNTAX_ERROR);
+              //MYSQL_YYABORT;
+            }
+
             thd->where= "global ORDER clause";
           }
           order_or_limit
@@ -16253,6 +17222,75 @@ union_order_or_limit:
             thd->where= "";
           }
         ;
+*/
+
+global_select_on:
+          {
+            LEX *lex= thd->lex;
+            SELECT_LEX *sel= lex->first_select_lex();
+            SELECT_LEX_UNIT *unit= sel->master_unit();
+            SELECT_LEX *fake= unit->fake_select_lex;
+            if (fake)
+            {
+              fake->no_table_names_allowed= 1;
+              lex->push_select_and_context(fake, thd->mem_root);
+            }
+#if 0
+            else if (sel->braces)
+            {
+              thd->parse_error(ER_SYNTAX_ERROR);
+              MYSQL_YYABORT;
+            }
+#endif
+            else
+            {
+              lex->push_select_and_context(sel, thd->mem_root);
+            }
+            DBUG_ASSERT(lex->current_select->linkage != GLOBAL_OPTIONS_TYPE);
+          }
+      ; 
+
+global_select_off:
+          {
+            SELECT_LEX *sel;
+            if ((sel= Lex->pop_select_and_context()))
+              sel->no_table_names_allowed= 0;
+
+          }
+        ;
+
+
+global_order_or_limit:
+          {
+            thd->where= "global ORDER clause";
+          }
+          order_or_limit
+          {
+            thd->where= "";
+          }
+        ;
+
+
+order_or_limit_new:
+          order_clause_new opt_limit_clause_new
+          {
+            $$= new(thd->mem_root) Lex_order_limit_lock;
+            if (!$$)
+              YYABORT;
+            $$->order_list= $1;
+            $$->limit= $2;
+          }
+        | limit_clause_new
+          {
+            Lex_order_limit_lock *op= $$= new(thd->mem_root) Lex_order_limit_lock;
+            if (!$$)
+              YYABORT;
+            op->order_list= NULL;
+            op->limit= $1;
+            $$->order_list= NULL;
+            $$->limit= $1;
+          }
+        ;
 
 order_or_limit:
           order_clause opt_limit_clause
@@ -16262,14 +17300,15 @@ order_or_limit:
 /*
   Start a UNION, for non-top level query expressions.
 */
+/*
 union_head_non_top:
-          unit_type_decl union_option
+          unit_type_decl
           {
-            if (Lex->add_select_to_union_list((bool)$2, $1, FALSE))
+            if (Lex->add_select_to_union_list($1.distinct, $1.unit_type, FALSE))
               MYSQL_YYABORT;
           }
         ;
-
+*/
 union_option:
           /* empty */ { $$=1; }
         | DISTINCT  { $$=1; }
@@ -16277,95 +17316,24 @@ union_option:
         ;
 
 /*
-  Corresponds to the SQL Standard
-  <query specification> ::=
-    SELECT [ <set quantifier> ] <select list> <table expression>
-
-  Notes:
-  - We allow more options in addition to <set quantifier>
-  - <table expression> is optional in MariaDB
-*/
-query_specification:
-          SELECT_SYM select_init2_derived opt_table_expression
-          {
-            $$= Lex->current_select->master_unit()->first_select();
-          }
-        ;
-
 query_term_union_not_ready:
           query_specification order_or_limit opt_select_lock_type { $$= $1; }
         | '(' select_paren_derived ')' union_order_or_limit       { $$= $2; }
         ;
+*/
 
+/*
 query_term_union_ready:
           query_specification opt_select_lock_type                { $$= $1; }
         | '(' select_paren_derived ')'                            { $$= $2; }
         ;
+*/
 
-query_expression_body:
-          query_term_union_not_ready                                { $$= $1; }
-        | query_term_union_ready                                    { $$= $1; }
-        | query_term_union_ready union_list_derived                 { $$= $1; }
-        ;
-
-/* Corresponds to <query expression> in the SQL:2003 standard. */
-subselect:
-          subselect_start opt_with_clause query_expression_body subselect_end
-          { 
-            $3->set_with_clause($2);
-            $$= $3;
-          }
-        ;
-
-subselect_start:
-          {
-            LEX *lex=Lex;
-            if (!lex->expr_allows_subselect ||
-               lex->sql_command == (int)SQLCOM_PURGE)
-            {
-              thd->parse_error();
-              MYSQL_YYABORT;
-            }
-            /* 
-              we are making a "derived table" for the parenthesis
-              as we need to have a lex level to fit the union 
-              after the parenthesis, e.g. 
-              (SELECT .. ) UNION ...  becomes 
-              SELECT * FROM ((SELECT ...) UNION ...)
-            */
-            if (mysql_new_select(Lex, 1, NULL))
-              MYSQL_YYABORT;
-          }
-        ;
-
-subselect_end:
-          {
-            LEX *lex=Lex;
-
-            lex->check_automatic_up(UNSPECIFIED_TYPE);
-            lex->pop_context();
-            SELECT_LEX *child= lex->current_select;
-            lex->current_select = lex->current_select->return_after_parsing();
-            lex->nest_level--;
-            lex->current_select->n_child_sum_items += child->n_sum_items;
-            /*
-              A subselect can add fields to an outer select. Reserve space for
-              them.
-            */
-            lex->current_select->select_n_where_fields+=
-            child->select_n_where_fields;
-
-            /*
-              Aggregate functions in having clause may add fields to an outer
-              select. Count them also.
-            */
-            lex->current_select->select_n_having_items+=
-            child->select_n_having_items;
-          }
-        ;
-
+/*
 opt_query_expression_options:
+*/
           /* empty */
+/*
         | query_expression_option_list
         ;
 
@@ -16373,7 +17341,7 @@ query_expression_option_list:
           query_expression_option_list query_expression_option
         | query_expression_option
         ;
-
+*/
 query_expression_option:
           STRAIGHT_JOIN { Select->options|= SELECT_STRAIGHT_JOIN; }
         | HIGH_PRIORITY
@@ -16486,6 +17454,27 @@ view_select:
             lex->parsing_options.allows_variable= FALSE;
             lex->create_view->select.str= (char *) YYLIP->get_cpp_ptr();
           }
+          opt_with_clause
+          select_expr
+          select_dedicated_tail
+          view_check_option
+          {
+            LEX *lex=Lex;
+            lex->pop_select_and_context(); //push at the end of select_expr
+            if ($3->set_nest_level(1))
+              MYSQL_YYABORT;
+            SQL_I_List<TABLE_LIST> *save= &lex->first_select_lex()->table_list; 
+            lex->unit.cut_subtree();
+            lex->unit.register_select_chain($3);
+            lex->first_select_lex()->table_list.push_front(save);
+            if ($4)
+              $4->set_to($3);
+            lex->current_select= lex->first_select_lex();
+            lex->create_view->check= $5;
+            lex->parsing_options.allows_variable= TRUE;
+            if ($3)
+              $3->set_with_clause($2);
+/*
           opt_with_clause query_expression_body_view view_check_option
           {
             LEX *lex= Lex;
@@ -16500,6 +17489,7 @@ view_select:
             lex->create_view->check= $4;
             lex->parsing_options.allows_variable= TRUE;
             lex->current_select->set_with_clause($2);
+*/
           }
         ;
 
@@ -16507,13 +17497,14 @@ view_select:
   SQL Standard <query expression body> for VIEWs.
   Does not include INTO and PROCEDURE clauses.
 */
+/*
 query_expression_body_view:
           SELECT_SYM select_options_and_item_list select_init3_view
         | '(' select_paren_view ')'
         | '(' select_paren_view ')' union_order_or_limit
         | '(' select_paren_view ')' union_list_view
         ;
-
+*/
 view_check_option:
           /* empty */                     { $$= VIEW_CHECK_NONE; }
         | WITH CHECK_SYM OPTION           { $$= VIEW_CHECK_CASCADED; }
@@ -16612,11 +17603,11 @@ trigger_tail:
               sp_proc_stmt alternatives are not saving/restoring LEX, so
               lex->query_tables can be wiped out.
             */
-            if (!lex->select_lex.add_table_to_list(thd, $10,
-                                                   (LEX_CSTRING*) 0,
-                                                   TL_OPTION_UPDATING,
-                                                   TL_READ_NO_INSERT,
-                                                   MDL_SHARED_NO_WRITE))
+            if (!lex->builtin_select.add_table_to_list(thd, $10,
+                                                       (LEX_CSTRING*) 0,
+                                                       TL_OPTION_UPDATING,
+                                                       TL_READ_NO_INSERT,
+                                                       MDL_SHARED_NO_WRITE))
               MYSQL_YYABORT;
           }
         ;
diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy
index a430512f3a1..90af468c9b1 100644
--- a/sql/sql_yacc_ora.yy
+++ b/sql/sql_yacc_ora.yy
@@ -1440,7 +1440,7 @@ query:
           END_OF_INPUT
           {
             if (!thd->bootstrap &&
-              (!(thd->lex->select_lex.options & OPTION_FOUND_COMMENT)))
+              (!(thd->lex->builtin_select.options & OPTION_FOUND_COMMENT)))
               my_yyabort_error((ER_EMPTY_QUERY, MYF(0)));
 
             thd->lex->sql_command= SQLCOM_EMPTY_QUERY;
@@ -1893,9 +1893,9 @@ create:
             lex->create_info.init();
             if (lex->set_command_with_check(SQLCOM_CREATE_TABLE, $2, $1 | $4))
                MYSQL_YYABORT;
-            if (!lex->select_lex.add_table_to_list(thd, $5, NULL,
-                                                   TL_OPTION_UPDATING,
-                                                   TL_WRITE, MDL_EXCLUSIVE))
+            if (!lex->builtin_select.add_table_to_list(thd, $5, NULL,
+                                                       TL_OPTION_UPDATING,
+                                                       TL_WRITE, MDL_EXCLUSIVE))
               MYSQL_YYABORT;
             lex->alter_info.reset();
             /*
@@ -1910,7 +1910,7 @@ create:
           create_body
           {
             LEX *lex= thd->lex;
-            lex->current_select= &lex->select_lex; 
+            lex->current_select= &lex->builtin_select;
             if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) &&
                 !lex->create_info.db_type)
             {
@@ -1930,9 +1930,9 @@ create:
            if (lex->set_command_with_check(SQLCOM_CREATE_SEQUENCE, $2, $1 | $4))
               MYSQL_YYABORT;
 
-           if (!lex->select_lex.add_table_to_list(thd, $5, NULL,
-                                                  TL_OPTION_UPDATING,
-                                                  TL_WRITE, MDL_EXCLUSIVE))
+           if (!lex->builtin_select.add_table_to_list(thd, $5, NULL,
+                                                      TL_OPTION_UPDATING,
+                                                      TL_WRITE, MDL_EXCLUSIVE))
              MYSQL_YYABORT;
 
                /*
@@ -1955,8 +1955,8 @@ create:
             if (lex->create_info.seq_create_info->check_and_adjust(1))
             {
               my_error(ER_SEQUENCE_INVALID_DATA, MYF(0),
-                       lex->select_lex.table_list.first->db,
-                       lex->select_lex.table_list.first->table_name);
+                       lex->builtin_select.table_list.first->db,
+                       lex->builtin_select.table_list.first->table_name);
               MYSQL_YYABORT;
             }
 
@@ -1968,7 +1968,7 @@ create:
 	    Lex->create_info.used_fields|= HA_CREATE_USED_SEQUENCE;
             Lex->create_info.sequence= 1;
 
-            lex->current_select= &lex->select_lex;
+            lex->current_select= &lex->builtin_select;
             if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) &&
                 !lex->create_info.db_type)
             {
@@ -2414,7 +2414,7 @@ clear_privileges:
            lex->columns.empty();
            lex->grant= lex->grant_tot_col= 0;
            lex->all_privileges= 0;
-           lex->select_lex.db= 0;
+           lex->builtin_select.db= 0;
            lex->ssl_type= SSL_TYPE_NOT_SPECIFIED;
            lex->ssl_cipher= lex->x509_subject= lex->x509_issuer= 0;
            bzero((char *)&(lex->mqh),sizeof(lex->mqh));
@@ -4680,7 +4680,7 @@ create_body:
           {
 
             Lex->create_info.add(DDL_options_st::OPT_LIKE);
-            TABLE_LIST *src_table= Lex->select_lex.add_table_to_list(thd,
+            TABLE_LIST *src_table= Lex->builtin_select.add_table_to_list(thd,
                                         $1, NULL, 0, TL_READ, MDL_SHARED_READ);
             if (! src_table)
               MYSQL_YYABORT;
@@ -5683,7 +5683,7 @@ create_table_option:
           }
         | UNION_SYM opt_equal
           {
-            Lex->select_lex.table_list.save_and_clear(&Lex->save_list);
+            Lex->builtin_select.table_list.save_and_clear(&Lex->save_list);
           }
           '(' opt_table_list ')'
           {
@@ -5692,8 +5692,8 @@ create_table_option:
               from the global list.
             */
             LEX *lex=Lex;
-            lex->create_info.merge_list= lex->select_lex.table_list;
-            lex->select_lex.table_list= lex->save_list;
+            lex->create_info.merge_list= lex->builtin_select.table_list;
+            lex->builtin_select.table_list= lex->save_list;
             /*
               When excluding union list from the global list we assume that
               elements of the former immediately follow elements which represent
@@ -7136,7 +7136,7 @@ alter:
             Lex->table_type= TABLE_TYPE_UNKNOWN;
             Lex->sql_command= SQLCOM_ALTER_TABLE;
             Lex->duplicates= DUP_ERROR; 
-            Lex->select_lex.init_order();
+            Lex->builtin_select.init_order();
             Lex->create_info.init();
             Lex->create_info.row_type= ROW_TYPE_NOT_USED;
             Lex->alter_info.reset();
@@ -7146,12 +7146,12 @@ alter:
           }
           alter_options TABLE_SYM table_ident opt_lock_wait_timeout
           {
-            if (!Lex->select_lex.add_table_to_list(thd, $5, NULL,
-                                                   TL_OPTION_UPDATING,
-                                                   TL_READ_NO_INSERT,
-                                                   MDL_SHARED_UPGRADABLE))
+            if (!Lex->builtin_select.add_table_to_list(thd, $5, NULL,
+                                                       TL_OPTION_UPDATING,
+                                                       TL_READ_NO_INSERT,
+                                                       MDL_SHARED_UPGRADABLE))
               MYSQL_YYABORT;
-            Lex->select_lex.db= (Lex->select_lex.table_list.first)->db;
+            Lex->builtin_select.db= (Lex->builtin_select.table_list.first)->db;
             Lex->create_last_non_select_table= Lex->last_table();
           }
           alter_commands
@@ -7318,9 +7318,9 @@ alter:
             LEX *lex= Lex;
             if (!(lex->create_info.seq_create_info= new (thd->mem_root)
                                                      sequence_definition()) ||
-                !lex->select_lex.add_table_to_list(thd, $5, NULL,
-                                                   TL_OPTION_SEQUENCE,
-                                                   TL_WRITE, MDL_EXCLUSIVE))
+                !lex->builtin_select.add_table_to_list(thd, $5, NULL,
+                                                       TL_OPTION_SEQUENCE,
+                                                       TL_WRITE, MDL_EXCLUSIVE))
               MYSQL_YYABORT;
           }
           sequence_defs
@@ -7479,18 +7479,18 @@ alter_commands:
           {
             LEX *lex= thd->lex;
             size_t dummy;
-            lex->select_lex.db=$6->db.str;
-            if (lex->select_lex.db == NULL &&
-                lex->copy_db_to(&lex->select_lex.db, &dummy))
+            lex->builtin_select.db=$6->db.str;
+            if (lex->builtin_select.db == NULL &&
+                lex->copy_db_to(&lex->builtin_select.db, &dummy))
             {
               MYSQL_YYABORT;
             }
             lex->name= $6->table;
             lex->alter_info.flags|= Alter_info::ALTER_EXCHANGE_PARTITION;
-            if (!lex->select_lex.add_table_to_list(thd, $6, NULL,
-                                                   TL_OPTION_UPDATING,
-                                                   TL_READ_NO_INSERT,
-                                                   MDL_SHARED_NO_WRITE))
+            if (!lex->builtin_select.add_table_to_list(thd, $6, NULL,
+                                                       TL_OPTION_UPDATING,
+                                                       TL_READ_NO_INSERT,
+                                                       MDL_SHARED_NO_WRITE))
               MYSQL_YYABORT;
             DBUG_ASSERT(!lex->m_sql_cmd);
             lex->m_sql_cmd= new (thd->mem_root)
@@ -7741,9 +7741,9 @@ alter_list_item:
           {
             LEX *lex=Lex;
             size_t dummy;
-            lex->select_lex.db=$3->db.str;
-            if (lex->select_lex.db == NULL &&
-                lex->copy_db_to(&lex->select_lex.db, &dummy))
+            lex->builtin_select.db=$3->db.str;
+            if (lex->builtin_select.db == NULL &&
+                lex->copy_db_to(&lex->builtin_select.db, &dummy))
             {
               MYSQL_YYABORT;
             }
@@ -8420,8 +8420,8 @@ adm_partition:
 
 cache_keys_spec:
           {
-            Lex->select_lex.alloc_index_hints(thd);
-            Select->set_index_hint_type(INDEX_HINT_USE, 
+            Lex->builtin_select.alloc_index_hints(thd);
+            Select->set_index_hint_type(INDEX_HINT_USE,
                                         INDEX_HINT_MASK_ALL);
           }
           cache_key_list_or_empty
@@ -8690,16 +8690,16 @@ select_option:
               Allow this flag only on the first top-level SELECT statement, if
               SQL_CACHE wasn't specified, and only once per query.
              */
-            if (Lex->current_select != &Lex->select_lex)
+            if (Lex->current_select != &Lex->builtin_select)
               my_yyabort_error((ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_NO_CACHE"));
-            if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_CACHE)
+            if (Lex->builtin_select.sql_cache == SELECT_LEX::SQL_CACHE)
               my_yyabort_error((ER_WRONG_USAGE, MYF(0), "SQL_CACHE", "SQL_NO_CACHE"));
-            if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_NO_CACHE)
+            if (Lex->builtin_select.sql_cache == SELECT_LEX::SQL_NO_CACHE)
               my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "SQL_NO_CACHE"));
 
             Lex->safe_to_cache_query=0;
-            Lex->select_lex.options&= ~OPTION_TO_QUERY_CACHE;
-            Lex->select_lex.sql_cache= SELECT_LEX::SQL_NO_CACHE;
+            Lex->builtin_select.options&= ~OPTION_TO_QUERY_CACHE;
+            Lex->builtin_select.sql_cache= SELECT_LEX::SQL_NO_CACHE;
           }
         | SQL_CACHE_SYM
           {
@@ -8707,16 +8707,16 @@ select_option:
               Allow this flag only on the first top-level SELECT statement, if
               SQL_NO_CACHE wasn't specified, and only once per query.
              */
-            if (Lex->current_select != &Lex->select_lex)
+            if (Lex->current_select != &Lex->builtin_select)
               my_yyabort_error((ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_CACHE"));
-            if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_NO_CACHE)
+            if (Lex->builtin_select.sql_cache == SELECT_LEX::SQL_NO_CACHE)
               my_yyabort_error((ER_WRONG_USAGE, MYF(0), "SQL_NO_CACHE", "SQL_CACHE"));
-            if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_CACHE)
+            if (Lex->builtin_select.sql_cache == SELECT_LEX::SQL_CACHE)
               my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "SQL_CACHE"));
 
             Lex->safe_to_cache_query=1;
-            Lex->select_lex.options|= OPTION_TO_QUERY_CACHE;
-            Lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE;
+            Lex->builtin_select.options|= OPTION_TO_QUERY_CACHE;
+            Lex->builtin_select.sql_cache= SELECT_LEX::SQL_CACHE;
           }
         ;
 
@@ -11016,7 +11016,7 @@ join_table:
           {
 	    $3->straight=$2;
             add_join_on(thd, $3, $6);
-            Lex->pop_context();
+            Lex->pop_context("ON normal");
             Select->parsing_place= NO_MATTER;
           }
         | table_ref normal_join table_ref
@@ -11050,7 +11050,7 @@ join_table:
           expr
           {
             add_join_on(thd, $5, $8);
-            Lex->pop_context();
+            Lex->pop_context("ON left");
             $5->outer_join|=JOIN_TYPE_LEFT;
             $$=$5;
             Select->parsing_place= NO_MATTER;
@@ -11089,7 +11089,7 @@ join_table:
             if (!($$= lex->current_select->convert_right_join()))
               MYSQL_YYABORT;
             add_join_on(thd, $$, $8);
-            Lex->pop_context();
+            Lex->pop_context("ON right");
             Select->parsing_place= NO_MATTER;
           }
         | table_ref RIGHT opt_outer JOIN_SYM table_factor
@@ -11223,7 +11223,7 @@ table_primary_derived:
 
                 MYSQL_YYABORT;
               sel->add_joined_table($$);
-              lex->pop_context();
+              lex->pop_context("derived");
               lex->nest_level--;
             }
             else if ($5 != NULL)
@@ -11316,9 +11316,9 @@ select_derived_union:
        ;
 
 union_list_derived_part2:
-         query_term_union_not_ready { Lex->pop_context(); }
-       | query_term_union_ready     { Lex->pop_context(); }
-       | query_term_union_ready     { Lex->pop_context(); } union_list_derived
+         query_term_union_not_ready { Lex->pop_context("u1"); }
+       | query_term_union_ready     { Lex->pop_context("u2"); }
+       | query_term_union_ready     { Lex->pop_context("u3"); } union_list_derived
        ;
 
 union_list_derived:
@@ -11395,7 +11395,7 @@ select_derived2:
                 mysql_new_select(lex, 1, NULL))
               MYSQL_YYABORT;
             mysql_init_select(lex);
-            lex->current_select->linkage= DERIVED_TABLE_TYPE;
+            lex->current_select->set_linkage(DERIVED_TABLE_TYPE);
             lex->current_select->parsing_place= SELECT_LIST;
           }
           select_options select_item_list
@@ -12122,7 +12122,7 @@ procedure_clause:
           {
             LEX *lex=Lex;
 
-            DBUG_ASSERT(&lex->select_lex == lex->current_select);
+            DBUG_ASSERT(&lex->builtin_select == lex->current_select);
 
             lex->proc_list.elements=0;
             lex->proc_list.first=0;
@@ -12502,7 +12502,7 @@ insert:
           opt_ignore insert2
           {
             Select->set_lock_for_tables($3);
-            Lex->current_select= &Lex->select_lex;
+            Lex->current_select= &Lex->builtin_select;
           }
           insert_field_spec opt_insert_update
           {}
@@ -12519,7 +12519,7 @@ replace:
           replace_lock_option insert2
           {
             Select->set_lock_for_tables($3);
-            Lex->current_select= &Lex->select_lex;
+            Lex->current_select= &Lex->builtin_select;
           }
           insert_field_spec
           {}
@@ -12707,13 +12707,13 @@ update:
           SET update_list
           {
             LEX *lex= Lex;
-            if (lex->select_lex.table_list.elements > 1)
+            if (lex->builtin_select.table_list.elements > 1)
               lex->sql_command= SQLCOM_UPDATE_MULTI;
-            else if (lex->select_lex.get_table_list()->derived)
+            else if (lex->builtin_select.get_table_list()->derived)
             {
               /* it is single table update and it is update of derived table */
               my_error(ER_NON_UPDATABLE_TABLE, MYF(0),
-                       lex->select_lex.get_table_list()->alias, "UPDATE");
+                       lex->builtin_select.get_table_list()->alias, "UPDATE");
               MYSQL_YYABORT;
             }
             /*
@@ -12771,7 +12771,7 @@ delete:
             YYPS->m_mdl_type= MDL_SHARED_WRITE;
 
             lex->ignore= 0;
-            lex->select_lex.init_order();
+            lex->builtin_select.init_order();
           }
           opt_delete_options single_multi
         ;
@@ -12876,9 +12876,9 @@ truncate:
             LEX* lex= Lex;
             lex->sql_command= SQLCOM_TRUNCATE;
             lex->alter_info.reset();
-            lex->select_lex.options= 0;
-            lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED;
-            lex->select_lex.init_order();
+            lex->builtin_select.options= 0;
+            lex->builtin_select.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED;
+            lex->builtin_select.init_order();
             YYPS->m_lock_type= TL_WRITE;
             YYPS->m_mdl_type= MDL_EXCLUSIVE;
           }
@@ -12992,7 +12992,7 @@ show_param:
            {
              LEX *lex= Lex;
              lex->sql_command= SQLCOM_SHOW_TABLES;
-             lex->select_lex.db= $3.str;
+             lex->builtin_select.db= $3.str;
              if (prepare_schema_table(thd, lex, 0, SCH_TABLE_NAMES))
                MYSQL_YYABORT;
            }
@@ -13000,7 +13000,7 @@ show_param:
            {
              LEX *lex= Lex;
              lex->sql_command= SQLCOM_SHOW_TRIGGERS;
-             lex->select_lex.db= $3.str;
+             lex->builtin_select.db= $3.str;
              if (prepare_schema_table(thd, lex, 0, SCH_TRIGGERS))
                MYSQL_YYABORT;
            }
@@ -13008,7 +13008,7 @@ show_param:
            {
              LEX *lex= Lex;
              lex->sql_command= SQLCOM_SHOW_EVENTS;
-             lex->select_lex.db= $2.str;
+             lex->builtin_select.db= $2.str;
              if (prepare_schema_table(thd, lex, 0, SCH_EVENTS))
                MYSQL_YYABORT;
            }
@@ -13016,7 +13016,7 @@ show_param:
            {
              LEX *lex= Lex;
              lex->sql_command= SQLCOM_SHOW_TABLE_STATUS;
-             lex->select_lex.db= $3.str;
+             lex->builtin_select.db= $3.str;
              if (prepare_schema_table(thd, lex, 0, SCH_TABLES))
                MYSQL_YYABORT;
            }
@@ -13024,7 +13024,7 @@ show_param:
           {
             LEX *lex= Lex;
             lex->sql_command= SQLCOM_SHOW_OPEN_TABLES;
-            lex->select_lex.db= $3.str;
+            lex->builtin_select.db= $3.str;
             if (prepare_schema_table(thd, lex, 0, SCH_OPEN_TABLES))
               MYSQL_YYABORT;
           }
@@ -13188,7 +13188,7 @@ show_param:
           {
             LEX *lex= Lex;
             lex->sql_command = SQLCOM_SHOW_CREATE;
-            if (!lex->select_lex.add_table_to_list(thd, $3, NULL,0))
+            if (!lex->builtin_select.add_table_to_list(thd, $3, NULL,0))
               MYSQL_YYABORT;
             lex->create_info.storage_media= HA_SM_DEFAULT;
           }
@@ -13196,7 +13196,7 @@ show_param:
           {
             LEX *lex= Lex;
             lex->sql_command = SQLCOM_SHOW_CREATE;
-            if (!lex->select_lex.add_table_to_list(thd, $3, NULL, 0))
+            if (!lex->builtin_select.add_table_to_list(thd, $3, NULL, 0))
               MYSQL_YYABORT;
             lex->table_type= TABLE_TYPE_VIEW;
           }
@@ -13204,7 +13204,7 @@ show_param:
           {
             LEX *lex= Lex;
             lex->sql_command = SQLCOM_SHOW_CREATE;
-            if (!lex->select_lex.add_table_to_list(thd, $3, NULL, 0))
+            if (!lex->builtin_select.add_table_to_list(thd, $3, NULL, 0))
               MYSQL_YYABORT;
             lex->table_type= TABLE_TYPE_SEQUENCE;
           }
@@ -13389,7 +13389,7 @@ describe:
             mysql_init_select(lex);
             lex->current_select->parsing_place= SELECT_LIST;
             lex->sql_command= SQLCOM_SHOW_FIELDS;
-            lex->select_lex.db= 0;
+            lex->builtin_select.db= 0;
             lex->verbose= 0;
             if (prepare_schema_table(thd, lex, $2, SCH_COLUMNS))
               MYSQL_YYABORT;
@@ -13403,7 +13403,7 @@ describe:
           explainable_command
           {
             LEX *lex=Lex;
-            lex->select_lex.options|= SELECT_DESCRIBE;
+            lex->builtin_select.options|= SELECT_DESCRIBE;
           }
         ;
 
@@ -13723,7 +13723,7 @@ use:
           {
             LEX *lex=Lex;
             lex->sql_command=SQLCOM_CHANGE_DB;
-            lex->select_lex.db= $2.str;
+            lex->builtin_select.db= $2.str;
           }
         ;
 
@@ -16420,7 +16420,7 @@ union_list:
               Remove from the name resolution context stack the context of the
               last select in the union.
             */
-            Lex->pop_context();
+            Lex->pop_context("union list");
           }
         ;
 
@@ -16432,7 +16432,7 @@ union_list_view:
           }
           query_expression_body_view
           {
-            Lex->pop_context();
+            Lex->pop_context("union view");
           }
         ;
 
@@ -16546,7 +16546,7 @@ subselect_end:
             LEX *lex=Lex;
 
             lex->check_automatic_up(UNSPECIFIED_TYPE);
-            lex->pop_context();
+            lex->pop_context("subselect end");
             SELECT_LEX *child= lex->current_select;
             lex->current_select = lex->current_select->return_after_parsing();
             lex->nest_level--;
@@ -16818,11 +16818,11 @@ trigger_tail:
               sp_proc_stmt alternatives are not saving/restoring LEX, so
               lex->query_tables can be wiped out.
             */
-            if (!lex->select_lex.add_table_to_list(thd, $10,
-                                                   (LEX_CSTRING*) 0,
-                                                   TL_OPTION_UPDATING,
-                                                   TL_READ_NO_INSERT,
-                                                   MDL_SHARED_NO_WRITE))
+            if (!lex->builtin_select.add_table_to_list(thd, $10,
+                                                       (LEX_CSTRING*) 0,
+                                                       TL_OPTION_UPDATING,
+                                                       TL_READ_NO_INSERT,
+                                                       MDL_SHARED_NO_WRITE))
               MYSQL_YYABORT;
           }
         ;
diff --git a/sql/structs.h b/sql/structs.h
index 793be462b26..1d9bedd80c9 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -728,5 +728,58 @@ struct Lex_string_with_pos_st: public LEX_CSTRING
   const char *m_pos;
 };
 
+class Lex_select_lock
+{
+public:
+  struct
+  {
+    uint defined_lock:1;
+    uint update_lock:1;
+    uint defined_timeout:1;
+  };
+  ulong timeout;
+
+
+  void empty()
+  {
+    defined_lock= update_lock= defined_timeout= FALSE;
+    timeout= 0;
+  }
+};
+
+class Lex_select_limit
+{
+public:
+  bool explicit_limit;
+  Item *select_limit, *offset_limit;
+
+  void empty()
+  {
+    explicit_limit= FALSE;
+    select_limit= offset_limit= NULL;
+  }
+};
+
+struct st_order;
+class st_select_lex;
+
+/**
+  ORDER BY ... LIMIT parameters;
+*/
+class Lex_order_limit_lock
+{
+public:
+  SQL_I_List<st_order> *order_list;   /* ORDER clause */
+  Lex_select_lock lock;
+  Lex_select_limit limit;
+
+  static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
+  { return alloc_root(mem_root, size); }
+  Lex_order_limit_lock() :order_list(NULL)
+  {}
+
+  bool set_to(st_select_lex *sel);
+};
+
 
 #endif /* STRUCTS_INCLUDED */
diff --git a/sql/table.cc b/sql/table.cc
index 7dd93d5107d..fc8856b2b62 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -2594,7 +2594,7 @@ static bool sql_unusable_for_discovery(THD *thd, handlerton *engine,
   if (lex->create_info.like())
     return 1;
   // ... create select
-  if (lex->select_lex.item_list.elements)
+  if (lex->first_select_lex()->item_list.elements)
     return 1;
   // ... temporary
   if (create_info->tmp_table())
@@ -4813,13 +4813,13 @@ bool TABLE_LIST::single_table_updatable()
 {
   if (!updatable)
     return false;
-  if (view && view->select_lex.table_list.elements == 1)
+  if (view && view->first_select_lex()->table_list.elements == 1)
   {
     /*
       We need to check deeply only single table views. Multi-table views
       will be turned to multi-table updates and then checked by leaf tables
     */
-    return (((TABLE_LIST *)view->select_lex.table_list.first)->
+    return (((TABLE_LIST *)view->first_select_lex()->table_list.first)->
             single_table_updatable());
   }
   return true;
@@ -4856,7 +4856,8 @@ merge_on_conds(THD *thd, TABLE_LIST *table, bool is_cascaded)
     cond= table->on_expr->copy_andor_structure(thd);
   if (!table->view)
     DBUG_RETURN(cond);
-  for (TABLE_LIST *tbl= (TABLE_LIST*)table->view->select_lex.table_list.first;
+  for (TABLE_LIST *tbl=
+         (TABLE_LIST*)table->view->first_select_lex()->table_list.first;
        tbl;
        tbl= tbl->next_local)
   {
@@ -4898,7 +4899,7 @@ bool TABLE_LIST::prep_check_option(THD *thd, uint8 check_opt_type)
 {
   DBUG_ENTER("TABLE_LIST::prep_check_option");
   bool is_cascaded= check_opt_type == VIEW_CHECK_CASCADED;
-  TABLE_LIST *merge_underlying_list= view->select_lex.get_table_list();
+  TABLE_LIST *merge_underlying_list= view->first_select_lex()->get_table_list();
   for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
   {
     /* see comment of check_opt_type parameter */
@@ -5020,7 +5021,7 @@ TABLE_LIST *TABLE_LIST::find_underlying_table(TABLE *table_to_find)
   if (!view)
     return 0;
 
-  for (TABLE_LIST *tbl= view->select_lex.get_table_list();
+  for (TABLE_LIST *tbl= view->first_select_lex()->get_table_list();
        tbl;
        tbl= tbl->next_local)
   {
@@ -5192,7 +5193,8 @@ bool TABLE_LIST::set_insert_values(MEM_ROOT *mem_root)
   {
     DBUG_PRINT("info", ("setting insert_value for view"));
     DBUG_ASSERT(is_view_or_derived() && is_merged_derived());
-    for (TABLE_LIST *tbl= (TABLE_LIST*)view->select_lex.table_list.first;
+    for (TABLE_LIST *tbl=
+           (TABLE_LIST*)view->first_select_lex()->table_list.first;
          tbl;
          tbl= tbl->next_local)
       if (tbl->set_insert_values(mem_root))
@@ -5359,7 +5361,7 @@ void TABLE_LIST::register_want_access(ulong want_access)
   }
   if (!view)
     return;
-  for (TABLE_LIST *tbl= view->select_lex.get_table_list();
+  for (TABLE_LIST *tbl= view->first_select_lex()->get_table_list();
        tbl;
        tbl= tbl->next_local)
     tbl->register_want_access(want_access);
@@ -5567,14 +5569,14 @@ TABLE *TABLE_LIST::get_real_join_table()
       break;
     /* we do not support merging of union yet */
     DBUG_ASSERT(tbl->view == NULL ||
-               tbl->view->select_lex.next_select() == NULL);
+               tbl->view->first_select_lex()->next_select() == NULL);
     DBUG_ASSERT(tbl->derived == NULL ||
                tbl->derived->first_select()->next_select() == NULL);
 
     {
       List_iterator_fast<TABLE_LIST>
         ti(tbl->view != NULL ?
-           tbl->view->select_lex.top_join_list :
+           tbl->view->first_select_lex()->top_join_list :
            tbl->derived->first_select()->top_join_list);
       for (;;)
       {
@@ -5745,7 +5747,7 @@ Item *Field_iterator_view::create_item(THD *thd)
 Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref,
                         LEX_CSTRING *name)
 {
-  bool save_wrapper= thd->lex->select_lex.no_wrap_view_item;
+  bool save_wrapper= thd->lex->first_select_lex()->no_wrap_view_item;
   Item *field= *field_ref;
   DBUG_ENTER("create_view_field");
 
@@ -5776,8 +5778,9 @@ Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref,
   {
     DBUG_RETURN(field);
   }
-  Name_resolution_context *context= view->view ? &view->view->select_lex.context :
-                                    &thd->lex->select_lex.context;
+  Name_resolution_context *context= (view->view ?
+                                     &view->view->first_select_lex()->context:
+                                     &thd->lex->first_select_lex()->context);
   Item *item= (new (thd->mem_root)
                Item_direct_view_ref(thd, context, field_ref, view->alias,
                                     name, view));
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
index 63d153a7af4..68bd8f41796 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -1319,7 +1319,7 @@ static int
 create_view_query(THD *thd, uchar** buf, size_t* buf_len)
 {
     LEX *lex= thd->lex;
-    SELECT_LEX *select_lex= &lex->select_lex;
+    SELECT_LEX *select_lex= lex->first_select_lex();
     TABLE_LIST *first_table= select_lex->table_list.first;
     TABLE_LIST *views = first_table;
     LEX_USER *definer;
@@ -1413,7 +1413,7 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table,
   DBUG_ASSERT(table_list || db);
 
   LEX* lex= thd->lex;
-  SELECT_LEX* select_lex= &lex->select_lex;
+  SELECT_LEX* select_lex= lex->first_select_lex();
   TABLE_LIST* first_table= select_lex->table_list.first;
 
   switch (lex->sql_command)
diff --git a/storage/mroonga/ha_mroonga.cpp b/storage/mroonga/ha_mroonga.cpp
index 963f657d735..9b1e5bce412 100644
--- a/storage/mroonga/ha_mroonga.cpp
+++ b/storage/mroonga/ha_mroonga.cpp
@@ -182,7 +182,7 @@ static mysql_mutex_t *mrn_LOCK_open;
 #if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
 #  define MRN_LEX_GET_TABLE_LIST(lex) (lex)->select_lex->table_list.first
 #else
-#  define MRN_LEX_GET_TABLE_LIST(lex) (lex)->select_lex.table_list.first
+#  define MRN_LEX_GET_TABLE_LIST(lex) (lex)->first_select_lex()->table_list.first
 #endif
 
 #if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
diff --git a/storage/spider/spd_db_mysql.cc b/storage/spider/spd_db_mysql.cc
index 4e2a41e9fa6..7d6d895b514 100644
--- a/storage/spider/spd_db_mysql.cc
+++ b/storage/spider/spd_db_mysql.cc
@@ -6438,7 +6438,7 @@ int spider_mysql_handler::append_select(
     if (result_list->lock_type != F_WRLCK && spider->lock_mode < 1)
     {
       /* no lock */
-      st_select_lex *select_lex = &spider->trx->thd->lex->select_lex;
+      st_select_lex *select_lex = spider->trx->thd->lex->first_select_lex();
       if (
         select_lex->sql_cache == SELECT_LEX::SQL_CACHE &&
         (spider->share->query_cache_sync & 1)
diff --git a/storage/tokudb/tokudb_dir_cmd.cc b/storage/tokudb/tokudb_dir_cmd.cc
index 5431cbab7aa..d0da92eab27 100644
--- a/storage/tokudb/tokudb_dir_cmd.cc
+++ b/storage/tokudb/tokudb_dir_cmd.cc
@@ -50,11 +50,11 @@ static int MDL_and_TDC(THD *thd,
     table_arg.str = const_cast<char *>(table);
     table_arg.length = strlen(table);
     Table_ident table_ident(thd, &db_arg, &table_arg, true);;
-    thd->lex->select_lex.add_table_to_list(
+    thd->lex->first_select_lex()->add_table_to_list(
         thd, &table_ident, NULL, 1, TL_UNLOCK, MDL_EXCLUSIVE, 0, 0, 0);
     /* The lock will be released at the end of mysq_execute_command() */
     error = lock_table_names(thd,
-                             thd->lex->select_lex.table_list.first,
+                             thd->lex->first_select_lex()->table_list.first,
                              NULL,
                              thd->variables.lock_wait_timeout,
                              0);


More information about the commits mailing list