[Commits] b32031991e4: initial oracle parser fix

Oleksandr Byelkin sanja at mariadb.com
Fri Apr 6 18:34:31 EEST 2018


revision-id: b32031991e4ba270f5c221f7f6068732d09efd53 (mariadb-10.3.5-110-gb32031991e4)
parent(s): 60a502eb7efbe87bd8e3af3e3ece49a9eb83f8b3
author: Oleksandr Byelkin
committer: Oleksandr Byelkin
timestamp: 2018-04-06 17:05:34 +0200
message:

initial oracle parser fix

---
 sql/sql_yacc.yy     |    8 +-
 sql/sql_yacc_ora.yy | 2085 +++++++++++++++++++++++++++++----------------------
 2 files changed, 1183 insertions(+), 910 deletions(-)

diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index e4cbff7114e..9372269b05d 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -904,7 +904,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
 %parse-param { THD *thd }
 %lex-param { THD *thd }
 /*
-  Currently there are 96 shift/reduce conflicts.
+  Currently there are 135 shift/reduce conflicts.
   We should not introduce new conflicts any more.
 */
 %expect 135
@@ -9244,7 +9244,7 @@ table_value_constructor:
                   lex->push_select(sel))
               MYSQL_YYABORT;
             sel->init_select();
-            sel->braces= FALSE;
+            sel->braces= FALSE; // just initialisation
 	  }
 	  values_list
 	  {
@@ -13763,8 +13763,10 @@ single_multi:
           }
         | table_wild_list
           {
+            /* XXX
             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;
@@ -13779,8 +13781,10 @@ single_multi:
           }
         | FROM table_alias_ref_list
           {
+            /* XXX
             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;
diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy
index c1512434d72..4a3ee348f89 100644
--- a/sql/sql_yacc_ora.yy
+++ b/sql/sql_yacc_ora.yy
@@ -186,6 +186,20 @@ void ORAerror(THD *thd, const char *s)
     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;
+  SQL_I_List<ORDER> *select_order;
+  Lex_select_lock select_lock;
+  Lex_select_limit select_limit;
+  Lex_order_limit_lock *order_limit_lock;
 
   /* pointers */
   Create_field *create_field;
@@ -231,6 +245,7 @@ void ORAerror(THD *thd, const char *s)
 
   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;
@@ -240,7 +255,6 @@ void ORAerror(THD *thd, const char *s)
   /* enums */
   enum enum_sp_suid_behaviour sp_suid;
   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;
@@ -277,10 +291,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
 %parse-param { THD *thd }
 %lex-param { THD *thd }
 /*
-  Currently there are 104 shift/reduce conflicts.
+  Currently there are 99 shift/reduce conflicts.
   We should not introduce new conflicts any more.
 */
-%expect 104
+%expect 99
 
 /*
    Comments for TOKENS.
@@ -599,6 +613,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
 %token  LEAVES
 %token  LEAVE_SYM
 %token  LEFT                          /* SQL-2003-R */
+%token  LEFT_PAREN_ALT                /* INTERNAL */
+%token  LEFT_PAREN_WITH               /* INTERNAL */
+%token  LEFT_PAREN_LIKE               /* INTERNAL */
 %token  LESS_SYM
 %token  LEVEL_SYM
 %token  LEX_HOSTNAME
@@ -1063,7 +1080,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
         NCHAR_STRING
 
 %type <lex_str_ptr>
-        opt_table_alias
+        opt_table_alias_clause
+        table_alias_clause
 
 %type <lex_string_with_pos>
         ident ident_with_tok_start
@@ -1111,7 +1129,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
         opt_temporary all_or_any opt_distinct opt_glimit_clause
         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
@@ -1231,9 +1249,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *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
 
@@ -1276,12 +1293,16 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
         UNDERSCORE_CHARSET
 
 %type <select_lex> subselect
-        get_select_lex get_select_lex_derived
         query_specification
-        query_term_union_not_ready
-        query_term_union_ready
+        table_value_constructor
+        simple_table
+        query_primary
+        query_primary_parens
+
+%type <select_lex_unit>
         query_expression_body
-        select_paren_derived
+        query_expression
+        query_expression_unit
 
 %type <boolfunc2creator> comp_op
 
@@ -1293,7 +1314,21 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *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
+        select_lock_type
+        opt_lock_wait_timeout_new
+
+%type <select_limit> opt_limit_clause limit_clause limit_options
+
+%type <order_limit_lock>
+        query_expression_tail
+        order_or_limit
+
+%type <select_order> opt_order_clause order_clause order_list
 
 %type <NONE>
         analyze_stmt_command
@@ -1313,7 +1348,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
         assign_to_keycache_parts
         preload_list preload_list_or_parts preload_keys preload_keys_parts
         select_item_list select_item values_list no_braces
-        opt_limit_clause delete_limit_clause fields opt_values values
+        delete_limit_clause fields opt_values values
         procedure_list procedure_list2 procedure_item
         field_def handler opt_generated_always
         opt_ignore opt_column opt_restrict
@@ -1333,9 +1368,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *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
@@ -1606,14 +1640,22 @@ 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"));
+            if (Lex->check_main_unit_semantics())
+              MYSQL_YYABORT;
             lex->sql_command= SQLCOM_PREPARE;
-            lex->prepared_stmt_name= $2;
+            lex->prepared_stmt_name= $3;
+            Lex->pop_select(); //main select
           }
         ;
 
@@ -1632,10 +1674,21 @@ execute:
             LEX *lex= thd->lex;
             lex->sql_command= SQLCOM_EXECUTE;
             lex->prepared_stmt_name= $2;
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
           }
           execute_using
