← Back to team overview

maria-developers team mailing list archive

Re: Fwd: [Commits] b32031991e4: initial oracle parser fix

 

  Hello Sanja,


I reviewed your recent changes in "10.3-MDEV-11953"
(and the attached additional patch for sql_yacc_ora.yy)

I have some proposals:



1. Can you please move huge pieces of the code from sql_yacc.yy to LEX
or other relevant classes?

It makes the grammar much more readable (patches are aslo much more
readable).

I'd move the relevant pieces of the code to LEX as a separate patch,
even before fixing the grammar.


2. You're adding too many main_select_push() and pop_select().
Please move them to upper level rules (it should be possible in many cases).

Add new helper rules when needed.
For example, this piece of code repeats many times:

+          {
+            if (Lex->main_select_push())
+              MYSQL_YYABORT;
+          }
+          expr
+          {
+            Lex->pop_select(); //main select
+            $$= $3;

It deserved a rule, say, expr_with_select_push_pop.
You can find a better name :)


- Serg and I spent a lot of time working on this task:
  MDEV-8909 union parser cleanup
  (and its 13 dependency tasks, and 3 related tasks,
   see the "Issue links" section in MDEV).

We think that it should be the parser who disallows bad grammar, instead
of post-analysis with raising errors like
ER_CANT_USE_OPTION_HERE.
Please keep using the same approach.

Thanks!


On 04/06/2018 07:37 PM, Oleksandr Byelkin wrote:
> 
> 
> 
> -------- Weitergeleitete Nachricht --------
> Betreff:     [Commits] b32031991e4: initial oracle parser fix
> Datum:     Fri, 06 Apr 2018 17:34:31 +0200
> Von:     Oleksandr Byelkin <sanja@xxxxxxxxxxx>
> Antwort an:     maria-developers@xxxxxxxxxxxxxxxxxxx
> An:     commits@xxxxxxxxxxx
> 
> 
> 
> 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; }
> _______________________________________________
> commits mailing list
> commits@xxxxxxxxxxx
> https://lists.askmonty.org/cgi-bin/mailman/listinfo/commits
> 


Follow ups