-          {}
-        | EXECUTE_SYM IMMEDIATE_SYM prepare_src
+          {
+            Lex->pop_select(); //main select
+            if (Lex->check_main_unit_semantics())
+              MYSQL_YYABORT;
+          }
+        | EXECUTE_SYM IMMEDIATE_SYM
+          {
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
+          }
+          prepare_src
           {
             if (Lex->table_or_sp_used())
               my_yyabort_error((ER_SUBQUERIES_NOT_SUPPORTED, MYF(0),
@@ -1643,7 +1696,11 @@ execute:
             Lex->sql_command= SQLCOM_EXECUTE_IMMEDIATE;
           }
           execute_using
-          {}
+          {
+            Lex->pop_select(); //main select
+            if (Lex->check_main_unit_semantics())
+              MYSQL_YYABORT;
+          }
         ;
 
 execute_using:
@@ -1928,13 +1985,20 @@ connection_name:
 /* create a table */
 
 create:
-          create_or_replace opt_temporary TABLE_SYM opt_if_not_exists table_ident
+          create_or_replace opt_temporary TABLE_SYM opt_if_not_exists
           {
             LEX *lex= thd->lex;
             lex->create_info.init();
+            if (lex->main_select_push())
+              MYSQL_YYABORT;
+            lex->current_select->parsing_place= BEFORE_OPT_LIST;
             if (lex->set_command_with_check(SQLCOM_CREATE_TABLE, $2, $1 | $4))
                MYSQL_YYABORT;
-            if (!lex->builtin_select.add_table_to_list(thd, $5, NULL,
+          }
+          table_ident
+          {
+            LEX *lex= thd->lex;
+            if (!lex->builtin_select.add_table_to_list(thd, $6, NULL,
                                                        TL_OPTION_UPDATING,
                                                        TL_WRITE, MDL_EXCLUSIVE))
               MYSQL_YYABORT;
@@ -1960,13 +2024,16 @@ create:
                                   ER_WARN_USING_OTHER_HANDLER,
                                   ER_THD(thd, ER_WARN_USING_OTHER_HANDLER),
                                   hton_name(lex->create_info.db_type)->str,
-                                  $5->table.str);
+                                  $6->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;
@@ -2021,42 +2088,69 @@ 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
+        | create_or_replace opt_unique INDEX_SYM opt_if_not_exists
+          {
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
+          }
+          ident
           opt_key_algorithm_clause
           ON table_ident
           {
-            if (Lex->add_create_index_prepare($8))
+            if (Lex->add_create_index_prepare($9))
               MYSQL_YYABORT;
-            if (Lex->add_create_index($2, &$5, $6, $1 | $4))
+            if (Lex->add_create_index($2, &$6, $7, $1 | $4))
               MYSQL_YYABORT;
           }
           '(' key_list ')' opt_lock_wait_timeout normal_key_options
-          opt_index_lock_algorithm { }
-        | create_or_replace fulltext INDEX_SYM opt_if_not_exists ident
+          opt_index_lock_algorithm
+          {
+            Lex->pop_select(); //main select
+          }
+        | create_or_replace fulltext INDEX_SYM
+          {
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
+          }
+          opt_if_not_exists ident
           ON table_ident
           {
-            if (Lex->add_create_index_prepare($7))
+            if (Lex->add_create_index_prepare($8))
               MYSQL_YYABORT;
-            if (Lex->add_create_index($2, &$5, HA_KEY_ALG_UNDEF, $1 | $4))
+            if (Lex->add_create_index($2, &$6, HA_KEY_ALG_UNDEF, $1 | $5))
               MYSQL_YYABORT;
           }
           '(' key_list ')' opt_lock_wait_timeout fulltext_key_options
-          opt_index_lock_algorithm { }
-        | create_or_replace spatial INDEX_SYM opt_if_not_exists ident
+          opt_index_lock_algorithm
+          {
+            Lex->pop_select(); //main select
+          }
+        | create_or_replace spatial INDEX_SYM
+          {
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
+          }
+          opt_if_not_exists ident
           ON table_ident
           {
-            if (Lex->add_create_index_prepare($7))
+            if (Lex->add_create_index_prepare($8))
               MYSQL_YYABORT;
-            if (Lex->add_create_index($2, &$5, HA_KEY_ALG_UNDEF, $1 | $4))
+            if (Lex->add_create_index($2, &$6, HA_KEY_ALG_UNDEF, $1 | $5))
               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
           {
@@ -2064,51 +2158,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->main_select_push())
+              MYSQL_YYABORT;
             if (Lex->add_create_view(thd, $1 | $6, $2, $4, $7))
               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_standalone
-          { }
+          {
+            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_standalone
-          { }
+          {
+            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
           {
@@ -2815,8 +2952,13 @@ call:
           {
             if (Lex->call_statement_start(thd, $2))
               MYSQL_YYABORT;
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
+          }
+          opt_sp_cparam_list
+          {
+            Lex->pop_select(); //main select
           }
-          opt_sp_cparam_list {}
         ;
 
 /* CALL parameters */
@@ -3346,10 +3488,16 @@ raise_stmt:
         ;
 
 signal_stmt:
-          SIGNAL_SYM signal_value opt_set_signal_information
+          SIGNAL_SYM
           {
-            if (Lex->add_signal_statement(thd, $2))
+            if (Lex->main_select_push())
+              YYABORT;
+          }
+          signal_value opt_set_signal_information
+          {
+            if (Lex->add_signal_statement(thd, $3))
               MYSQL_YYABORT;
+            Lex->pop_select(); //main select
           }
         ;
 
@@ -3475,9 +3623,14 @@ resignal_stmt:
         ;
 
 get_diagnostics:
-          GET_SYM which_area DIAGNOSTICS_SYM diagnostics_information
+          GET_SYM which_area DIAGNOSTICS_SYM
+          {
+            if (Lex->main_select_push())
+              YYABORT;
+          }
+          diagnostics_information
           {
-            Diagnostics_information *info= $4;
+            Diagnostics_information *info= $5;
 
             info->set_which_da($2);
 
@@ -3486,6 +3639,7 @@ get_diagnostics:
 
             if (Lex->m_sql_cmd == NULL)
               MYSQL_YYABORT;
+            Lex->pop_select(); //main select
           }
         ;
 
@@ -3666,8 +3820,26 @@ sp_decl_idents:
 
 sp_opt_default:
           /* Empty */ { $$ = NULL; }
-        | DEFAULT expr { $$ = $2; }
-        | SET_VAR expr { $$ = $2; }
+        | DEFAULT
+          {
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
+          }
+          expr
+          {
+            Lex->pop_select(); //main select
+            $$ = $3;
+          }
+        | SET_VAR
+          {
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
+          }
+          expr
+          {
+            Lex->pop_select(); //main select
+            $$ = $3;
+          }
         ;
 
 sp_proc_stmt:
@@ -3784,10 +3956,15 @@ sp_proc_stmt_statement:
 
 sp_proc_stmt_return:
           RETURN_SYM 
-          { Lex->sphead->reset_lex(thd); }
+          {
+            Lex->sphead->reset_lex(thd);
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
+          }
           expr
           {
             LEX *lex= Lex;
+            lex->pop_select(); //main select
             sp_head *sp= lex->sphead;
             if (sp->m_handler->add_instr_freturn(thd, sp, lex->spcont,
                                                  $3, lex) ||
@@ -3902,6 +4079,8 @@ assignment_source_expr:
           {
             DBUG_ASSERT(thd->free_list == NULL);
             Lex->sphead->reset_lex(thd, $1);
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
           }
           expr
           {
@@ -3910,6 +4089,7 @@ assignment_source_expr:
             $$->sp_lex_in_use= true;
             $$->set_item_and_free_list($3, thd->free_list);
             thd->free_list= NULL;
+            Lex->pop_select(); //main select
             if ($$->sphead->restore_lex(thd))
               MYSQL_YYABORT;
           }
@@ -4030,9 +4210,14 @@ sp_fetch_list:
         ;
 
 sp_if:
-          { Lex->sphead->reset_lex(thd); }
+          {
+            Lex->sphead->reset_lex(thd);
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
+          }
           expr THEN_SYM
           {
+            Lex->pop_select(); //main select
             LEX *lex= Lex;
             sp_head *sp= lex->sphead;
             sp_pcontext *ctx= lex->spcont;
@@ -4144,12 +4329,18 @@ case_stmt_specification:
         ;
 
 case_stmt_body:
-          { Lex->sphead->reset_lex(thd); /* For expr $2 */ }
+          {
+            Lex->sphead->reset_lex(thd); /* For expr $2 */
+
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
+          }
           expr
           {
             if (Lex->case_stmt_action_expr($2))
               MYSQL_YYABORT;
 
+            Lex->pop_select(); //main select
             if (Lex->sphead->restore_lex(thd))
               MYSQL_YYABORT;
           }
@@ -4173,6 +4364,9 @@ simple_when_clause:
           WHEN_SYM
           {
             Lex->sphead->reset_lex(thd); /* For expr $3 */
+
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
           }
           expr
           {
@@ -4181,6 +4375,8 @@ simple_when_clause:
             LEX *lex= Lex;
             if (lex->case_stmt_action_when($3, true))
               MYSQL_YYABORT;
+
+            lex->pop_select(); //main select
             /* For expr $3 */
             if (lex->sphead->restore_lex(thd))
               MYSQL_YYABORT;
@@ -4197,12 +4393,17 @@ searched_when_clause:
           WHEN_SYM
           {
             Lex->sphead->reset_lex(thd); /* For expr $3 */
+
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
           }
           expr
           {
             LEX *lex= Lex;
             if (lex->case_stmt_action_when($3, false))
               MYSQL_YYABORT;
+
+            lex->pop_select(); //main select
             /* For expr $3 */
             if (lex->sphead->restore_lex(thd))
               MYSQL_YYABORT;
@@ -4442,6 +4643,7 @@ while_body:
             LEX *lex= Lex;
             if (lex->sp_while_loop_expression(thd, $1))
               MYSQL_YYABORT;
+            Lex->pop_select(); //main select pushed before while_body use
             if (lex->sphead->restore_lex(thd))
               MYSQL_YYABORT;
           }
@@ -4454,7 +4656,12 @@ while_body:
 
 repeat_body:
           sp_proc_stmts1 UNTIL_SYM 
-          { Lex->sphead->reset_lex(thd); }
+          {
+            Lex->sphead->reset_lex(thd);
+
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
+          }
           expr END REPEAT_SYM
           {
             LEX *lex= Lex;
@@ -4465,6 +4672,8 @@ repeat_body:
             if (i == NULL ||
                 lex->sphead->add_instr(i))
               MYSQL_YYABORT;
+
+            lex->pop_select(); //main select
             if (lex->sphead->restore_lex(thd))
               MYSQL_YYABORT;
             /* We can shortcut the cont_backpatch here */
@@ -4493,8 +4702,12 @@ sp_labeled_control:
             if (Lex->sp_push_loop_label(thd, &$1))
               MYSQL_YYABORT;
             Lex->sphead->reset_lex(thd);
+
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
           }
           while_body pop_sp_loop_label
+
           { }
         | labels_declaration_oracle FOR_SYM
           {
@@ -4546,9 +4759,13 @@ sp_unlabeled_control:
             if (Lex->sp_push_loop_empty_label(thd))
               MYSQL_YYABORT;
             Lex->sphead->reset_lex(thd);
+
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
           }
           while_body
           {
+            // while body pop main select
             Lex->sp_pop_loop_empty_label(thd);
           }
         | FOR_SYM
@@ -4981,20 +5198,10 @@ size_number:
 */
 
 create_body:
-          '(' create_field_list ')'
+          create_field_list_parens
           { Lex->create_info.option_list= NULL; }
           opt_create_table_options opt_create_partitioning opt_create_select {}
         | opt_create_table_options opt_create_partitioning opt_create_select {}
-        /*
-          the following rule is redundant, but there's a shift/reduce
-          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
           {
 
@@ -5010,7 +5217,7 @@ create_body:
 
 create_like:
           LIKE table_ident                      { $$= $2; }
-        | '(' LIKE table_ident ')'              { $$= $3; }
+        | LEFT_PAREN_LIKE LIKE table_ident ')'  { $$= $3; }
         ;
 
 opt_create_select:
@@ -5019,23 +5226,42 @@ opt_create_select:
         ;
 
 create_select_query_expression:
-          opt_with_clause SELECT_SYM create_select_part2 opt_table_expression
-          create_select_part4
-          { 
-            Select->set_braces(0);
-            Select->set_with_clause($1);
+          query_expression
+          {
+            SELECT_LEX *first_select= $1->first_select();
+
+            if (Lex->sql_command == SQLCOM_INSERT ||
+                Lex->sql_command == SQLCOM_REPLACE)
+            {
+              if (Lex->sql_command == SQLCOM_INSERT)
+                Lex->sql_command= SQLCOM_INSERT_SELECT;
+              else
+                Lex->sql_command= SQLCOM_REPLACE_SELECT;
+            }
+            Lex->insert_select_hack(first_select);
+            if (Lex->check_main_unit_semantics())
+              MYSQL_YYABORT;
+
           }
-          union_clause
-        | opt_with_clause SELECT_SYM create_select_part2 
-          create_select_part3_union_not_ready create_select_part4
+        | LEFT_PAREN_WITH with_clause query_expression_body ')'
           {
-            Select->set_with_clause($1);
+            SELECT_LEX *first_select= $3->first_select();
+            $3->set_with_clause($2);
+            $2->attach_to(first_select);
+
+            Lex->insert_select_hack(first_select);
+            if (Lex->check_main_unit_semantics())
+              MYSQL_YYABORT;
+
+            if (Lex->sql_command == SQLCOM_INSERT ||
+                Lex->sql_command == SQLCOM_REPLACE)
+            {
+              if (Lex->sql_command == SQLCOM_INSERT)
+                Lex->sql_command= SQLCOM_INSERT_SELECT;
+              else
+                Lex->sql_command= SQLCOM_REPLACE_SELECT;
+            }
           }
-        | '(' 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 {}
         ;
 
 opt_create_partitioning:
@@ -5126,8 +5352,13 @@ partition_entry:
               We enter here when opening the frm file to translate
               partition info string into part_info data structure.
             */
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
+          }
+          partition
+          {
+            Lex->pop_select(); //main select
           }
-          partition {}
         ;
 
 partition:
@@ -5742,56 +5973,6 @@ 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
-          {
-            Select->set_with_clause($1);
-          }
-        ;
-
-create_select_part2:
-          {
-            LEX *lex=Lex;
-            if (lex->sql_command == SQLCOM_INSERT)
-              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;
-          }
-          select_options select_item_list
-          {
-            Select->parsing_place= NO_MATTER;
-          }
-        ;
-
-create_select_part3:
-          opt_table_expression
-        | create_select_part3_union_not_ready
-        ;
-
-create_select_part3_union_not_ready:
-          table_expression order_or_limit
-        | order_or_limit
-        ;
-
-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 */ {}
         | AS {}
@@ -6195,6 +6376,13 @@ create_field_list:
         }
         ;
 
+create_field_list_parens:
+        LEFT_PAREN_ALT field_list ')'
+        {
+          Lex->create_last_non_select_table= Lex->last_table();
+        }
+        ;
+
 field_list:
           field_list_item
         | field_list ',' field_list_item
@@ -6462,6 +6650,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
           {
@@ -6469,13 +6659,29 @@ parse_vcol_expr:
             if (!v)
               MYSQL_YYABORT;
             Lex->last_field->vcol_info= v;
+            Lex->pop_select(); //main select
           }
         ;
 
 parenthesized_expr:
-          subselect
+          remember_tok_start
+          query_expression
           {
-            $$= new (thd->mem_root) Item_singlerow_subselect(thd, $1);
+            if (!Lex->expr_allows_subselect ||
+               Lex->sql_command == (int)SQLCOM_PURGE)
+            {
+              thd->parse_error(ER_SYNTAX_ERROR, $1);
+              MYSQL_YYABORT;
+            }
+
+            // Add the subtree of subquery to the current SELECT_LEX
+            SELECT_LEX *curr_sel= Lex->select_stack_head();
+            DBUG_ASSERT(Lex->current_select == curr_sel);
+            curr_sel->register_unit($2, &curr_sel->context);
+            curr_sel->add_statistics($2);
+
+            $$= new (thd->mem_root)
+              Item_singlerow_subselect(thd, $2->first_select());
             if ($$ == NULL)
               MYSQL_YYABORT;
           }
@@ -7474,6 +7680,8 @@ alter:
             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
@@ -7494,12 +7702,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
           {
@@ -7508,6 +7719,7 @@ alter:
             lex->name= $3;
             if (lex->name.str == NULL && lex->copy_db_to(&lex->name))
               MYSQL_YYABORT;
+            Lex->pop_select(); //main select
           }
         | ALTER DATABASE ident UPGRADE_SYM DATA_SYM DIRECTORY_SYM NAME_SYM
           {
@@ -7523,6 +7735,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
@@ -7531,6 +7745,9 @@ alter:
 
             lex->sql_command= SQLCOM_ALTER_PROCEDURE;
             lex->spname= $3;
+            Lex->pop_select(); //main select
+            if (Lex->check_main_unit_semantics())
+              MYSQL_YYABORT;
           }
         | ALTER FUNCTION_SYM sp_name
           {
@@ -7538,6 +7755,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
@@ -7546,14 +7765,23 @@ alter:
 
             lex->sql_command= SQLCOM_ALTER_FUNCTION;
             lex->spname= $3;
+            Lex->pop_select(); //main select
+            if (Lex->check_main_unit_semantics())
+              MYSQL_YYABORT;
           }
         | 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
+            if (Lex->check_main_unit_semantics())
+              MYSQL_YYABORT;
+          }
         | ALTER definer_opt opt_view_suid VIEW_SYM table_ident
           /*
             We have two separate rules for ALTER VIEW rather that
@@ -7561,14 +7789,22 @@ 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
+            if (Lex->check_main_unit_semantics())
+              MYSQL_YYABORT;
+          }
         | 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
@@ -7600,6 +7836,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
           {
@@ -7643,6 +7881,8 @@ 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
           {
@@ -7660,6 +7900,9 @@ alter:
             Lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_alter_sequence($3);
             if (Lex->m_sql_cmd == NULL)
               MYSQL_YYABORT;
+            Lex->pop_select(); //main select
+            if (Lex->check_main_unit_semantics())
+              MYSQL_YYABORT;
           }
         ;
 
@@ -8336,9 +8579,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:
@@ -8364,6 +8611,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
           {
@@ -8372,6 +8621,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
           }
         ;
 
@@ -8400,6 +8650,8 @@ analyze:
           ANALYZE_SYM opt_no_write_to_binlog table_or_tables
           {
             LEX *lex=Lex;
+            if (lex->main_select_push())
+              YYABORT;
             lex->sql_command = SQLCOM_ANALYZE;
             lex->no_write_to_binlog= $2;
             lex->check_opt.init();
@@ -8414,6 +8666,7 @@ analyze:
             lex->m_sql_cmd= new (thd->mem_root) Sql_cmd_analyze_table();
             if (lex->m_sql_cmd == NULL)
               MYSQL_YYABORT;
+            Lex->pop_select(); //main select
           }
         ;
 
@@ -8530,6 +8783,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
           {
@@ -8540,6 +8795,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
           }
         ;
 
@@ -8577,6 +8833,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
           {
@@ -8585,6 +8843,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
           }
         ;
 
@@ -8598,9 +8857,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;
@@ -8694,10 +8957,14 @@ 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:
           preload_keys_parts
@@ -8763,192 +9030,353 @@ opt_ignore_leaves:
 
 
 select:
-          opt_with_clause select_init
+          query_expression
           {
-            LEX *lex= Lex;
-            lex->sql_command= SQLCOM_SELECT;
-            lex->current_select->set_with_clause($1);
+            Lex->selects_allow_into= TRUE;
+            Lex->selects_allow_procedure= TRUE;
+            Lex->set_main_unit($1);
+            if (Lex->check_main_unit_semantics())
+              MYSQL_YYABORT;
+
+            SELECT_LEX *fake= Lex->unit.fake_select_lex;
+            if (fake)
+            {
+              fake->no_table_names_allowed= 1;
+              Lex->push_select(fake);
+            }
+            else
+              Lex->push_select(Lex->first_select_lex());
+            Lex->sql_command= SQLCOM_SELECT;
           }
         ;
 
-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
+simple_table:
+          query_specification      { $$= $1; }
+        | table_value_constructor  { $$= $1; }
         ;
-
-select_paren:
+        
+table_value_constructor:
+	  VALUES
+	  {
+	    LEX *lex= Lex;
+            SELECT_LEX *sel;
+            //lex->field_list.empty();
+            lex->many_values.empty();
+            lex->insert_list=0;
+            if (!(sel= lex->alloc_select(TRUE)) ||
+                  lex->push_select(sel))
+              MYSQL_YYABORT;
+            sel->init_select();
+            sel->braces= FALSE; // just initialisation
+	  }
+	  values_list
+	  {
+	    LEX *lex=Lex;
+            $$= lex->pop_select(); // above TVC select
+	    if (!($$->tvc=
+	          new (lex->thd->mem_root) table_value_constr(lex->many_values,
+                                                              $$,
+                                                              $$->options)))
+	      MYSQL_YYABORT;
+	    lex->many_values.empty();
+	  }
+	;
+	
+query_specification:
+          SELECT_SYM
           {
-            /*
-              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_LEX *sel;
+            LEX *lex= Lex;
+            if (!(sel= lex->alloc_select(TRUE)) ||
+                  lex->push_select(sel))
+              MYSQL_YYABORT;
+            sel->init_select();
+            sel->braces= FALSE;
           }
-          SELECT_SYM select_options_and_item_list select_part3
-          opt_select_lock_type
+          select_options
           {
-            DBUG_ASSERT(Lex->current_select->braces);
+            Select->parsing_place= SELECT_LIST;
           }
-        | '(' select_paren ')'
-        ;
-
-select_paren_union_query_term:
+          select_item_list
           {
-            /*
-              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->parsing_place= NO_MATTER;
           }
-          SELECT_SYM select_options_and_item_list select_part3_union_query_term
-          opt_select_lock_type
+          opt_into
+          opt_from_clause
+          opt_where_clause
+          opt_group_clause
+          opt_having_clause
+          opt_window_clause
           {
-            DBUG_ASSERT(Lex->current_select->braces);
+            $$= Lex->pop_select();
           }
-        | '(' 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 ')'
+opt_from_clause:
+        /* Empty */
+        | from_clause
+         ;
+ 
+query_primary:
+          simple_table
+          { $$= $1; }
+        | query_primary_parens
+          { $$= $1; }
         ;
 
-/* The equivalent of select_paren for nested queries. */
-select_paren_derived:
+query_primary_parens:
+          '(' query_expression_unit
           {
-            Lex->current_select->set_braces(true);
+            SELECT_LEX *last= $2->pre_last_parse->next_select();
+            int cmp= cmp_unit_op($2->first_select()->next_select()->linkage,
+                                last->linkage);
+            if (cmp < 0)
+            {
+              if (!check_intersect_prefix($2->first_select()))
+              {
+                if (Lex->pop_new_select_and_wrap() == NULL)
+                  MYSQL_YYABORT;
+              }
+            }
+            Lex->push_select($2->fake_select_lex);
           }
-          SELECT_SYM select_part2_derived
-          opt_table_expression
-          opt_order_clause
-          opt_limit_clause
-          opt_select_lock_type
+          query_expression_tail ')'
           {
-            DBUG_ASSERT(Lex->current_select->braces);
-            $$= Lex->current_select->master_unit()->first_select();
+            Lex->pop_select();
+            if ($4)
+            {
+              ($4)->set_to($2->fake_select_lex);
+            }
+            $$= $2->first_select();
           }
-        | '(' select_paren_derived ')'  { $$= $2; }
-        ;
-
-select_init3:
-          opt_table_expression
-          opt_select_lock_type
+        | '(' query_primary
           {
-            /* Parentheses carry no meaning here */
-            Lex->current_select->set_braces(false);
+            Lex->push_select($2);
           }
-          union_clause
-        | select_part3_union_not_ready
-          opt_select_lock_type
+          query_expression_tail ')'
           {
-            /* Parentheses carry no meaning here */
-            Lex->current_select->set_braces(false);
+            Lex->pop_select();
+            $$= $2;
+            $$->braces= TRUE;
+            if ($4)
+            {
+              if ($2->next_select())
+              {
+                SELECT_LEX_UNIT *unit= $2->master_unit();
+                if (!unit)
+                  unit= Lex->create_unit($2);
+                if (!unit)
+                  YYABORT;
+                if (!unit->fake_select_lex->is_set_query_expr_tail)
+                  $4->set_to(unit->fake_select_lex);
+                else
+                {
+                  $$= Lex->wrap_unit_into_derived(unit);
+                  if (!$$)
+                    YYABORT;
+                  $4->set_to($$);
+                }
+              }
+              else if (!$2->is_set_query_expr_tail)
+              {
+                $4->set_to($2);
+              }
+              else
+              {
+                SELECT_LEX_UNIT *unit= Lex->create_unit($2);
+                if (!unit)
+                  YYABORT;
+                $$= Lex->wrap_unit_into_derived(unit);
+                if (!$$)
+                  YYABORT;
+                $4->set_to($$);
+              }
+            }
           }
         ;
 
-
-select_init3_union_query_term:
-          opt_table_expression
-          opt_select_lock_type
+query_expression_unit:
+          query_primary
+          unit_type_decl
+          query_primary
           {
-            /* Parentheses carry no meaning here */
-            Lex->current_select->set_braces(false);
+            SELECT_LEX *sel1;
+            SELECT_LEX *sel2;
+            if (!$1->next_select())
+              sel1= $1;
+            else
+            {
+              sel1= Lex->wrap_unit_into_derived($1->master_unit());
+              if (!sel1)
+                YYABORT;
+            }
+            if (!$3->next_select())
+              sel2= $3;
+            else
+            {
+              sel2= Lex->wrap_unit_into_derived($3->master_unit());
+              if (!sel2)
+                YYABORT;
+            }
+            sel1->link_neighbour(sel2);
+            sel2->set_linkage_and_distinct($2.unit_type, $2.distinct);
+            $$= Lex->create_unit(sel1);
+            $$->pre_last_parse= sel1;
+            if ($$ == NULL)
+              YYABORT;
           }
-          union_clause
-        | select_part3_union_not_ready_noproc
-          opt_select_lock_type
+        | query_expression_unit
+          unit_type_decl
+          query_primary
           {
-            /* Parentheses carry no meaning here */
-            Lex->current_select->set_braces(false);
+            SELECT_LEX *sel1;
+            if (!$3->next_select())
+              sel1= $3;
+            else
+            {
+              sel1= Lex->wrap_unit_into_derived($3->master_unit());
+              if (!sel1)
+                YYABORT;
+            }
+            SELECT_LEX *last= $1->pre_last_parse->next_select();
+
+            int cmp= cmp_unit_op($2.unit_type, last->linkage);
+            if (cmp == 0)
+            {
+              // do nothing, this part will be just connected
+            }
+            else if (cmp > 0)
+            {
+              // Store beginning and continue to connect parts
+              if (Lex->push_new_select($1->pre_last_parse))
+                MYSQL_YYABORT;
+            }
+            else /* cmp < 0 */
+            {
+              // wrap stored part in a select, then continue to connect parts
+              if (!check_intersect_prefix($1->first_select()))
+              {
+                if ((last= Lex->pop_new_select_and_wrap()) == NULL)
+                  MYSQL_YYABORT;
+                last->set_master_unit($1);
+              }
+            }
+            last->link_neighbour(sel1);
+            sel1->set_master_unit($1);
+            sel1->set_linkage_and_distinct($2.unit_type, $2.distinct);
+            $$= $1;
+            $$->pre_last_parse= last;
           }
         ;
 
-
-select_init3_view:
-          opt_table_expression opt_select_lock_type
+query_expression_body:
+          query_primary
           {
-            Lex->current_select->set_braces(false);
+            Lex->push_select($1);
           }
-        | opt_table_expression opt_select_lock_type
+          query_expression_tail
           {
-            Lex->current_select->set_braces(false);
+            Lex->pop_select();
+            SELECT_LEX *sel= $1;
+            if ($3)
+            {
+              if ($1->next_select())
+              {
+                SELECT_LEX_UNIT *unit= $1->master_unit();
+                if (!unit)
+                  unit= Lex->create_unit($1);
+                if (!unit)
+                  YYABORT;
+                if (!unit->fake_select_lex->is_set_query_expr_tail)
+                  $3->set_to(unit->fake_select_lex);
+                else
+                {
+                  SELECT_LEX *sel= Lex->wrap_unit_into_derived(unit);
+                  if (!sel)
+                    YYABORT;
+                  $3->set_to(sel);
+                }
+              }
+              else if (!$1->is_set_query_expr_tail)
+                $3->set_to($1);
+              else
+              {
+                SELECT_LEX_UNIT *unit= $1->master_unit();
+                if (!unit)
+                  unit= Lex->create_unit($1);
+                if (!unit)
+                  YYABORT;
+                sel= Lex->wrap_unit_into_derived(unit);
+                if (!sel)
+                  YYABORT;
+                $3->set_to(sel);
+              }
+            }
+            $$= Lex->create_unit(sel);
+            if ($$ == NULL)
+              YYABORT;
           }
-          union_list_view
-        | order_or_limit opt_select_lock_type
+        | query_expression_unit
           {
-            Lex->current_select->set_braces(false);
+            SELECT_LEX *last= $1->pre_last_parse->next_select();
+            int cmp= cmp_unit_op($1->first_select()->next_select()->linkage,
+                                last->linkage);
+            if (cmp < 0)
+            {
+              if (!check_intersect_prefix($1->first_select()))
+              {
+                if (Lex->pop_new_select_and_wrap() == NULL)
+                  MYSQL_YYABORT;
+              }
+            }
+            Lex->push_select($1->fake_select_lex);
           }
-        | table_expression order_or_limit opt_select_lock_type
+          query_expression_tail
           {
-            Lex->current_select->set_braces(false);
+            Lex->pop_select();
+            if ($3)
+            {
+              ($3)->set_to($1->fake_select_lex);
+            }
+            $$= $1;
           }
         ;
 
-/*
-  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
-        ;
-
-select_part3_view:
-          opt_table_expression
-        | order_or_limit
-        | table_expression order_or_limit
+query_expression:
+          opt_with_clause
+          query_expression_body
+          {
+            if ($1)
+            {
+              $2->set_with_clause($1);
+              $1->attach_to($2->first_select());
+            }
+            $$= $2;
+          }
         ;
 
-select_part3_union_not_ready:
-          select_part3_union_not_ready_noproc
-        | table_expression procedure_clause
-        | table_expression order_or_limit procedure_clause
-        ;
+subselect:
+          remember_tok_start
+          query_expression
+          {
+            if (!Lex->expr_allows_subselect ||
+                Lex->sql_command == (int)SQLCOM_PURGE)
+            {
+              thd->parse_error(ER_SYNTAX_ERROR, $1);
+              MYSQL_YYABORT;
+            }
 
-select_part3_union_not_ready_noproc:
-          order_or_limit
-        | into opt_table_expression opt_order_clause opt_limit_clause
-        | table_expression into
-        | table_expression order_or_limit
-        | table_expression order_or_limit into
-        ;
+            // Add the subtree of subquery to the current SELECT_LEX
+            SELECT_LEX *curr_sel= Lex->select_stack_head();
+            DBUG_ASSERT(Lex->current_select == curr_sel);
+            if (curr_sel)
+            {
+              curr_sel->register_unit($2, &curr_sel->context);
+              curr_sel->add_statistics($2);
+            }
 
-select_options_and_item_list:
-          {
-            LEX *lex= Lex;
-            SELECT_LEX *sel= lex->current_select;
-            if (sel->linkage != UNION_TYPE)
-              mysql_init_select(lex);
-            lex->current_select->parsing_place= SELECT_LIST;
-          }
-          select_options select_item_list
-          {
-            Select->parsing_place= NO_MATTER;
+            $$= $2->first_select();
           }
         ;
 
@@ -8956,18 +9384,6 @@ select_options_and_item_list:
 /**
   <table expression>, as in the SQL standard.
 */
-table_expression:
-          from_clause
-          opt_where_clause
-          opt_group_clause
-          opt_having_clause
-          opt_window_clause
-        ;
-
-opt_table_expression:
-            /* Empty */
-          | table_expression
-        ;
 
 from_clause:
           FROM table_reference_list
@@ -9005,59 +9421,63 @@ select_option:
           query_expression_option
         | SQL_NO_CACHE_SYM
           {
-            /* 
-              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->builtin_select)
-              my_yyabort_error((ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_NO_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->builtin_select.sql_cache == SELECT_LEX::SQL_NO_CACHE)
+            /*
+              Allow this flag once per query.
+            */
+            if (Select->options & OPTION_NO_QUERY_CACHE)
               my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "SQL_NO_CACHE"));
-
-            Lex->safe_to_cache_query=0;
-            Lex->builtin_select.options&= ~OPTION_TO_QUERY_CACHE;
-            Lex->builtin_select.sql_cache= SELECT_LEX::SQL_NO_CACHE;
+            Select->options|= OPTION_NO_QUERY_CACHE;
           }
         | SQL_CACHE_SYM
           {
-            /* 
-              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->builtin_select)
-              my_yyabort_error((ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_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->builtin_select.sql_cache == SELECT_LEX::SQL_CACHE)
+            /*
+              Allow this flag once per query.
+            */
+            if (Select->options & OPTION_TO_QUERY_CACHE)
               my_yyabort_error((ER_DUP_ARGUMENT, MYF(0), "SQL_CACHE"));
-
-            Lex->safe_to_cache_query=1;
-            Lex->builtin_select.options|= OPTION_TO_QUERY_CACHE;
-            Lex->builtin_select.sql_cache= SELECT_LEX::SQL_CACHE;
+            Select->options|= OPTION_TO_QUERY_CACHE;
           }
         ;
 
 opt_select_lock_type:
           /* empty */
-        | FOR_SYM UPDATE_SYM opt_lock_wait_timeout
+          { $$.empty(); }
+        | select_lock_type
+          { $$= $1; }
+        ;
+
+select_lock_type:
+          FOR_SYM UPDATE_SYM opt_lock_wait_timeout_new
           {
-            LEX *lex=Lex;
-            lex->current_select->lock_type= TL_WRITE;
-            lex->current_select->set_lock_for_tables(TL_WRITE);
-            lex->safe_to_cache_query=0;
+            $$= $3;
+            $$.defined_lock= TRUE;
+            $$.update_lock= TRUE;
           }
-        | LOCK_SYM IN_SYM SHARE_SYM MODE_SYM opt_lock_wait_timeout
+        | LOCK_SYM IN_SYM SHARE_SYM MODE_SYM opt_lock_wait_timeout_new
           {
-            LEX *lex=Lex;
-            lex->current_select->lock_type= TL_READ_WITH_SHARED_LOCKS;
-            lex->current_select->
-              set_lock_for_tables(TL_READ_WITH_SHARED_LOCKS);
-            lex->safe_to_cache_query=0;
+            $$= $5;
+            $$.defined_lock= TRUE;
+            $$.update_lock= FALSE;
           }
         ;
 
+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
@@ -11361,10 +11781,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);
           }
         ;
 
@@ -11383,11 +11808,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;
@@ -11404,6 +11836,8 @@ join_table:
           USING
           {
             MYSQL_YYABORT_UNLESS($1 && $3);
+            Select->add_joined_table($1);
+            Select->add_joined_table($3);
           }
           '(' using_list ')'
           { 
@@ -11414,6 +11848,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);
           }
@@ -11423,6 +11859,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;
@@ -11439,6 +11877,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 ')'
           { 
@@ -11449,6 +11889,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;
@@ -11459,6 +11901,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;
@@ -11476,6 +11920,8 @@ join_table:
         | 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 ')'
           {
@@ -11487,6 +11933,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()))
@@ -11521,40 +11969,70 @@ use_partition:
             $$= $3;
           }
         ;
-  
-/* 
-   This is a flattening of the rules <table factor> and <table primary>
-   in the SQL:2003 standard, since we don't have <sample clause>
 
-   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_primary_ident { $$= $1; }
+        | table_primary_derived { $$= $1; }
+        | join_table_parens { $$= $1; }
+        | table_reference_list_parens { $$= $1; }
         ;
 
+table_reference_list_parens:
+          '(' table_reference_list_parens ')' { $$= $2; }
+        | '(' nested_table_reference_list ')'
+          {
+            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_clause opt_key_definition
           {
             SELECT_LEX *sel= Select;
             sel->table_join_options= 0;
-          }
-          table_ident opt_use_partition opt_table_alias opt_key_definition
-          {
-            if (!($$= Select->add_table_to_list(thd, $2, $4,
+            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
@@ -11572,242 +12050,56 @@ table_primary_ident:
 */
 
 table_primary_derived:
-          '(' get_select_lex select_derived_union ')' opt_table_alias
+          query_primary_parens table_alias_clause
           {
-            /* 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)
+            LEX *lex=Lex;
+            lex->derived_tables|= DERIVED_SUBQUERY;
+            $1->linkage= DERIVED_TABLE_TYPE;
+            $1->braces= FALSE;
+            // Add the subtree of subquery to the current SELECT_LEX
+            SELECT_LEX *curr_sel= Lex->select_stack_head();
+            DBUG_ASSERT(Lex->current_select == curr_sel);
+            SELECT_LEX_UNIT *unit= $1->master_unit();
+            if (!unit)
             {
-              /* 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;
+              unit= Lex->create_unit($1);
+              if (!unit)
+                YYABORT;
             }
-            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;
-              SELECT_LEX_UNIT *unit= sel->master_unit();
-              lex->current_select= sel= unit->outer_select();
-              Table_ident *ti= new (thd->mem_root) Table_ident(unit);
-              if (ti == NULL)
-                MYSQL_YYABORT;
-              if (!($$= sel->add_table_to_list(thd,
-                                               ti, $5, 0,
-                                               TL_READ, MDL_SHARED_READ)))
+            curr_sel->register_unit(unit, &curr_sel->context);
+            curr_sel->add_statistics(unit);
 
-                MYSQL_YYABORT;
-              sel->add_joined_table($$);
-              //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
-          {
-            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)
               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 (!($$= curr_sel->add_table_to_list(lex->thd,
+                                                  ti, $2, 0,
+                                                  TL_READ, MDL_SHARED_READ)))
               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
-  subselect_start. This forces bison to take a decision which rules to
-  reduce by long before it has seen any tokens. This approach ties us
-  to a very limited class of parseable languages, and unfortunately
-  SQL is not one of them. The chosen 'solution' was this rule, which
-  produces just about anything, even complete bogus statements, for
-  instance ( table UNION SELECT 1 ).
-  Fortunately, we know that the semantic value returned by
-  select_derived is NULL if it contained a derived table, and a pointer to
-  the base table's TABLE_LIST if it was a base table. So in the rule
-  regarding union's, we throw a parse error manually and pretend it
-  was bison that did it.
- 
-  Also worth noting is that this rule concerns query expressions in
-  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
-          {
-            if ($1)
-            {
-              thd->parse_error();
-              MYSQL_YYABORT;
-            }
-          }
-        | select_derived union_head_non_top
-          {
-            if ($1)
-            {
-              thd->parse_error();
-              MYSQL_YYABORT;
-            }
           }
-          union_list_derived_part2
-        | derived_query_specification opt_select_lock_type
-        | 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
-       ;
-
-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;
-            SELECT_LEX *sel= lex->current_select;
-            if (sel->linkage != UNION_TYPE)
-              mysql_init_select(lex);
-            lex->current_select->parsing_place= SELECT_LIST;
-          }
-          opt_query_expression_options select_item_list
-          {
-            Select->parsing_place= NO_MATTER;
-          }
-        ;
-
-/* handle contents of parentheses in join expression */
-select_derived:
-          get_select_lex_derived derived_table_list
+        | '('
+          query_expression
+          ')' table_alias_clause
           {
-            LEX *lex= Lex;
-            /* for normal joins, $2 != NULL and end_nested_join() != NULL,
-               for derived tables, both must equal NULL */
+            LEX *lex=Lex;
+            lex->derived_tables|= DERIVED_SUBQUERY;
+            $2->first_select()->linkage= DERIVED_TABLE_TYPE;
 
-            if (!($$= $1->end_nested_join(lex->thd)) && $2)
-              MYSQL_YYABORT;
-            if (!$2 && $$)
-            {
-              thd->parse_error();
-              MYSQL_YYABORT;
-            }
-          }
-        ;
 
-/*
-  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
-          {
-            if ($2)
-              Select->set_braces(1);
-            $$= NULL;
-          }
-        ;
+            // Add the subtree of subquery to the current SELECT_LEX
+            SELECT_LEX *curr_sel= Lex->select_stack_head();
+            DBUG_ASSERT(Lex->current_select == curr_sel);
+            curr_sel->register_unit($2, &curr_sel->context);
+            curr_sel->add_statistics($2);
 
-select_derived2:
-          {
-            LEX *lex= Lex;
-            lex->derived_tables|= DERIVED_SUBQUERY;
-            if (!lex->expr_allows_subselect ||
-                lex->sql_command == (int)SQLCOM_PURGE)
-            {
-              thd->parse_error();
-              MYSQL_YYABORT;
-            }
-            if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE ||
-                mysql_new_select(lex, 1, NULL))
+            Table_ident *ti= new (thd->mem_root) Table_ident($2);
+            if (ti == NULL)
               MYSQL_YYABORT;
-            mysql_init_select(lex);
-            lex->current_select->set_linkage(DERIVED_TABLE_TYPE);
-            lex->current_select->parsing_place= SELECT_LIST;
-          }
-          select_options select_item_list
-          {
-            Select->parsing_place= NO_MATTER;
-          }
-          opt_table_expression
-        ;
-
-get_select_lex:
-          /* Empty */ { $$= Select; }
-        ;
-
-get_select_lex_derived:
-          get_select_lex
-          {
-            LEX *lex= Lex;
-            if ($1->init_nested_join(lex->thd))
+            if (!($$= curr_sel->add_table_to_list(lex->thd,
+                                                  ti, $4, 0,
+                                                  TL_READ, MDL_SHARED_READ)))
               MYSQL_YYABORT;
           }
-       ;
-
-select_derived_init:
-          {
-            LEX *lex= Lex;
-
-            TABLE_LIST *embedding= lex->current_select->embedding;
-            $$= embedding &&
-                !embedding->nested_join->join_list.elements;
-            /* return true if we are deeply nested */
-          }
         ;
 
 opt_outer:
@@ -11939,9 +12231,14 @@ table_alias:
         | '='
         ;
 
-opt_table_alias:
+opt_table_alias_clause:
           /* empty */ { $$=0; }
-        | table_alias ident
+
+        | table_alias_clause { $$= $1; }
+        ;
+
+table_alias_clause:
+          table_alias ident
           {
             $$= (LEX_CSTRING*) thd->memdup(&$2,sizeof(LEX_STRING));
             if ($$ == NULL)
@@ -12108,7 +12405,7 @@ opt_window_partition_clause:
 
 opt_window_order_clause:
           /* empty */ { }
-        | ORDER_SYM BY order_list
+        | ORDER_SYM BY order_list { Select->order_list= *($3); } 
         ;
 
 opt_window_frame_clause:
@@ -12232,64 +12529,35 @@ alter_order_item:
 
 opt_order_clause:
           /* empty */
+          { $$= NULL; }
         | order_clause
+          { $$= $1; }
         ;
 
 order_clause:
           ORDER_SYM BY
           {
-            LEX *lex=Lex;
-            SELECT_LEX *sel= lex->current_select;
-            SELECT_LEX_UNIT *unit= sel-> master_unit();
-            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");
-              MYSQL_YYABORT;
-            }
-            if (lex->sql_command != SQLCOM_ALTER_TABLE &&
-                !unit->fake_select_lex)
-            {
-              /*
-                A query of the of the form (SELECT ...) ORDER BY order_list is
-                executed in the same way as the query
-                SELECT ... ORDER BY order_list
-                unless the SELECT construct contains ORDER BY or LIMIT clauses.
-                Otherwise we create a fake SELECT_LEX if it has not been created
-                yet.
-              */
-              SELECT_LEX *first_sl= unit->first_select();
-              if (!unit->is_unit_op() &&
-                  (first_sl->order_list.elements || 
-                   first_sl->select_limit) &&            
-                  unit->add_fake_select_lex(thd))
-                MYSQL_YYABORT;
-            }
-            if (sel->master_unit()->is_unit_op() && !sel->braces)
-            {
-               /*
-                 At this point we don't know yet whether this is the last
-                 select in union or not, but we move ORDER BY to
-                 fake_select_lex anyway. If there would be one more select
-                 in union mysql_new_select will correctly throw error.
-               */
-               DBUG_ASSERT(sel->master_unit()->fake_select_lex);
-               lex->current_select= sel->master_unit()->fake_select_lex;
-             }
+            thd->where= "ORDER clause";
           }
           order_list
           {
-
+            $$= $4;
           }
          ;
 
 order_list:
           order_list ',' order_ident order_dir
-          { if (add_order_to_list(thd, $3,(bool) $4)) MYSQL_YYABORT; }
+          {
+            $$= $1;
+            if (add_to_list(thd, *$$, $3,(bool) $4))
+              MYSQL_YYABORT;
+          }
         | order_ident order_dir
-          { if (add_order_to_list(thd, $1,(bool) $2)) MYSQL_YYABORT; }
+          {
+            $$= new (thd->mem_root) SQL_I_List<ORDER>();
+            if (add_to_list(thd, *$$, $1, (bool) $2))
+              MYSQL_YYABORT;
+          }
         ;
 
 order_dir:
@@ -12299,63 +12567,61 @@ order_dir:
         ;
 
 opt_limit_clause:
-          /* empty */ {}
-        | limit_clause {}
+          /* empty */
+          { $$.empty(); }
+        | limit_clause
+          { $$= $1; }
         ;
 
-limit_clause_init:
-          LIMIT
-          {
-            SELECT_LEX *sel= Select;
-            if (sel->master_unit()->is_unit_op() && !sel->braces)
-            {
-              /* Move LIMIT that belongs to UNION to fake_select_lex */
-              Lex->current_select= sel->master_unit()->fake_select_lex;
-              DBUG_ASSERT(Select);
-            }
-          }
-        ;  
-
 limit_clause:
-          limit_clause_init limit_options
+          LIMIT limit_options
           {
-            SELECT_LEX *sel= Select;
-            if (!sel->select_limit->basic_const_item() ||
-                sel->select_limit->val_int() > 0)
+            $$= $2;
+            if (!$$.select_limit->basic_const_item() ||
+                $$.select_limit->val_int() > 0)
               Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT);
           }
-        | limit_clause_init limit_options
+        | LIMIT limit_options
           ROWS_SYM EXAMINED_SYM limit_rows_option
           {
+            $$= $2;
             Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_LIMIT);
           }
-        | limit_clause_init ROWS_SYM EXAMINED_SYM limit_rows_option
+        | 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);
           }
         ;
 
+opt_global_limit_clause:
+          opt_limit_clause
+          {
+            Select->explicit_limit= $1.explicit_limit;
+            Select->select_limit= $1.select_limit;
+            Select->offset_limit= $1.offset_limit;
+          }
+
 limit_options:
           limit_option
           {
-            SELECT_LEX *sel= Select;
-            sel->select_limit= $1;
-            sel->offset_limit= 0;
-            sel->explicit_limit= 1;
+            $$.select_limit= $1;
+            $$.offset_limit= 0;
+            $$.explicit_limit= 1;
           }
         | limit_option ',' limit_option
           {
-            SELECT_LEX *sel= Select;
-            sel->select_limit= $3;
-            sel->offset_limit= $1;
-            sel->explicit_limit= 1;
+            $$.select_limit= $3;
+            $$.offset_limit= $1;
+            $$.explicit_limit= 1;
           }
         | limit_option OFFSET_SYM limit_option
           {
-            SELECT_LEX *sel= Select;
-            sel->select_limit= $1;
-            sel->offset_limit= $3;
-            sel->explicit_limit= 1;
+            $$.select_limit= $1;
+            $$.offset_limit= $3;
+            $$.explicit_limit= 1;
           }
         ;
 
@@ -12424,6 +12690,66 @@ delete_limit_clause:
        | LIMIT limit_option ROWS_SYM EXAMINED_SYM { thd->parse_error(); MYSQL_YYABORT; }
         ;
 
+query_expression_tail:
+          /* empty */ { $$= NULL; }
+        | order_or_limit opt_select_lock_type
+          {
+            $$= $1;
+            $$->lock= $2;
+          }
+        | order_or_limit procedure_or_into opt_select_lock_type
+          {
+            $$= $1;
+            $$->lock= $3;
+          }
+        | procedure_or_into opt_select_lock_type
+          {
+            $$= new(thd->mem_root) Lex_order_limit_lock;
+            if (!$$)
+              YYABORT;
+            $$->order_list= NULL;
+            $$->limit.empty();
+            $$->lock= $2;
+          }
+        | select_lock_type
+          {
+            $$= new(thd->mem_root) Lex_order_limit_lock;
+            if (!$$)
+              YYABORT;
+            $$->order_list= NULL;
+            $$->limit.empty();
+            $$->lock= $1;
+          }
+        ;
+
+procedure_or_into:
+          procedure_clause
+        | into
+        | procedure_clause into
+        ;
+
+order_or_limit:
+          order_clause opt_limit_clause
+          {
+            $$= new(thd->mem_root) Lex_order_limit_lock;
+            if (!$$)
+              YYABORT;
+            $$->order_list= $1;
+            $$->limit= $2;
+          }
+        | limit_clause
+          {
+            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;
+          }
+        ;
+
+
 opt_plus:
           /* empty */
         | '+'
@@ -12493,14 +12819,11 @@ bool:
         | TRUE_SYM  { $$= 1; }
         | FALSE_SYM { $$= 0; }
 
-
 procedure_clause:
           PROCEDURE_SYM ident /* Procedure name */
           {
             LEX *lex=Lex;
 
-            DBUG_ASSERT(&lex->builtin_select == lex->current_select);
-
             lex->proc_list.elements=0;
             lex->proc_list.first=0;
             lex->proc_list.next= &lex->proc_list.first;
@@ -12520,6 +12843,7 @@ procedure_clause:
               parameters are reduced.
             */
             Lex->expr_allows_subselect= false;
+            Select->options|= OPTION_PROCEDURE_CLAUSE;
           }
           '(' procedure_list ')'
           {
@@ -12600,8 +12924,21 @@ select_outvar:
           }
         ;
 
+opt_into:
+          /* empty */
+        | into
+        ;
 into:
           INTO into_destination
+          {
+            if (!(Select->options & OPTION_INTO_CLAUSE))
+              Select->options|= OPTION_INTO_CLAUSE;
+            else
+            {
+              my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "INTO");
+              MYSQL_YYABORT;
+            }
+          }
         ;
 
 into_destination:
@@ -12647,10 +12984,15 @@ 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
+            if (Lex->check_main_unit_semantics())
+              MYSQL_YYABORT;
           }
         ;
 
@@ -12882,17 +13224,24 @@ insert:
           {
             LEX *lex= Lex;
             lex->sql_command= SQLCOM_INSERT;
-            lex->duplicates= DUP_ERROR; 
-            mysql_init_select(lex);
+            lex->duplicates= DUP_ERROR;
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
+             mysql_init_select(lex);
+            lex->current_select->parsing_place= BEFORE_OPT_LIST;
           }
           insert_lock_option
           opt_ignore insert2
           {
             Select->set_lock_for_tables($3);
-            Lex->current_select= &Lex->builtin_select;
+            Lex->current_select= Lex->first_select_lex();
           }
           insert_field_spec opt_insert_update
-          {}
+          {
+            Lex->pop_select(); //main select
+            if (Lex->check_main_unit_semantics())
+              MYSQL_YYABORT;
+          }
         ;
 
 replace:
@@ -12901,15 +13250,22 @@ replace:
             LEX *lex=Lex;
             lex->sql_command = SQLCOM_REPLACE;
             lex->duplicates= DUP_REPLACE;
-            mysql_init_select(lex);
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
+             mysql_init_select(lex);
+            lex->current_select->parsing_place= BEFORE_OPT_LIST;
           }
           replace_lock_option insert2
           {
             Select->set_lock_for_tables($3);
-            Lex->current_select= &Lex->builtin_select;
+            Lex->current_select= Lex->first_select_lex();
           }
           insert_field_spec
-          {}
+          {
+            Lex->pop_select(); //main select
+            if (Lex->check_main_unit_semantics())
+              MYSQL_YYABORT;
+          }
         ;
 
 insert_lock_option:
@@ -12955,35 +13311,47 @@ insert_table:
           table_name_with_opt_use_partition
           {
             LEX *lex=Lex;
-            lex->field_list.empty();
+            //lex->field_list.empty();
             lex->many_values.empty();
             lex->insert_list=0;
           };
 
 insert_field_spec:
           insert_values {}
-        | '(' ')' insert_values {}
-        | '(' fields ')' insert_values {}
+        | insert_field_list insert_values {}
         | SET
           {
             LEX *lex=Lex;
             if (!(lex->insert_list= new (thd->mem_root) List_item) ||
                 lex->many_values.push_back(lex->insert_list, thd->mem_root))
               MYSQL_YYABORT;
+            lex->current_select->parsing_place= NO_MATTER;
           }
           ident_eq_list
         ;
 
+insert_field_list:
+          LEFT_PAREN_ALT opt_fields ')'
+          {
+            Lex->current_select->parsing_place= AFTER_LIST;
+          }
+        ;
+
+opt_fields:
+          /* empty */
+        | fields
+        ;
+
 fields:
           fields ',' insert_ident
           { Lex->field_list.push_back($3, thd->mem_root); }
         | insert_ident { Lex->field_list.push_back($1, thd->mem_root); }
         ;
 
+
+
 insert_values:
-          VALUES values_list {}
-        | VALUE_SYM values_list {}
-        | create_select_query_expression {}
+         create_select_query_expression {}
         ;
 
 values_list:
@@ -13093,6 +13461,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; 
@@ -13118,7 +13488,14 @@ 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
+          {
+            if ($10)
+              Select->order_list= *($10);
+            Lex->pop_select(); //main select
+            if (Lex->check_main_unit_semantics())
+              MYSQL_YYABORT;
+          }
         ;
 
 update_list:
@@ -13164,6 +13541,8 @@ 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->builtin_select.init_order();
@@ -13185,7 +13564,12 @@ single_multi:
           }
           opt_where_clause opt_order_clause
           delete_limit_clause {}
-          opt_select_expressions {}
+          opt_select_expressions
+          {
+            if ($6)
+              Select->order_list= *($6);
+            Lex->pop_select(); //main select
+          }
         | table_wild_list
           {
             mysql_init_multi_delete(Lex);
@@ -13196,6 +13580,9 @@ single_multi:
           {
             if (multi_delete_set_locks_and_link_aux_tables(Lex))
               MYSQL_YYABORT;
+            Lex->pop_select(); //main select
+            if (Lex->check_main_unit_semantics())
+              MYSQL_YYABORT;
           }
         | FROM table_alias_ref_list
           {
@@ -13207,6 +13594,9 @@ single_multi:
           {
             if (multi_delete_set_locks_and_link_aux_tables(Lex))
               MYSQL_YYABORT;
+            Lex->pop_select(); //main select
+            if (Lex->check_main_unit_semantics())
+              MYSQL_YYABORT;
           }
         ;
 
@@ -13284,6 +13674,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
           }
           opt_truncate_table_storage_clause { }
         ;
@@ -13365,6 +13756,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();
@@ -13372,6 +13765,7 @@ show:
           show_param
           {
             Select->parsing_place= NO_MATTER;
+            Lex->pop_select(); //main select
           }
         ;
 
@@ -13387,7 +13781,7 @@ show_param:
            {
              LEX *lex= Lex;
              lex->sql_command= SQLCOM_SHOW_TABLES;
-             lex->builtin_select.db= $3;
+             lex->first_select_lex()->db= $3;
              if (prepare_schema_table(thd, lex, 0, SCH_TABLE_NAMES))
                MYSQL_YYABORT;
            }
@@ -13395,7 +13789,7 @@ show_param:
            {
              LEX *lex= Lex;
              lex->sql_command= SQLCOM_SHOW_TRIGGERS;
-             lex->builtin_select.db= $3;
+             lex->first_select_lex()->db= $3;
              if (prepare_schema_table(thd, lex, 0, SCH_TRIGGERS))
                MYSQL_YYABORT;
            }
@@ -13403,7 +13797,7 @@ show_param:
            {
              LEX *lex= Lex;
              lex->sql_command= SQLCOM_SHOW_EVENTS;
-             lex->builtin_select.db= $2;
+             lex->first_select_lex()->db= $2;
              if (prepare_schema_table(thd, lex, 0, SCH_EVENTS))
                MYSQL_YYABORT;
            }
@@ -13411,7 +13805,7 @@ show_param:
            {
              LEX *lex= Lex;
              lex->sql_command= SQLCOM_SHOW_TABLE_STATUS;
-             lex->builtin_select.db= $3;
+             lex->first_select_lex()->db= $3;
              if (prepare_schema_table(thd, lex, 0, SCH_TABLES))
                MYSQL_YYABORT;
            }
@@ -13419,7 +13813,7 @@ show_param:
           {
             LEX *lex= Lex;
             lex->sql_command= SQLCOM_SHOW_OPEN_TABLES;
-            lex->builtin_select.db= $3;
+            lex->first_select_lex()->db= $3;
             if (prepare_schema_table(thd, lex, 0, SCH_OPEN_TABLES))
               MYSQL_YYABORT;
           }
@@ -13469,12 +13863,13 @@ show_param:
             LEX *lex= Lex;
             lex->sql_command= SQLCOM_SHOW_BINLOG_EVENTS;
           }
-          opt_limit_clause
+          opt_global_limit_clause
         | RELAYLOG_SYM optional_connection_name EVENTS_SYM binlog_in binlog_from
           {
             LEX *lex= Lex;
             lex->sql_command= SQLCOM_SHOW_RELAYLOG_EVENTS;
-          } opt_limit_clause
+          }
+          opt_global_limit_clause
         | keys_or_index from_or_in table_ident opt_db opt_where_clause
           {
             LEX *lex= Lex;
@@ -13516,13 +13911,13 @@ show_param:
             LEX_CSTRING var= {STRING_WITH_LEN("error_count")};
             (void) create_select_for_variable(thd, &var);
           }
-        | WARNINGS opt_limit_clause
+        | WARNINGS opt_global_limit_clause
           { Lex->sql_command = SQLCOM_SHOW_WARNS;}
-        | ERRORS opt_limit_clause
+        | ERRORS opt_global_limit_clause
           { Lex->sql_command = SQLCOM_SHOW_ERRORS;}
         | PROFILES_SYM
           { Lex->sql_command = SQLCOM_SHOW_PROFILES; }
-        | PROFILE_SYM opt_profile_defs opt_profile_args opt_limit_clause
+        | PROFILE_SYM opt_profile_defs opt_profile_args opt_global_limit_clause
           { 
             LEX *lex= Lex;
             lex->sql_command= SQLCOM_SHOW_PROFILE;
@@ -13829,7 +14224,7 @@ describe:
           explainable_command
           {
             LEX *lex=Lex;
-            lex->builtin_select.options|= SELECT_DESCRIBE;
+            lex->first_select_lex()->options|= SELECT_DESCRIBE;
           }
         ;
 
@@ -13855,6 +14250,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 {}
         ;
@@ -13897,8 +14294,7 @@ flush:
             lex->type= 0;
             lex->no_write_to_binlog= $2;
           }
-          flush_options
-          {}
+          flush_options {}
         ;
 
 flush_options:
@@ -13915,6 +14311,7 @@ flush_options:
           opt_table_list opt_flush_lock
           {}
         | flush_options_list
+          {}
         ;
 
 opt_flush_lock:
@@ -14070,9 +14467,13 @@ purge:
             LEX *lex=Lex;
             lex->type=0;
             lex->sql_command = SQLCOM_PURGE;
+            if (lex->main_select_push())
+              MYSQL_YYABORT;
           }
           purge_options
-          {}
+          {
+            Lex->pop_select(); //main select
+          }
         ;
 
 purge_options:
@@ -14090,6 +14491,8 @@ purge_option:
             lex->value_list.empty();
             lex->value_list.push_front($2, thd->mem_root);
             lex->sql_command= SQLCOM_PURGE_BEFORE;
+            if (Lex->check_main_unit_semantics())
+              MYSQL_YYABORT;
           }
         ;
 
@@ -14099,6 +14502,8 @@ kill:
           KILL_SYM
           {
             LEX *lex=Lex;
+            if (lex->main_select_push())
+              YYABORT;
             lex->value_list.empty();
             lex->users_list.empty();
             lex->sql_command= SQLCOM_KILL;
@@ -14107,6 +14512,7 @@ kill:
           kill_type kill_option kill_expr
           {
             Lex->kill_signal= (killed_state) ($3 | $4);
+            Lex->pop_select(); //main select
           }
         ;
 
@@ -14167,6 +14573,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
           {
@@ -14193,7 +14601,11 @@ 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
+            if (Lex->check_main_unit_semantics())
+              MYSQL_YYABORT;
+          }
           ;
 
 data_or_xml:
@@ -14597,17 +15009,21 @@ opt_with_clause:
 
 
 with_clause:
-        WITH opt_recursive
+          WITH opt_recursive
           {
+             LEX *lex= Lex;
              With_clause *with_clause=
              new With_clause($2, Lex->curr_with_clause);
              if (with_clause == NULL)
                MYSQL_YYABORT;
-             Lex->derived_tables|= DERIVED_WITH;
-             Lex->curr_with_clause= with_clause;
+             lex->derived_tables|= DERIVED_WITH;
+             lex->curr_with_clause= with_clause;
              with_clause->add_to_list(Lex->with_clauses_list_last_next);
+             if (lex->current_select &&
+                 lex->current_select->parsing_place == BEFORE_OPT_LIST)
+               lex->current_select->parsing_place= NO_MATTER;
           }
-        with_list
+          with_list
           {
             $$= Lex->curr_with_clause;
             Lex->curr_with_clause= Lex->curr_with_clause->pop();
@@ -14636,9 +15052,9 @@ with_list_element:
               MYSQL_YYABORT;
             Lex->with_column_list.empty();
           }
-          AS '(' remember_name subselect remember_end ')'
+          AS '(' remember_name query_expression remember_end ')'
  	  {
-            With_element *elem= new With_element($1, *$2, $7->master_unit());
+            With_element *elem= new With_element($1, *$2, $7);
 	    if (elem == NULL || Lex->curr_with_clause->add_with_element(elem))
 	      MYSQL_YYABORT;
 	    if (elem->set_unparsed_spec(thd, $6+1, $8))
@@ -15589,14 +16005,22 @@ 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
+            if (Lex->check_main_unit_semantics())
+              MYSQL_YYABORT;
+          }
         | SET STATEMENT_SYM
           {
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
             Lex->set_stmt_init();
           }
           set_stmt_option_value_following_option_type_list
@@ -15606,6 +16030,9 @@ 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
+            if (Lex->check_main_unit_semantics())
+              MYSQL_YYABORT;
           }
           FOR_SYM verb_clause
 	  {}
@@ -16038,9 +16465,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:
@@ -16071,7 +16502,7 @@ table_lock_list:
         ;
 
 table_lock:
-          table_ident opt_table_alias lock_option
+          table_ident opt_table_alias_clause lock_option
           {
             thr_lock_type lock_type= (thr_lock_type) $3;
             bool lock_for_write= (lock_type >= TL_WRITE_ALLOW_WRITE);
@@ -16105,9 +16536,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
+          }
         ;
 
 /*
@@ -16115,25 +16550,36 @@ unlock:
 */
 
 handler:
-          HANDLER_SYM table_ident OPEN_SYM opt_table_alias
+          HANDLER_SYM
+          {
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
+          }
+          handler_tail
+          {
+            Lex->pop_select(); //main select
+          }
+
+handler_tail:
+          table_ident OPEN_SYM opt_table_alias_clause
           {
             LEX *lex= Lex;
             if (lex->sphead)
               my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "HANDLER"));
             lex->sql_command = SQLCOM_HA_OPEN;
-            if (!lex->current_select->add_table_to_list(thd, $2, $4, 0))
+            if (!lex->current_select->add_table_to_list(thd, $1, $3, 0))
               MYSQL_YYABORT;
           }
-        | HANDLER_SYM table_ident_nodb CLOSE_SYM
+        | table_ident_nodb CLOSE_SYM
           {
             LEX *lex= Lex;
             if (lex->sphead)
               my_yyabort_error((ER_SP_BADSTATEMENT, MYF(0), "HANDLER"));
             lex->sql_command = SQLCOM_HA_CLOSE;
-            if (!lex->current_select->add_table_to_list(thd, $2, 0, 0))
+            if (!lex->current_select->add_table_to_list(thd, $1, 0, 0))
               MYSQL_YYABORT;
           }
-        | HANDLER_SYM table_ident_nodb READ_SYM
+        | table_ident_nodb READ_SYM
           {
             LEX *lex=Lex;
             if (lex->sphead)
@@ -16141,20 +16587,24 @@ handler:
             lex->expr_allows_subselect= FALSE;
             lex->sql_command = SQLCOM_HA_READ;
             lex->ha_rkey_mode= HA_READ_KEY_EXACT; /* Avoid purify warnings */
-            Item *one= new (thd->mem_root) Item_int(thd, (int32) 1);
-            if (one == NULL)
-              MYSQL_YYABORT;
-            lex->current_select->select_limit= one;
-            lex->current_select->offset_limit= 0;
-            lex->limit_rows_examined= 0;
-            if (!lex->current_select->add_table_to_list(thd, $2, 0, 0))
+            if (!lex->current_select->add_table_to_list(thd, $1, 0, 0))
               MYSQL_YYABORT;
           }
-          handler_read_or_scan opt_where_clause opt_limit_clause
+          handler_read_or_scan opt_where_clause opt_global_limit_clause
           {
-            Lex->expr_allows_subselect= TRUE;
+            LEX *lex=Lex;
+            lex->expr_allows_subselect= TRUE;
+            if (!lex->current_select->explicit_limit)
+            {
+              Item *one= new (thd->mem_root) Item_int(thd, (int32) 1);
+              if (one == NULL)
+                MYSQL_YYABORT;
+              lex->current_select->select_limit= one;
+              lex->current_select->offset_limit= 0;
+              lex->limit_rows_examined= 0;
+            }
             /* Stored functions are not supported for HANDLER READ. */
-            if (Lex->uses_stored_routines())
+            if (lex->uses_stored_routines())
             {
               my_error(ER_NOT_SUPPORTED_YET, MYF(0),
                        "stored functions in HANDLER ... READ");
@@ -16800,83 +17250,16 @@ 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; }
-
-
-union_clause:
-          /* empty */ {}
-        | union_list
-        ;
-
-union_list:
-          unit_type_decl union_option
-          {
-            if (Lex->add_select_to_union_list((bool)$2, $1, 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();
-          }
-        ;
-
-union_list_view:
-          unit_type_decl union_option
-          {
-            if (Lex->add_select_to_union_list((bool)$2, $1, TRUE))
-              MYSQL_YYABORT;
-          }
-          query_expression_body_view
-          {
-            Lex->pop_context();
-          }
-        ;
-
-union_order_or_limit:
-          {
-            LEX *lex= thd->lex;
-            DBUG_ASSERT(lex->current_select->linkage != GLOBAL_OPTIONS_TYPE);
-            SELECT_LEX *sel= lex->current_select;
-            SELECT_LEX_UNIT *unit= sel->master_unit();
-            SELECT_LEX *fake= unit->fake_select_lex;
-            if (fake)
-            {
-              fake->no_table_names_allowed= 1;
-              lex->current_select= fake;
-            }
-            thd->where= "global ORDER clause";
-          }
-          order_or_limit
-          {
-            thd->lex->current_select->no_table_names_allowed= 0;
-            thd->where= "";
-          }
-        ;
-
-order_or_limit:
-          order_clause opt_limit_clause
-        | limit_clause
-        ;
+          { $$.unit_type= EXCEPT_TYPE; $$.distinct= 1; }
 
 /*
   Start a UNION, for non-top level query expressions.
 */
-union_head_non_top:
-          unit_type_decl union_option
-          {
-            if (Lex->add_select_to_union_list((bool)$2, $1, FALSE))
-              MYSQL_YYABORT;
-          }
-        ;
 
 union_option:
           /* empty */ { $$=1; }
@@ -16884,110 +17267,10 @@ union_option:
         | ALL       { $$=0; }
         ;
 
-/*
-  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
-        ;
-
-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
           {
-            if (check_simple_select())
-              MYSQL_YYABORT;
             YYPS->m_lock_type= TL_READ_HIGH_PRIORITY;
             YYPS->m_mdl_type= MDL_SHARED_READ;
             Select->options|= SELECT_HIGH_PRIORITY;
@@ -16996,18 +17279,8 @@ query_expression_option:
         | UNIQUE_SYM       { Select->options|= SELECT_DISTINCT; }
         | SQL_SMALL_RESULT { Select->options|= SELECT_SMALL_RESULT; }
         | SQL_BIG_RESULT   { Select->options|= SELECT_BIG_RESULT; }
-        | SQL_BUFFER_RESULT
-          {
-            if (check_simple_select())
-              MYSQL_YYABORT;
-            Select->options|= OPTION_BUFFER_RESULT;
-          }
-        | SQL_CALC_FOUND_ROWS
-          {
-            if (check_simple_select())
-              MYSQL_YYABORT;
-            Select->options|= OPTION_FOUND_ROWS;
-          }
+        | SQL_BUFFER_RESULT { Select->options|= OPTION_BUFFER_RESULT; }
+        | SQL_CALC_FOUND_ROWS { Select->options|= OPTION_FOUND_ROWS; }
         | ALL { Select->options|= SELECT_ALL; }
         ;
 
@@ -17095,32 +17368,28 @@ view_select:
             lex->parsing_options.allows_variable= FALSE;
             lex->create_view->select.str= (char *) YYLIP->get_cpp_ptr();
           }
-          opt_with_clause query_expression_body_view view_check_option
+          query_expression
+          view_check_option
           {
             LEX *lex= Lex;
+            SQL_I_List<TABLE_LIST> *save= &lex->first_select_lex()->table_list;
+            lex->set_main_unit($2);
+            if (lex->check_main_unit_semantics())
+              MYSQL_YYABORT;
+            lex->first_select_lex()->table_list.push_front(save);
+            lex->current_select= Lex->first_select_lex();
             size_t len= YYLIP->get_cpp_ptr() - lex->create_view->select.str;
             void *create_view_select= thd->memdup(lex->create_view->select.str, len);
             lex->create_view->select.length= len;
             lex->create_view->select.str= (char *) create_view_select;
+            size_t not_used;
             trim_whitespace(thd->charset(),
-                            &lex->create_view->select);
-            lex->create_view->check= $4;
+                            &lex->create_view->select, &not_used);
+            lex->create_view->check= $3;
             lex->parsing_options.allows_variable= TRUE;
-            lex->current_select->set_with_clause($2);
           }
         ;
 
-/*
-  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; }


More information about the commits mailing list