diff options
Diffstat (limited to 'sql')
47 files changed, 4006 insertions, 2419 deletions
diff --git a/sql/events.cc b/sql/events.cc index 2fbb16861f6..7568d03c0e0 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -826,12 +826,13 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */) */ if (thd->lex->sql_command == SQLCOM_SHOW_EVENTS) { - DBUG_ASSERT(thd->lex->select_lex.db.str); - if (!is_infoschema_db(&thd->lex->select_lex.db) && // There is no events in I_S - check_access(thd, EVENT_ACL, thd->lex->select_lex.db.str, + DBUG_ASSERT(thd->lex->first_select_lex()->db.str); + if (!is_infoschema_db(&thd->lex->first_select_lex()->db) && // There is no events in I_S + check_access(thd, EVENT_ACL, thd->lex->first_select_lex()->db.str, NULL, NULL, 0, 0)) DBUG_RETURN(1); - db= normalize_db_name(thd->lex->select_lex.db.str, db_tmp, sizeof(db_tmp)); + db= normalize_db_name(thd->lex->first_select_lex()->db.str, + db_tmp, sizeof(db_tmp)); } ret= db_repository->fill_schema_events(thd, tables, db); diff --git a/sql/item.cc b/sql/item.cc index dd12d9a476f..b5acebedf7f 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -734,7 +734,8 @@ Item_ident::Item_ident(THD *thd, TABLE_LIST *view_arg, :Item_result_field(thd), orig_db_name(NullS), orig_table_name(view_arg->table_name.str), orig_field_name(*field_name_arg), - context(&view_arg->view->select_lex.context), + /* TODO: suspicious use of first_select_lex */ + context(&view_arg->view->first_select_lex()->context), db_name(NullS), table_name(view_arg->alias.str), field_name(*field_name_arg), alias_name_used(FALSE), cached_field_index(NO_CACHED_FIELD_INDEX), @@ -3077,7 +3078,10 @@ Item_field::Item_field(THD *thd, Field *f) have_privileges(0), any_privileges(0) { set_field(f); - + /* + field_name and table_name should not point to garbage + if this item is to be reused + */ orig_table_name= table_name; orig_field_name= field_name; with_field= 1; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 6378e9b76bf..5a447cef23a 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -123,14 +123,7 @@ void Item_subselect::init(st_select_lex *select_lex, else engine= new subselect_single_select_engine(select_lex, result, this); } - { - SELECT_LEX *upper= unit->outer_select(); - if (upper->parsing_place == IN_HAVING) - upper->subquery_in_having= 1; - /* The subquery is an expression cache candidate */ - upper->expr_cache_may_be_used[upper->parsing_place]= TRUE; - } - DBUG_PRINT("info", ("engine: %p", engine)); + DBUG_PRINT("info", ("engine: 0x%lx", (ulong)engine)); DBUG_VOID_RETURN; } @@ -219,7 +212,8 @@ Item_subselect::~Item_subselect() if (own_engine) delete engine; else - engine->cleanup(); + if (engine) // can be empty in case of EOM + engine->cleanup(); engine= NULL; DBUG_VOID_RETURN; } @@ -243,6 +237,14 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref) DBUG_ASSERT(unit->thd == thd); + { + SELECT_LEX *upper= unit->outer_select(); + if (upper->parsing_place == IN_HAVING) + upper->subquery_in_having= 1; + /* The subquery is an expression cache candidate */ + upper->expr_cache_may_be_used[upper->parsing_place]= TRUE; + } + status_var_increment(thd_param->status_var.feature_subquery); DBUG_ASSERT(fixed == 0); diff --git a/sql/log_event.cc b/sql/log_event.cc index cd47cbba9bd..2e342936893 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -4389,7 +4389,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, size_t que have to use the transactional cache to ensure we don't calculate any checksum for the CREATE part. */ - trx_cache= (lex->select_lex.item_list.elements && + trx_cache= (lex->first_select_lex()->item_list.elements && thd->is_current_stmt_binlog_format_row()) || (thd->variables.option_bits & OPTION_GTID_BEGIN); use_cache= (lex->tmp_table() && @@ -7339,8 +7339,9 @@ int Load_log_event::do_apply_event(NET* net, rpl_group_info *rgi, ex.skip_lines = skip_lines; List<Item> field_list; - thd->lex->select_lex.context.resolve_in_table_list_only(&tables); - set_fields(tables.db.str, field_list, &thd->lex->select_lex.context); + thd->lex->first_select_lex()->context.resolve_in_table_list_only(&tables); + set_fields(tables.db.str, + field_list, &thd->lex->first_select_lex()->context); thd->variables.pseudo_thread_id= thread_id; if (net) { diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 38dbed92a22..39c36cdd529 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -4543,7 +4543,7 @@ double get_sweep_read_cost(const PARAM *param, ha_rows records) if (max_cost != DBL_MAX && (busy_blocks+index_reads_cost) >= n_blocks) return 1; */ - JOIN *join= param->thd->lex->select_lex.join; + JOIN *join= param->thd->lex->first_select_lex()->join; if (!join || join->table_count == 1) { /* No join, assume reading is done in one 'sweep' */ diff --git a/sql/opt_table_elimination.cc b/sql/opt_table_elimination.cc index ef9b07cca47..95743ecaad4 100644 --- a/sql/opt_table_elimination.cc +++ b/sql/opt_table_elimination.cc @@ -617,7 +617,7 @@ void eliminate_tables(JOIN *join) we should also take into account tables mentioned in "val". */ if (join->thd->lex->sql_command == SQLCOM_INSERT_SELECT && - join->select_lex == &thd->lex->select_lex) + join->select_lex == thd->lex->first_select_lex()) { List_iterator<Item> val_it(thd->lex->value_list); while ((item= val_it++)) @@ -640,7 +640,7 @@ void eliminate_tables(JOIN *join) used_tables |= (*(cur_list->item))->used_tables(); } - if (join->select_lex == &thd->lex->select_lex) + if (join->select_lex == thd->lex->first_select_lex()) { /* Multi-table UPDATE: don't eliminate tables referred from SET statement */ diff --git a/sql/set_var.cc b/sql/set_var.cc index bf373dde905..0923682a486 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -730,7 +730,7 @@ int sql_set_variables(THD *thd, List<set_var_base> *var_list, bool free) err: if (free) - free_underlaid_joins(thd, &thd->lex->select_lex); + free_underlaid_joins(thd, thd->lex->first_select_lex()); DBUG_RETURN(error); } diff --git a/sql/sp_head.cc b/sql/sp_head.cc index f7847bae89d..7129f362fd2 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -317,7 +317,7 @@ sp_get_flags_for_command(LEX *lex) - EXPLAIN DELETE ... - ANALYZE DELETE ... */ - if (lex->select_lex.item_list.is_empty() && + if (lex->first_select_lex()->item_list.is_empty() && !lex->describe && !lex->analyze_stmt) flags= 0; else @@ -556,6 +556,7 @@ sp_head::sp_head(sp_package *parent, const Sp_handler *sph) m_backpatch_goto.empty(); m_cont_backpatch.empty(); m_lex.empty(); + m_stmt_lex.empty(); my_init_dynamic_array(&m_instr, sizeof(sp_instr *), 16, 8, MYF(0)); my_hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0); my_hash_init(&m_sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key, @@ -830,13 +831,15 @@ sp_head::~sp_head() THD::lex. It is safe to not update LEX::ptr because further query string parsing and execution will be stopped anyway. */ + DBUG_ASSERT(m_lex.elements == m_stmt_lex.elements); while ((lex= (LEX *)m_lex.pop())) { THD *thd= lex->thd; thd->lex->sphead= NULL; lex_end(thd->lex); delete thd->lex; - thd->lex= thd->stmt_lex= lex; + thd->lex= lex; + thd->stmt_lex= m_stmt_lex.pop(); } my_hash_free(&m_sptabs); @@ -2285,6 +2288,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) if (!err_status) { err_status= execute(thd, TRUE); + DBUG_PRINT("info", ("execute returned %d", (int) err_status)); } if (save_log_general) @@ -2386,10 +2390,11 @@ sp_head::reset_lex(THD *thd, sp_lex_local *sublex) { DBUG_ENTER("sp_head::reset_lex"); LEX *oldlex= thd->lex; + LEX *oldstmtlex= thd->stmt_lex; - thd->set_local_lex(sublex); + thd->set_local_lex(sublex, sublex); - DBUG_RETURN(m_lex.push_front(oldlex)); + DBUG_RETURN(m_lex.push_front(oldlex) || m_stmt_lex.push_front(oldstmtlex)); } diff --git a/sql/sp_head.h b/sql/sp_head.h index f588f79b599..f28e1919959 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -589,10 +589,12 @@ public: { DBUG_ENTER("sp_head::restore_lex"); LEX *oldlex= (LEX *) m_lex.pop(); + LEX *oldstmtlex= (LEX *) m_stmt_lex.pop(); if (!oldlex) DBUG_RETURN(false); // Nothing to restore LEX *sublex= thd->lex; - if (thd->restore_from_local_lex_to_old_lex(oldlex))// This restores thd->lex + // This restores thd->lex and thd->stmt_lex + if (thd->restore_from_local_lex_to_old_lex(oldlex, oldstmtlex)) DBUG_RETURN(true); if (!sublex->sp_lex_in_use) { @@ -858,6 +860,7 @@ protected: sp_pcontext *m_pcont; ///< Parse context List<LEX> m_lex; ///< Temp. store for the other lex + List<LEX> m_stmt_lex; ///< Temp. store for the other stmt_lex DYNAMIC_ARRAY m_instr; ///< The "instructions" enum backpatch_instr_type { GOTO, CPOP, HPOP }; diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index 2e9ae23d7f9..19b23cd59ee 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -227,9 +227,10 @@ bool Qualified_column_ident::resolve_type_ref(THD *thd, Column_definition *def) // Make %TYPE variables see temporary tables that shadow permanent tables thd->temporary_tables= open_tables_state_backup.temporary_tables; - if ((table_list= lex.select_lex.add_table_to_list(thd, this, NULL, 0, - TL_READ_NO_INSERT, - MDL_SHARED_READ)) && + if ((table_list= + lex.first_select_lex()->add_table_to_list(thd, this, NULL, 0, + TL_READ_NO_INSERT, + MDL_SHARED_READ)) && !check_table_access(thd, SELECT_ACL, table_list, TRUE, UINT_MAX, FALSE) && !open_tables_only_view_structure(thd, table_list, thd->mdl_context.has_locks())) @@ -285,9 +286,10 @@ bool Table_ident::resolve_table_rowtype_ref(THD *thd, // Make %ROWTYPE variables see temporary tables that shadow permanent tables thd->temporary_tables= open_tables_state_backup.temporary_tables; - if ((table_list= lex.select_lex.add_table_to_list(thd, this, NULL, 0, - TL_READ_NO_INSERT, - MDL_SHARED_READ)) && + if ((table_list= + lex.first_select_lex()->add_table_to_list(thd, this, NULL, 0, + TL_READ_NO_INSERT, + MDL_SHARED_READ)) && !check_table_access(thd, SELECT_ACL, table_list, TRUE, UINT_MAX, FALSE) && !open_tables_only_view_structure(thd, table_list, thd->mdl_context.has_locks())) diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index 82fc1cbfff7..610b1a9ffed 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -306,7 +306,7 @@ static bool open_only_one_table(THD* thd, TABLE_LIST* table, bool is_view_operator_func) { LEX *lex= thd->lex; - SELECT_LEX *select= &lex->select_lex; + SELECT_LEX *select= lex->first_select_lex(); TABLE_LIST *save_next_global, *save_next_local; bool open_error; save_next_global= table->next_global; @@ -1295,7 +1295,7 @@ bool mysql_preload_keys(THD* thd, TABLE_LIST* tables) bool Sql_cmd_analyze_table::execute(THD *thd) { LEX *m_lex= thd->lex; - TABLE_LIST *first_table= m_lex->select_lex.table_list.first; + TABLE_LIST *first_table= m_lex->first_select_lex()->table_list.first; bool res= TRUE; thr_lock_type lock_type = TL_READ_NO_INSERT; DBUG_ENTER("Sql_cmd_analyze_table::execute"); @@ -1315,7 +1315,7 @@ bool Sql_cmd_analyze_table::execute(THD *thd) */ res= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } - m_lex->select_lex.table_list.first= first_table; + m_lex->first_select_lex()->table_list.first= first_table; m_lex->query_tables= first_table; error: @@ -1326,7 +1326,7 @@ error: bool Sql_cmd_check_table::execute(THD *thd) { LEX *m_lex= thd->lex; - TABLE_LIST *first_table= m_lex->select_lex.table_list.first; + TABLE_LIST *first_table= m_lex->first_select_lex()->table_list.first; thr_lock_type lock_type = TL_READ_NO_INSERT; bool res= TRUE; DBUG_ENTER("Sql_cmd_check_table::execute"); @@ -1339,7 +1339,7 @@ bool Sql_cmd_check_table::execute(THD *thd) lock_type, 0, 0, HA_OPEN_FOR_REPAIR, 0, &handler::ha_check, &view_check); - m_lex->select_lex.table_list.first= first_table; + m_lex->first_select_lex()->table_list.first= first_table; m_lex->query_tables= first_table; error: @@ -1350,7 +1350,7 @@ error: bool Sql_cmd_optimize_table::execute(THD *thd) { LEX *m_lex= thd->lex; - TABLE_LIST *first_table= m_lex->select_lex.table_list.first; + TABLE_LIST *first_table= m_lex->first_select_lex()->table_list.first; bool res= TRUE; DBUG_ENTER("Sql_cmd_optimize_table::execute"); @@ -1372,7 +1372,7 @@ bool Sql_cmd_optimize_table::execute(THD *thd) */ res= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } - m_lex->select_lex.table_list.first= first_table; + m_lex->first_select_lex()->table_list.first= first_table; m_lex->query_tables= first_table; error: @@ -1383,7 +1383,7 @@ error: bool Sql_cmd_repair_table::execute(THD *thd) { LEX *m_lex= thd->lex; - TABLE_LIST *first_table= m_lex->select_lex.table_list.first; + TABLE_LIST *first_table= m_lex->first_select_lex()->table_list.first; bool res= TRUE; DBUG_ENTER("Sql_cmd_repair_table::execute"); @@ -1407,7 +1407,7 @@ bool Sql_cmd_repair_table::execute(THD *thd) */ res= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } - m_lex->select_lex.table_list.first= first_table; + m_lex->first_select_lex()->table_list.first= first_table; m_lex->query_tables= first_table; error: diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc index 77e0c9d5298..e4c84c1c3cb 100644 --- a/sql/sql_alter.cc +++ b/sql/sql_alter.cc @@ -201,7 +201,7 @@ bool Sql_cmd_alter_table::execute(THD *thd) { LEX *lex= thd->lex; /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */ - SELECT_LEX *select_lex= &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); /* first table of first SELECT_LEX */ TABLE_LIST *first_table= (TABLE_LIST*) select_lex->table_list.first; /* @@ -345,7 +345,7 @@ error: bool Sql_cmd_discard_import_tablespace::execute(THD *thd) { /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */ - SELECT_LEX *select_lex= &thd->lex->select_lex; + SELECT_LEX *select_lex= thd->lex->first_select_lex(); /* first table of first SELECT_LEX */ TABLE_LIST *table_list= (TABLE_LIST*) select_lex->table_list.first; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 3354a2fdf1b..f26407eacff 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7435,7 +7435,7 @@ bool setup_tables(THD *thd, Name_resolution_context *context, TABLE_LIST *first_select_table= (select_insert ? tables->next_local: 0); - SELECT_LEX *select_lex= select_insert ? &thd->lex->select_lex : + SELECT_LEX *select_lex= select_insert ? thd->lex->first_select_lex() : thd->lex->current_select; if (select_lex->first_cond_optimization) { @@ -7463,7 +7463,7 @@ bool setup_tables(THD *thd, Name_resolution_context *context, { /* new counting for SELECT of INSERT ... SELECT command */ first_select_table= 0; - thd->lex->select_lex.insert_tables= tablenr; + thd->lex->first_select_lex()->insert_tables= tablenr; tablenr= 0; } if(table_list->jtbm_subselect) @@ -8017,7 +8017,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, List<TABLE_LIST> &leaves, from subquery of VIEW, because tables of subquery belongs to VIEW (see condition before prepare_check_option() call) */ - bool it_is_update= (select_lex == &thd->lex->select_lex) && + bool it_is_update= (select_lex == thd->lex->first_select_lex()) && thd->lex->which_check_option_applicable(); bool save_is_item_list_lookup= select_lex->is_item_list_lookup; TABLE_LIST *derived= select_lex->master_unit()->derived; @@ -8033,7 +8033,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, List<TABLE_LIST> &leaves, for (table= tables; table; table= table->next_local) { - if (select_lex == &thd->lex->select_lex && + if (select_lex == thd->lex->first_select_lex() && select_lex->first_cond_optimization && table->merged_for_insert && table->prepare_where(thd, conds, FALSE)) diff --git a/sql/sql_base.h b/sql/sql_base.h index a6a85d47dc9..6cbf6005f04 100644 --- a/sql/sql_base.h +++ b/sql/sql_base.h @@ -358,10 +358,12 @@ inline bool setup_fields_with_no_wrap(THD *thd, Ref_ptr_array ref_pointer_array, bool allow_sum_func) { bool res; - thd->lex->select_lex.no_wrap_view_item= TRUE; + SELECT_LEX *first= thd->lex->first_select_lex(); + DBUG_ASSERT(thd->lex->current_select == first); + first->no_wrap_view_item= TRUE; res= setup_fields(thd, ref_pointer_array, item, column_usage, sum_func_list, NULL, allow_sum_func); - thd->lex->select_lex.no_wrap_view_item= FALSE; + first->no_wrap_view_item= FALSE; return res; } diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index c8f18556d50..9aee9e14870 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -4130,13 +4130,13 @@ Query_cache::is_cacheable(THD *thd, LEX *lex, if (thd->lex->safe_to_cache_query && (thd->variables.query_cache_type == 1 || - (thd->variables.query_cache_type == 2 && (lex->select_lex.options & - OPTION_TO_QUERY_CACHE))) && + (thd->variables.query_cache_type == 2 && + (lex->first_select_lex()->options & OPTION_TO_QUERY_CACHE))) && qc_is_able_to_intercept_result(thd)) { DBUG_PRINT("qcache", ("options: %lx %lx type: %u", (long) OPTION_TO_QUERY_CACHE, - (long) lex->select_lex.options, + (long) lex->first_select_lex()->options, (int) thd->variables.query_cache_type)); if (!(table_count= process_and_count_tables(thd, tables_used, @@ -4157,7 +4157,7 @@ Query_cache::is_cacheable(THD *thd, LEX *lex, ("not interesting query: %d or not cacheable, options %lx %lx type: %u net->vio present: %u", (int) lex->sql_command, (long) OPTION_TO_QUERY_CACHE, - (long) lex->select_lex.options, + (long) lex->first_select_lex()->options, (int) thd->variables.query_cache_type, (uint) MY_TEST(qc_is_able_to_intercept_result(thd)))); DBUG_RETURN(0); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 7b7d34c6bc0..8f1deee3821 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1374,12 +1374,13 @@ void THD::init(bool skip_lock) } -bool THD::restore_from_local_lex_to_old_lex(LEX *oldlex) +bool THD::restore_from_local_lex_to_old_lex(LEX *oldlex, LEX *oldstmtlex) { DBUG_ASSERT(lex->sphead); if (lex->sphead->merge_lex(this, oldlex, lex)) return true; lex= oldlex; + stmt_lex= oldstmtlex; return false; } @@ -3798,6 +3799,7 @@ Statement::Statement(LEX *lex_arg, MEM_ROOT *mem_root_arg, id(id_arg), column_usage(MARK_COLUMNS_READ), lex(lex_arg), + stmt_lex(lex_arg), db(null_clex_str) { name= null_clex_str; diff --git a/sql/sql_class.h b/sql/sql_class.h index a7c33cbc504..b6476963727 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -4547,6 +4547,7 @@ public: TMP_TABLE_SHARE* save_tmp_table_share(TABLE *table); void restore_tmp_table_share(TMP_TABLE_SHARE *share); + bool inline is_main_lex(LEX *lex) { return lex == &main_lex; } private: /* Whether a lock has been acquired? */ bool m_tmp_tables_locked; @@ -4724,7 +4725,7 @@ public: /** Switch to a sublex, to parse a substatement or an expression. */ - void set_local_lex(sp_lex_local *sublex) + void set_local_lex(sp_lex_local *sublex, LEX *stmtlex) { DBUG_ASSERT(lex->sphead); lex= stmt_lex= sublex; @@ -4743,7 +4744,7 @@ public: See also sp_head::merge_lex(). */ - bool restore_from_local_lex_to_old_lex(LEX *oldlex); + bool restore_from_local_lex_to_old_lex(LEX *oldlex, LEX *oldstmtlex); Item *sp_fix_func_item(Item **it_addr); Item *sp_prepare_func_item(Item **it_addr, uint cols= 1); @@ -6134,7 +6135,8 @@ public: inline bool add_item_to_list(THD *thd, Item *item) { - return thd->lex->current_select->add_item_to_list(thd, item); + bool res= thd->lex->current_select->add_item_to_list(thd, item); + return res; } inline bool add_value_to_list(THD *thd, Item *value) diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc index a58a9254a82..4a2ff42733e 100644 --- a/sql/sql_cte.cc +++ b/sql/sql_cte.cc @@ -55,6 +55,14 @@ bool With_clause::add_with_element(With_element *elem) } +void st_select_lex_unit::set_with_clause(With_clause *with_cl) +{ + with_clause= with_cl; + if (with_clause) + with_clause->set_owner(this); +} + + /** @brief Check dependencies between tables defined in a list of with clauses @@ -683,7 +691,7 @@ void With_element::move_anchors_ahead() st_select_lex *next_sl; st_select_lex *new_pos= spec->first_select(); st_select_lex *UNINIT_VAR(last_sl); - new_pos->linkage= UNION_TYPE; + new_pos->set_linkage(UNION_TYPE); for (st_select_lex *sl= new_pos; sl; sl= next_sl) { next_sl= sl->next_select(); @@ -829,9 +837,8 @@ st_select_lex_unit *With_element::clone_parsed_spec(THD *thd, if (parser_state.init(thd, (char*) unparsed_spec.str, (unsigned int)unparsed_spec.length)) goto err; lex_start(thd); - with_select= &lex->select_lex; - with_select->select_number= ++thd->stmt_lex->current_select_number; parse_status= parse_sql(thd, &parser_state, 0); + with_select= lex->first_select_lex(); if (parse_status) goto err; @@ -982,7 +989,7 @@ bool With_element::prepare_unreferenced(THD *thd) rename_columns_of_derived_unit(thd, spec) || check_duplicate_names(thd, first_sl->item_list, 1))) rc= true; - + thd->lex->context_analysis_only&= ~CONTEXT_ANALYSIS_ONLY_DERIVED; return rc; } @@ -1094,6 +1101,7 @@ bool TABLE_LIST::set_as_with_table(THD *thd, With_element *with_elem) return true; } derived->first_select()->linkage= DERIVED_TABLE_TYPE; + select_lex->add_statistics(derived); with_elem->inc_references(); return false; } diff --git a/sql/sql_cte.h b/sql/sql_cte.h index 16b473f0665..4a194b2a38f 100644 --- a/sql/sql_cte.h +++ b/sql/sql_cte.h @@ -279,8 +279,7 @@ private: */ With_clause *next_with_clause; /* Set to true if dependencies between with elements have been checked */ - bool dependencies_are_checked; - + bool dependencies_are_checked; /* The bitmap of all recursive with elements whose specifications are not complied with restrictions imposed by the SQL standards @@ -304,9 +303,8 @@ public: bool with_recursive; With_clause(bool recursive_fl, With_clause *emb_with_clause) - : owner(NULL), - embedding_with_clause(emb_with_clause), next_with_clause(NULL), - dependencies_are_checked(false), unrestricted(0), + : owner(NULL), embedding_with_clause(emb_with_clause), + next_with_clause(NULL), dependencies_are_checked(false), unrestricted(0), with_prepared_anchor(0), cleaned(0), stabilized(0), with_recursive(recursive_fl) { } @@ -320,8 +318,12 @@ public: last_next= &this->next_with_clause; } + st_select_lex_unit *get_owner() { return owner; } + void set_owner(st_select_lex_unit *unit) { owner= unit; } + void attach_to(st_select_lex *select_lex); + With_clause *pop() { return embedding_with_clause; } bool check_dependencies(); @@ -354,7 +356,6 @@ bool With_element::is_unrestricted() } inline - bool With_element::is_with_prepared_anchor() { return owner->with_prepared_anchor & get_elem_map(); @@ -436,11 +437,14 @@ void With_element::prepare_for_next_iteration() inline -void st_select_lex_unit::set_with_clause(With_clause *with_cl) -{ - with_clause= with_cl; - if (with_clause) - with_clause->set_owner(this); +void With_clause::attach_to(st_select_lex *select_lex) +{ + for (With_element *with_elem= with_list.first; + with_elem; + with_elem= with_elem->next) + { + select_lex->register_unit(with_elem->spec, NULL); + } } diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 0a12d01596b..4a8f4e71d1d 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -285,7 +285,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, bool has_triggers; ORDER *order= (ORDER *) ((order_list && order_list->elements) ? order_list->first : NULL); - SELECT_LEX *select_lex= &thd->lex->select_lex; + SELECT_LEX *select_lex= thd->lex->first_select_lex(); killed_state killed_status= NOT_KILLED; THD::enum_binlog_query_type query_type= THD::ROW_QUERY_TYPE; bool binlog_is_row; @@ -350,7 +350,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, DBUG_RETURN(TRUE); } table->map=1; - query_plan.select_lex= &thd->lex->select_lex; + query_plan.select_lex= thd->lex->first_select_lex(); query_plan.table= table; query_plan.updating_a_view= MY_TEST(table_list->view); @@ -382,7 +382,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, setup_order(thd, select_lex->ref_pointer_array, &tables, fields, all_fields, order)) { - free_underlaid_joins(thd, &thd->lex->select_lex); + free_underlaid_joins(thd, thd->lex->first_select_lex()); DBUG_RETURN(TRUE); } } @@ -926,14 +926,16 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, bool *delete_while_scanning) { Item *fake_conds= 0; - SELECT_LEX *select_lex= &thd->lex->select_lex; + SELECT_LEX *select_lex= thd->lex->first_select_lex(); DBUG_ENTER("mysql_prepare_delete"); List<Item> all_fields; *delete_while_scanning= true; thd->lex->allow_sum_func= 0; - if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context, - &thd->lex->select_lex.top_join_list, + if (setup_tables_and_check_access(thd, + &thd->lex->first_select_lex()->context, + &thd->lex->first_select_lex()-> + top_join_list, table_list, select_lex->leaf_tables, FALSE, DELETE_ACL, SELECT_ACL, TRUE)) @@ -1015,21 +1017,23 @@ int mysql_multi_delete_prepare(THD *thd) lex->query_tables also point on local list of DELETE SELECT_LEX */ - if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context, - &thd->lex->select_lex.top_join_list, + if (setup_tables_and_check_access(thd, + &thd->lex->first_select_lex()->context, + &thd->lex->first_select_lex()-> + top_join_list, lex->query_tables, - lex->select_lex.leaf_tables, FALSE, - DELETE_ACL, SELECT_ACL, FALSE)) + lex->first_select_lex()->leaf_tables, + FALSE, DELETE_ACL, SELECT_ACL, FALSE)) DBUG_RETURN(TRUE); - if (lex->select_lex.handle_derived(thd->lex, DT_MERGE)) + if (lex->first_select_lex()->handle_derived(thd->lex, DT_MERGE)) DBUG_RETURN(TRUE); /* Multi-delete can't be constructed over-union => we always have single SELECT on top and have to check underlying SELECTs of it */ - lex->select_lex.exclude_from_table_unique_test= TRUE; + lex->first_select_lex()->exclude_from_table_unique_test= TRUE; /* Fix tables-to-be-deleted-from list to point at opened tables */ for (target_tbl= (TABLE_LIST*) aux_tables; target_tbl; @@ -1071,8 +1075,8 @@ int mysql_multi_delete_prepare(THD *thd) Reset the exclude flag to false so it doesn't interfare with further calls to unique_table */ - lex->select_lex.exclude_from_table_unique_test= FALSE; - + lex->first_select_lex()->exclude_from_table_unique_test= FALSE; + if (lex->save_prep_leaf_tables()) DBUG_RETURN(TRUE); diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index ab66384c6cb..26b1fca473a 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -99,7 +99,8 @@ mysql_handle_derived(LEX *lex, uint phases) processed normally. */ if (phases == DT_MERGE_FOR_INSERT && - cursor && cursor->top_table()->select_lex != &lex->select_lex) + cursor && (cursor->top_table()->select_lex != + lex->first_select_lex())) continue; for (; cursor && !res; diff --git a/sql/sql_do.cc b/sql/sql_do.cc index 20a7aa75590..72acbd763e1 100644 --- a/sql/sql_do.cc +++ b/sql/sql_do.cc @@ -33,7 +33,7 @@ bool mysql_do(THD *thd, List<Item> &values) DBUG_RETURN(TRUE); while ((value = li++)) (void) value->is_null(); - free_underlaid_joins(thd, &thd->lex->select_lex); + free_underlaid_joins(thd, thd->lex->first_select_lex()); if (thd->is_error()) { diff --git a/sql/sql_error.cc b/sql/sql_error.cc index 67440aeed33..160bf7469c5 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -781,7 +781,7 @@ bool mysqld_show_warnings(THD *thd, ulong levels_to_show) List<Item> field_list; MEM_ROOT *mem_root= thd->mem_root; const Sql_condition *err; - SELECT_LEX *sel= &thd->lex->select_lex; + SELECT_LEX *sel= thd->lex->first_select_lex(); SELECT_LEX_UNIT *unit= &thd->lex->unit; ulonglong idx= 0; Protocol *protocol=thd->protocol; diff --git a/sql/sql_help.cc b/sql/sql_help.cc index da38a2caf94..866bf86c733 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -87,7 +87,7 @@ enum enum_used_fields static bool init_fields(THD *thd, TABLE_LIST *tables, struct st_find_field *find_fields, uint count) { - Name_resolution_context *context= &thd->lex->select_lex.context; + Name_resolution_context *context= &thd->lex->first_select_lex()->context; DBUG_ENTER("init_fields"); context->resolve_in_table_list_only(tables); for (; count-- ; find_fields++) @@ -719,10 +719,11 @@ static bool mysqld_help_internal(THD *thd, const char *mask) Init tables and fields to be usable from items tables do not contain VIEWs => we can pass 0 as conds */ - thd->lex->select_lex.context.table_list= - thd->lex->select_lex.context.first_name_resolution_table= &tables[0]; - if (setup_tables(thd, &thd->lex->select_lex.context, - &thd->lex->select_lex.top_join_list, + thd->lex->first_select_lex()->context.table_list= + thd->lex->first_select_lex()->context.first_name_resolution_table= + &tables[0]; + if (setup_tables(thd, &thd->lex->first_select_lex()->context, + &thd->lex->first_select_lex()->top_join_list, tables, leaves, FALSE, FALSE)) goto error; memcpy((char*) used_fields, (char*) init_used_fields, sizeof(used_fields)); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 392aa52825e..aa51af80407 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -241,7 +241,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, } else { // Part field list - SELECT_LEX *select_lex= &thd->lex->select_lex; + SELECT_LEX *select_lex= thd->lex->first_select_lex(); Name_resolution_context *context= &select_lex->context; Name_resolution_context_state ctx_state; int res; @@ -273,7 +273,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, /* Restore the current context. */ ctx_state.restore_state(context, table_list); - thd->lex->select_lex.no_wrap_view_item= FALSE; + thd->lex->first_select_lex()->no_wrap_view_item= FALSE; if (res) DBUG_RETURN(-1); @@ -657,7 +657,7 @@ static void save_insert_query_plan(THD* thd, TABLE_LIST *table_list) bool skip= MY_TEST(table_list->view); /* Save subquery children */ - for (SELECT_LEX_UNIT *unit= thd->lex->select_lex.first_inner_unit(); + for (SELECT_LEX_UNIT *unit= thd->lex->first_select_lex()->first_inner_unit(); unit; unit= unit->next_unit()) { @@ -783,7 +783,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, /* mysql_prepare_insert sets table_list->table if it was not set */ table= table_list->table; - context= &thd->lex->select_lex.context; + context= &thd->lex->first_select_lex()->context; /* These three asserts test the hypothesis that the resetting of the name resolution context below is not necessary at all since the list of local @@ -1073,7 +1073,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, } while (bulk_parameters_iterations(thd)); values_loop_end: - free_underlaid_joins(thd, &thd->lex->select_lex); + free_underlaid_joins(thd, thd->lex->first_select_lex()); joins_freed= TRUE; /* @@ -1261,7 +1261,7 @@ abort: table->file->ha_release_auto_increment(); if (!joins_freed) - free_underlaid_joins(thd, &thd->lex->select_lex); + free_underlaid_joins(thd, thd->lex->first_select_lex()); thd->abort_on_warning= 0; DBUG_RETURN(retval); } @@ -1291,7 +1291,7 @@ abort: static bool check_view_insertability(THD * thd, TABLE_LIST *view) { - uint num= view->view->select_lex.item_list.elements; + uint num= view->view->first_select_lex()->item_list.elements; TABLE *table= view->table; Field_translator *trans_start= view->field_translation, *trans_end= trans_start + num; @@ -1391,10 +1391,12 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, than INSERT. */ - if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context, - &thd->lex->select_lex.top_join_list, + if (setup_tables_and_check_access(thd, + &thd->lex->first_select_lex()->context, + &thd->lex->first_select_lex()-> + top_join_list, table_list, - thd->lex->select_lex.leaf_tables, + thd->lex->first_select_lex()->leaf_tables, select_insert, INSERT_ACL, SELECT_ACL, TRUE)) DBUG_RETURN(TRUE); @@ -1402,7 +1404,7 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, if (insert_into_view && !fields.elements) { thd->lex->empty_field_list_on_rset= 1; - if (!thd->lex->select_lex.leaf_tables.head()->table || + if (!thd->lex->first_select_lex()->leaf_tables.head()->table || table_list->is_multitable()) { my_error(ER_VIEW_NO_INSERT_FIELD_LIST, MYF(0), @@ -1476,7 +1478,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, enum_duplicates duplic, COND **where, bool select_insert) { - SELECT_LEX *select_lex= &thd->lex->select_lex; + SELECT_LEX *select_lex= thd->lex->first_select_lex(); Name_resolution_context *context= &select_lex->context; Name_resolution_context_state ctx_state; bool insert_into_view= (table_list->view != 0); @@ -3530,7 +3532,7 @@ bool Delayed_insert::handle_inserts(void) bool mysql_insert_select_prepare(THD *thd) { LEX *lex= thd->lex; - SELECT_LEX *select_lex= &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); DBUG_ENTER("mysql_insert_select_prepare"); @@ -3619,7 +3621,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) select, LEX::current_select should point to the first select while we are fixing fields from insert list. */ - lex->current_select= &lex->select_lex; + lex->current_select= lex->first_select_lex(); res= (setup_fields(thd, Ref_ptr_array(), values, MARK_COLUMNS_READ, 0, NULL, 0) || @@ -3636,7 +3638,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) if (info.handle_duplicates == DUP_UPDATE && !res) { - Name_resolution_context *context= &lex->select_lex.context; + Name_resolution_context *context= &lex->first_select_lex()->context; Name_resolution_context_state ctx_state; /* Save the state of the current name resolution context. */ @@ -3646,7 +3648,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) table_list->next_local= 0; context->resolve_in_table_list_only(table_list); - lex->select_lex.no_wrap_view_item= TRUE; + lex->first_select_lex()->no_wrap_view_item= TRUE; res= res || check_update_fields(thd, context->table_list, *info.update_fields, *info.update_values, @@ -3657,15 +3659,15 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) */ true, &map); - lex->select_lex.no_wrap_view_item= FALSE; + lex->first_select_lex()->no_wrap_view_item= FALSE; /* When we are not using GROUP BY and there are no ungrouped aggregate functions we can refer to other tables in the ON DUPLICATE KEY part. We use next_name_resolution_table descructively, so check it first (views?) */ DBUG_ASSERT (!table_list->next_name_resolution_table); - if (lex->select_lex.group_list.elements == 0 && - !lex->select_lex.with_sum_func) + if (lex->first_select_lex()->group_list.elements == 0 && + !lex->first_select_lex()->with_sum_func) /* We must make a single context out of the two separate name resolution contexts : the INSERT table and the tables in the SELECT part of INSERT ... SELECT. diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 19e5acfa64c..92b5b6b5a21 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -176,7 +176,7 @@ init_lex_with_single_table(THD *thd, TABLE *table, LEX *lex) { TABLE_LIST *table_list; Table_ident *table_ident; - SELECT_LEX *select_lex= &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); Name_resolution_context *context= &select_lex->context; /* We will call the parser to create a part_info struct based on the @@ -673,20 +673,26 @@ void LEX::start(THD *thd_arg) this, thd_arg->lex, thd_arg->stmt_lex)); thd= unit.thd= thd_arg; - + DBUG_PRINT("info", ("Lex %p stmt_lex: %p", thd->lex, thd->stmt_lex)); + DBUG_ASSERT(!explain); context_stack.empty(); + //empty select_stack + select_stack_top= 0; unit.init_query(); - current_select_number= 1; - select_lex.linkage= UNSPECIFIED_TYPE; + current_select_number= 0; + builtin_select.linkage= UNSPECIFIED_TYPE; + builtin_select.set_linkage(UNSPECIFIED_TYPE); + builtin_select.distinct= TRUE; /* 'parent_lex' is used in init_query() so it must be before it. */ - select_lex.parent_lex= this; - select_lex.init_query(); + builtin_select.parent_lex= this; + builtin_select.init_query(); curr_with_clause= 0; with_clauses_list= 0; with_clauses_list_last_next= &with_clauses_list; create_view= NULL; + field_list.empty(); value_list.empty(); update_list.empty(); set_var_list.empty(); @@ -700,17 +706,17 @@ void LEX::start(THD *thd_arg) auxiliary_table_list.empty(); unit.next= unit.master= unit.link_next= unit.return_to= 0; unit.prev= unit.link_prev= 0; - unit.slave= current_select= all_selects_list= &select_lex; - select_lex.master= &unit; - select_lex.prev= &unit.slave; - select_lex.link_next= select_lex.slave= select_lex.next= 0; - select_lex.link_prev= (st_select_lex_node**)&(all_selects_list); - select_lex.options= 0; - select_lex.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED; - select_lex.init_order(); - select_lex.group_list.empty(); - if (select_lex.group_list_ptrs) - select_lex.group_list_ptrs->clear(); + unit.slave= current_select= all_selects_list= &builtin_select; + builtin_select.master= &unit; + builtin_select.prev= &unit.slave; + builtin_select.link_next= builtin_select.slave= builtin_select.next= 0; + builtin_select.link_prev= (st_select_lex_node**)&(all_selects_list); + builtin_select.options= 0; + builtin_select.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED; + builtin_select.init_order(); + builtin_select.group_list.empty(); + if (builtin_select.group_list_ptrs) + builtin_select.group_list_ptrs->clear(); describe= 0; analyze_stmt= 0; explain_json= false; @@ -720,14 +726,14 @@ void LEX::start(THD *thd_arg) safe_to_cache_query= 1; parsing_options.reset(); empty_field_list_on_rset= 0; - select_lex.select_number= 1; + builtin_select.select_number= 1; part_info= 0; - select_lex.in_sum_expr=0; - select_lex.ftfunc_list_alloc.empty(); - select_lex.ftfunc_list= &select_lex.ftfunc_list_alloc; - select_lex.group_list.empty(); - select_lex.order_list.empty(); - select_lex.gorder_list.empty(); + builtin_select.in_sum_expr=0; + builtin_select.ftfunc_list_alloc.empty(); + builtin_select.ftfunc_list= &builtin_select.ftfunc_list_alloc; + builtin_select.group_list.empty(); + builtin_select.order_list.empty(); + builtin_select.gorder_list.empty(); m_sql_cmd= NULL; duplicates= DUP_ERROR; ignore= 0; @@ -739,6 +745,8 @@ void LEX::start(THD *thd_arg) query_tables= 0; reset_query_tables_list(FALSE); expr_allows_subselect= TRUE; + selects_allow_into= FALSE; + selects_allow_procedure= FALSE; use_only_table_context= FALSE; parse_vcol_expr= FALSE; check_exists= FALSE; @@ -748,8 +756,8 @@ void LEX::start(THD *thd_arg) name= null_clex_str; event_parse_data= NULL; profile_options= PROFILE_NONE; - nest_level=0 ; - select_lex.nest_level_base= &unit; + nest_level= 0; + builtin_select.nest_level_base= &unit; allow_sum_func= 0; in_sum_func= NULL; @@ -773,6 +781,13 @@ void LEX::start(THD *thd_arg) vers_conditions.empty(); is_lex_started= TRUE; + + next_is_main= FALSE; + next_is_down= FALSE; + + wild= 0; + exchange= 0; + DBUG_VOID_RETURN; } @@ -1308,7 +1323,8 @@ int MYSQLlex(YYSTYPE *yylval, THD *thd) { Lex_input_stream *lip= & thd->m_parser_state->m_lip; int token; - + const int left_paren= (int) '('; + if (lip->lookahead_token >= 0) { /* @@ -1325,6 +1341,8 @@ int MYSQLlex(YYSTYPE *yylval, THD *thd) token= lex_one_token(yylval, thd); lip->add_digest_token(token, yylval); + SELECT_LEX *curr_sel= thd->lex->current_select; + switch(token) { case WITH: /* @@ -1375,8 +1393,16 @@ int MYSQLlex(YYSTYPE *yylval, THD *thd) } break; case VALUES: - if (thd->lex->current_select->parsing_place == IN_UPDATE_ON_DUP_KEY || - thd->lex->current_select->parsing_place == IN_PART_FUNC) + if (curr_sel && + (curr_sel->parsing_place == BEFORE_OPT_LIST || + curr_sel->parsing_place == AFTER_LIST)) + { + curr_sel->parsing_place= NO_MATTER; + break; + } + if (curr_sel && + (curr_sel->parsing_place == IN_UPDATE_ON_DUP_KEY || + curr_sel->parsing_place == IN_PART_FUNC)) return VALUE_SYM; token= lex_one_token(yylval, thd); lip->add_digest_token(token, yylval); @@ -1391,6 +1417,43 @@ int MYSQLlex(YYSTYPE *yylval, THD *thd) lip->lookahead_token= token; return VALUES; } + case VALUE_SYM: + if (curr_sel && + (curr_sel->parsing_place == BEFORE_OPT_LIST || + curr_sel->parsing_place == AFTER_LIST)) + { + curr_sel->parsing_place= NO_MATTER; + return VALUES; + } + break; + case PARTITION_SYM: + case SELECT_SYM: + case UNION_SYM: + if (curr_sel && + (curr_sel->parsing_place == BEFORE_OPT_LIST || + curr_sel->parsing_place == AFTER_LIST)) + { + curr_sel->parsing_place= NO_MATTER; + } + break; + case left_paren: + if (!curr_sel || + curr_sel->parsing_place != BEFORE_OPT_LIST) + return token; + token= lex_one_token(yylval, thd); + lip->add_digest_token(token, yylval); + lip->lookahead_yylval= lip->yylval; + lip->yylval= NULL; + lip->lookahead_token= token; + curr_sel->parsing_place= NO_MATTER; + if (token == LIKE) + return LEFT_PAREN_LIKE; + if (token == WITH) + return LEFT_PAREN_WITH; + if (token != left_paren && token != SELECT_SYM) + return LEFT_PAREN_ALT; + else + return left_paren; break; default: break; @@ -1888,7 +1951,7 @@ static int lex_one_token(YYSTYPE *yylval, THD *thd) return(TEXT_STRING); } case MY_LEX_COMMENT: // Comment - lex->select_lex.options|= OPTION_FOUND_COMMENT; + lex->builtin_select.options|= OPTION_FOUND_COMMENT; while ((c = lip->yyGet()) != '\n' && c) ; lip->yyUnget(); // Safety against eof state = MY_LEX_START; // Try again @@ -1899,7 +1962,7 @@ static int lex_one_token(YYSTYPE *yylval, THD *thd) state=MY_LEX_CHAR; // Probable division break; } - lex->select_lex.options|= OPTION_FOUND_COMMENT; + lex->builtin_select.options|= OPTION_FOUND_COMMENT; /* Reject '/' '*', since we might need to turn off the echo */ lip->yyUnget(); @@ -2184,7 +2247,8 @@ void st_select_lex_node::init_query_common() { options= 0; sql_cache= SQL_CACHE_UNSPECIFIED; - linkage= UNSPECIFIED_TYPE; + set_linkage(UNSPECIFIED_TYPE); + distinct= TRUE; no_table_names_allowed= 0; uncacheable= 0; } @@ -2192,7 +2256,7 @@ void st_select_lex_node::init_query_common() void st_select_lex_unit::init_query() { init_query_common(); - linkage= GLOBAL_OPTIONS_TYPE; + set_linkage(GLOBAL_OPTIONS_TYPE); select_limit_cnt= HA_POS_ERROR; offset_limit_cnt= 0; union_distinct= 0; @@ -2233,16 +2297,6 @@ void st_select_lex::init_query() having_fix_field= 0; context.select_lex= this; context.init(); - /* - Add the name resolution context of the current (sub)query to the - stack of contexts for the whole query. - TODO: - push_context may return an error if there is no memory for a new - element in the stack, however this method has no return value, - thus push_context should be moved to a place where query - initialization is checked for failure. - */ - parent_lex->push_context(&context, parent_lex->thd->mem_root); cond_count= between_count= with_wild= 0; max_equal_elems= 0; ref_pointer_array.reset(); @@ -2297,6 +2351,7 @@ void st_select_lex::init_select() /* Set limit and offset to default values */ select_limit= 0; /* denotes the default limit = HA_POS_ERROR */ offset_limit= 0; /* denotes the default offset = 0 */ + is_set_query_expr_tail= false; with_sum_func= 0; is_correlated= 0; cur_pos_in_select_list= UNDEF_POS; @@ -2357,6 +2412,23 @@ void st_select_lex_node::add_slave(st_select_lex_node *slave_arg) } } +void st_select_lex_node::link_chain_down(st_select_lex_node *first) +{ + st_select_lex_node *last_node; + st_select_lex_node *node= first; + do + { + last_node= node; + node->master= this; + node= node->next; + } while (node); + if ((last_node->next= slave)) + { + slave->prev= &last_node->next; + } + first->prev= &slave; + slave= first; +} /* include on level down (but do not link) @@ -2406,7 +2478,7 @@ void st_select_lex_node::fast_exclude() // Remove slave structure for (; slave; slave= slave->next) slave->fast_exclude(); - + } @@ -3083,6 +3155,7 @@ LEX::LEX() gtid_domain_static_buffer, initial_gtid_domain_buffer_size, initial_gtid_domain_buffer_size, 0); + unit.slave= &builtin_select; } @@ -3109,12 +3182,12 @@ bool LEX::can_be_merged() // TODO: do not forget implement case when select_lex.table_list.elements==0 /* find non VIEW subqueries/unions */ - bool selects_allow_merge= (select_lex.next_select() == 0 && - !(select_lex.uncacheable & + bool selects_allow_merge= (first_select_lex()->next_select() == 0 && + !(first_select_lex()->uncacheable & UNCACHEABLE_RAND)); if (selects_allow_merge) { - for (SELECT_LEX_UNIT *tmp_unit= select_lex.first_inner_unit(); + for (SELECT_LEX_UNIT *tmp_unit= first_select_lex()->first_inner_unit(); tmp_unit; tmp_unit= tmp_unit->next_unit()) { @@ -3131,12 +3204,12 @@ bool LEX::can_be_merged() } return (selects_allow_merge && - select_lex.group_list.elements == 0 && - select_lex.having == 0 && - select_lex.with_sum_func == 0 && - select_lex.table_list.elements >= 1 && - !(select_lex.options & SELECT_DISTINCT) && - select_lex.select_limit == 0); + first_select_lex()->group_list.elements == 0 && + first_select_lex()->having == 0 && + first_select_lex()->with_sum_func == 0 && + first_select_lex()->table_list.elements >= 1 && + !(first_select_lex()->options & SELECT_DISTINCT) && + first_select_lex()->select_limit == 0); } @@ -3489,7 +3562,7 @@ void LEX::set_trg_event_type_for_tables() Do not iterate over sub-selects, only the tables in the outermost SELECT_LEX can be modified, if any. */ - TABLE_LIST *tables= select_lex.get_table_list(); + TABLE_LIST *tables= first_select_lex()->get_table_list(); while (tables) { @@ -3545,12 +3618,13 @@ TABLE_LIST *LEX::unlink_first_table(bool *link_to_local) /* and from local list if it is not empty */ - if ((*link_to_local= MY_TEST(select_lex.table_list.first))) + if ((*link_to_local= MY_TEST(first_select_lex()->table_list.first))) { - select_lex.context.table_list= - select_lex.context.first_name_resolution_table= first->next_local; - select_lex.table_list.first= first->next_local; - select_lex.table_list.elements--; //safety + first_select_lex()->context.table_list= + first_select_lex()->context.first_name_resolution_table= + first->next_local; + first_select_lex()->table_list.first= first->next_local; + first_select_lex()->table_list.elements--; //safety first->next_local= 0; /* Ensure that the global list has the same first table as the local @@ -3581,7 +3655,7 @@ TABLE_LIST *LEX::unlink_first_table(bool *link_to_local) void LEX::first_lists_tables_same() { - TABLE_LIST *first_table= select_lex.table_list.first; + TABLE_LIST *first_table= first_select_lex()->table_list.first; if (query_tables != first_table && first_table != 0) { TABLE_LIST *next; @@ -3606,6 +3680,23 @@ void LEX::first_lists_tables_same() } } +void LEX::fix_first_select_number() +{ + SELECT_LEX *first= first_select_lex(); + if (first && first->select_number != 1) + { + uint num= first->select_number; + for (SELECT_LEX *sel= all_selects_list; + sel; + sel= sel->next_select_in_list()) + { + if (sel->select_number < num) + sel->select_number++; + } + first->select_number= 1; + } +} + /* Link table back that was unlinked with unlink_first_table() @@ -3631,10 +3722,10 @@ void LEX::link_first_table_back(TABLE_LIST *first, if (link_to_local) { - first->next_local= select_lex.table_list.first; - select_lex.context.table_list= first; - select_lex.table_list.first= first; - select_lex.table_list.elements++; //safety + first->next_local= first_select_lex()->table_list.first; + first_select_lex()->context.table_list= first; + first_select_lex()->table_list.first= first; + first_select_lex()->table_list.elements++; //safety } } } @@ -3663,19 +3754,19 @@ void LEX::cleanup_after_one_table_open() NOTE: all units will be connected to thd->lex->select_lex, because we have not UNION on most upper level. */ - if (all_selects_list != &select_lex) + if (all_selects_list != first_select_lex()) { derived_tables= 0; - select_lex.exclude_from_table_unique_test= false; + first_select_lex()->exclude_from_table_unique_test= false; /* cleunup underlying units (units of VIEW) */ - for (SELECT_LEX_UNIT *un= select_lex.first_inner_unit(); + for (SELECT_LEX_UNIT *un= first_select_lex()->first_inner_unit(); un; un= un->next_unit()) un->cleanup(); /* reduce all selects list to default state */ - all_selects_list= &select_lex; + all_selects_list= first_select_lex(); /* remove underlying units (units of VIEW) subtree */ - select_lex.cut_subtree(); + first_select_lex()->cut_subtree(); } } @@ -4541,7 +4632,7 @@ void st_select_lex::set_explain_type(bool on_the_fly) using_materialization= TRUE; } - if (&master_unit()->thd->lex->select_lex == this) + if (master_unit()->thd->lex->first_select_lex() == this) { type= is_primary ? "PRIMARY" : "SIMPLE"; } @@ -4736,8 +4827,8 @@ bool LEX::save_prep_leaf_tables() Query_arena *arena= thd->stmt_arena, backup; arena= thd->activate_stmt_arena_if_needed(&backup); //It is used for DETETE/UPDATE so top level has only one SELECT - DBUG_ASSERT(select_lex.next_select() == NULL); - bool res= select_lex.save_prep_leaf_tables(thd); + DBUG_ASSERT(first_select_lex()->next_select() == NULL); + bool res= first_select_lex()->save_prep_leaf_tables(thd); if (arena) thd->restore_active_arena(arena, &backup); @@ -5066,8 +5157,13 @@ bool LEX::is_partition_management() const SELECT_LEX *LEX::exclude_last_select() { - DBUG_ENTER("SELECT_LEX::exclude_last_select"); - SELECT_LEX *exclude= current_select; + return exclude_not_first_select(current_select); +} + +SELECT_LEX *LEX::exclude_not_first_select(SELECT_LEX *exclude) +{ + DBUG_ENTER("LEX::exclude_not_first_select"); + DBUG_PRINT("enter", ("exclude %p #%u", exclude, exclude->select_number)); SELECT_LEX_UNIT *unit= exclude->master_unit(); SELECT_LEX *sl; DBUG_ASSERT(unit->first_select() != exclude); @@ -5078,13 +5174,228 @@ SELECT_LEX *LEX::exclude_last_select() DBUG_PRINT("info", ("excl: %p unit: %p prev: %p", exclude, unit, sl)); if (!sl) DBUG_RETURN(NULL); - DBUG_ASSERT(exclude->next_select() == NULL); - exclude->exclude_from_tree(); + DBUG_ASSERT(&sl->next == exclude->prev); + + exclude->prev= NULL; + current_select= sl; DBUG_RETURN(exclude); } +SELECT_LEX_UNIT *LEX::alloc_unit() +{ + SELECT_LEX_UNIT *unit; + DBUG_ENTER("LEX::alloc_unit"); + if (!(unit= new (thd->mem_root) SELECT_LEX_UNIT())) + DBUG_RETURN(NULL); + + unit->init_query(); + /* TODO: reentrant problem */ + unit->thd= thd; + unit->link_next= 0; + unit->link_prev= 0; + /* TODO: remove return_to */ + unit->return_to= NULL; + DBUG_RETURN(unit); +} + + +SELECT_LEX *LEX::alloc_select(bool select) +{ + SELECT_LEX *select_lex; + DBUG_ENTER("LEX::alloc_select"); + if (!(select_lex= new (thd->mem_root) SELECT_LEX())) + DBUG_RETURN(NULL); + DBUG_PRINT("info", ("Allocate select: %p #%u statement lex: %p", + select_lex, thd->stmt_lex->current_select_number, + thd->stmt_lex)); + select_lex->select_number= ++thd->stmt_lex->current_select_number; + select_lex->parent_lex= this; /* Used in init_query. */ + select_lex->init_query(); + if (select) + select_lex->init_select(); + select_lex->nest_level_base= &this->unit; + select_lex->include_global((st_select_lex_node**)&all_selects_list); + select_lex->context.resolve_in_select_list= TRUE; + DBUG_RETURN(select_lex); +} + +SELECT_LEX_UNIT * +LEX::create_unit(SELECT_LEX *first_sel) +{ + SELECT_LEX_UNIT *unit; + DBUG_ENTER("LEX::create_unit"); + + if (!(unit= alloc_unit())) + DBUG_RETURN(NULL); + + unit->register_select_chain(first_sel); + if (first_sel->next_select()) + { + unit->reset_distinct(); + DBUG_ASSERT(!unit->fake_select_lex); + if (unit->add_fake_select_lex(thd)) + DBUG_RETURN(NULL); + } + DBUG_RETURN(unit); +} + +SELECT_LEX_UNIT * +SELECT_LEX::attach_selects_chain(SELECT_LEX *first_sel, + Name_resolution_context *context) +{ + SELECT_LEX_UNIT *unit; + DBUG_ENTER("SELECT_LEX::attach_select_chain"); + + if (!(unit= parent_lex->alloc_unit())) + DBUG_RETURN(NULL); + + unit->register_select_chain(first_sel); + register_unit(unit, context); + if (first_sel->next_select()) + { + unit->reset_distinct(); + DBUG_ASSERT(!unit->fake_select_lex); + if (unit->add_fake_select_lex(parent_lex->thd)) + DBUG_RETURN(NULL); + } + + DBUG_RETURN(unit); +} + +SELECT_LEX * +LEX::wrap_unit_into_derived(SELECT_LEX_UNIT *unit) +{ + SELECT_LEX *wrapping_sel; + Table_ident *ti; + DBUG_ENTER("LEX::wrap_unit_into_derived"); + + if (!(wrapping_sel= alloc_select(TRUE))) + DBUG_RETURN(NULL); + Name_resolution_context *context= &wrapping_sel->context; + context->init(); + wrapping_sel->automatic_brackets= FALSE; + + wrapping_sel->register_unit(unit, context); + + /* stuff dummy SELECT * FROM (...) */ + + if (push_select(wrapping_sel)) // for Items & TABLE_LIST + DBUG_RETURN(NULL); + + /* add SELECT list*/ + { + Item *item= new (thd->mem_root) + Item_field(thd, context, NULL, NULL, &star_clex_str); + if (item == NULL) + goto err; + if (add_item_to_list(thd, item)) + goto err; + (wrapping_sel->with_wild)++; + } + + unit->first_select()->set_linkage(DERIVED_TABLE_TYPE); + + ti= new (thd->mem_root) Table_ident(unit); + if (ti == NULL) + goto err; + { + char buff[10]; + TABLE_LIST *table_list; + LEX_CSTRING alias; + alias.length= my_snprintf(buff, sizeof(buff), + "__%u", wrapping_sel->select_number); + alias.str= thd->strmake(buff, alias.length); + if (!alias.str) + goto err; + + if (!(table_list= wrapping_sel->add_table_to_list(thd, ti, &alias, + 0, TL_READ, + MDL_SHARED_READ))) + goto err; + + context->resolve_in_table_list_only(table_list); + wrapping_sel->add_joined_table(table_list); + } + + pop_select(); + + derived_tables|= DERIVED_SUBQUERY; + + DBUG_RETURN(wrapping_sel); + +err: + pop_select(); + DBUG_RETURN(NULL); +} + +SELECT_LEX *LEX::link_selects_chain_down(SELECT_LEX *sel) +{ + SELECT_LEX *dummy_select; + SELECT_LEX_UNIT *unit; + Table_ident *ti; + DBUG_ENTER("LEX::link_selects_chain_down"); + + if (!(dummy_select= alloc_select(TRUE))) + DBUG_RETURN(NULL); + Name_resolution_context *context= &dummy_select->context; + dummy_select->automatic_brackets= FALSE; + + if (!(unit= dummy_select->attach_selects_chain(sel, context))) + DBUG_RETURN(NULL); + + /* stuff dummy SELECT * FROM (...) */ + + if (push_select(dummy_select)) // for Items & TABLE_LIST + DBUG_RETURN(NULL); + + /* add SELECT list*/ + { + Item *item= new (thd->mem_root) + Item_field(thd, context, NULL, NULL, &star_clex_str); + if (item == NULL) + goto err; + if (add_item_to_list(thd, item)) + goto err; + (dummy_select->with_wild)++; + } + + sel->set_linkage(DERIVED_TABLE_TYPE); + + ti= new (thd->mem_root) Table_ident(unit); + if (ti == NULL) + goto err; + { + char buff[10]; + TABLE_LIST *table_list; + LEX_CSTRING alias; + alias.length= my_snprintf(buff, sizeof(buff), + "__%u", dummy_select->select_number); + alias.str= thd->strmake(buff, alias.length); + if (!alias.str) + goto err; + + if (!(table_list= dummy_select->add_table_to_list(thd, ti, &alias, + 0, TL_READ, + MDL_SHARED_READ))) + goto err; + + context->resolve_in_table_list_only(table_list); + dummy_select->add_joined_table(table_list); + } + + pop_select(); + + derived_tables|= DERIVED_SUBQUERY; + + DBUG_RETURN(dummy_select); + +err: + pop_select(); + DBUG_RETURN(NULL); +} + /** Put given (new) SELECT_LEX level below after currect (last) SELECT @@ -5107,13 +5418,43 @@ SELECT_LEX *LEX::exclude_last_select() bool LEX::add_unit_in_brackets(SELECT_LEX *nselect) { DBUG_ENTER("LEX::add_unit_in_brackets"); - bool distinct= nselect->master_unit()->union_distinct == nselect; - bool rc= add_select_to_union_list(distinct, nselect->linkage, 0); - if (rc) + SELECT_LEX_UNIT *unit= nselect->master_unit(); + int old_nest_level= nselect->nest_level; + bool distinct= unit->union_distinct == nselect; + if (add_select_to_union_list(distinct, nselect->linkage, 0)) DBUG_RETURN(TRUE); - SELECT_LEX* dummy_select= current_select; - dummy_select->automatic_brackets= TRUE; - dummy_select->linkage= nselect->linkage; + + SELECT_LEX *dummy= current_select; + dummy->next= NULL; + if (make_select_in_brackets(current_select, nselect, FALSE)) + DBUG_RETURN(TRUE); + + if (!distinct && nselect->master_unit()->union_distinct) + { + // move distinct pointer + if (unit->union_distinct->master_unit() != unit) + { + unit->union_distinct->master_unit()->union_distinct= unit->union_distinct; + unit->union_distinct= NULL; + } + } + else if (distinct) + unit->union_distinct= NULL;// distinct was moved by add_select_to_union_list + + dummy->set_nest_level(old_nest_level); + DBUG_RETURN(FALSE); +} + + +bool LEX::make_select_in_brackets(SELECT_LEX* dummy_select, + SELECT_LEX *nselect, bool automatic) +{ + DBUG_ENTER("LEX::make_select_in_brackets"); + + int old_nest_level= nselect->nest_level; + dummy_select->automatic_brackets= automatic; + dummy_select->set_linkage(nselect->linkage); + current_select= dummy_select; // for mysql_new_select & Items /* stuff dummy SELECT * FROM (...) */ Name_resolution_context *context= &dummy_select->context; @@ -5128,12 +5469,19 @@ bool LEX::add_unit_in_brackets(SELECT_LEX *nselect) DBUG_RETURN(TRUE); (dummy_select->with_wild)++; - rc= mysql_new_select(this, 1, nselect); - nselect->linkage= DERIVED_TABLE_TYPE; - DBUG_ASSERT(nselect->outer_select() == dummy_select); + nselect->set_linkage(DERIVED_TABLE_TYPE); + SELECT_LEX *sl= nselect; + bool down= TRUE; + do{ + SELECT_LEX *next= sl->next_select(); + if (mysql_new_select(this, down, sl)) + DBUG_RETURN(TRUE); + down= FALSE; + DBUG_ASSERT(sl->outer_select() == dummy_select); + sl= next; + } while (sl); current_select= dummy_select; - current_select->nest_level--; SELECT_LEX_UNIT *unit= nselect->master_unit(); Table_ident *ti= new (thd->mem_root) Table_ident(unit); @@ -5157,11 +5505,63 @@ bool LEX::add_unit_in_brackets(SELECT_LEX *nselect) derived_tables|= DERIVED_SUBQUERY; + if (dummy_select->set_nest_level(old_nest_level)) + DBUG_RETURN(TRUE); + current_select= nselect; - current_select->nest_level++; - DBUG_RETURN(rc); + DBUG_RETURN(FALSE); } +bool LEX::push_context(Name_resolution_context *context) +{ + DBUG_ENTER("LEX::push_context"); + DBUG_PRINT("info", ("Context: %p Select: %p (%d)", + context, context->select_lex, + (context->select_lex ? + context->select_lex->select_number: + 0))); + bool res= context_stack.push_front(context, thd->mem_root); + DBUG_RETURN(res); +} + + +bool LEX::push_new_select(SELECT_LEX *last) +{ + DBUG_ENTER("LEX::push new_select"); + DBUG_PRINT("info", ("Push last select: %p (%d)", + last, last->select_number)); + bool res= last_select_stack.push_front(last, thd->mem_root); + DBUG_RETURN(res); +} + + +bool check_intersect_prefix(SELECT_LEX* first_in_unit) +{ + SELECT_LEX *sel; + for (sel= first_in_unit->next_select(); + sel && sel->linkage == INTERSECT_TYPE; + sel= sel->next_select()) + ; + return (sel == NULL); +} + + +SELECT_LEX *LEX::pop_new_select_and_wrap() +{ + DBUG_ENTER("LEX::pop_new_select_and_wrap"); + SELECT_LEX *sel; + SELECT_LEX *last= pop_new_select(); + SELECT_LEX *first= last->next_select(); + last->cut_next(); + enum sub_select_type op= first->linkage; + bool ds= first->distinct; + if (!(sel= link_selects_chain_down(first))) + DBUG_RETURN(NULL); + last->link_neighbour(sel); + sel->set_linkage_and_distinct(op, ds); + sel->set_master_unit(last->master_unit()); + DBUG_RETURN(sel); +} /** Checks if we need finish "automatic brackets" mode @@ -6559,7 +6959,6 @@ Item_param *LEX::add_placeholder(THD *thd, const LEX_CSTRING *name, my_error(ER_VIEW_SELECT_VARIABLE, MYF(0)); return NULL; } - Query_fragment pos(thd, sphead, start, end); Item_param *item= new (thd->mem_root) Item_param(thd, name, pos.pos(), pos.length()); @@ -7416,6 +7815,156 @@ Item *st_select_lex::build_cond_for_grouping_fields(THD *thd, Item *cond, } +bool st_select_lex::set_nest_level(int new_nest_level) +{ + DBUG_ENTER("st_select_lex::set_nest_level"); + DBUG_PRINT("enter", ("select #%d %p nest level: %d", + select_number, this, new_nest_level)); + if (new_nest_level > (int) MAX_SELECT_NESTING) + { + my_error(ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT, MYF(0)); + DBUG_RETURN(TRUE); + } + nest_level= new_nest_level; + new_nest_level++; + for (SELECT_LEX_UNIT *u= first_inner_unit(); u; u= u->next_unit()) + { + if (u->set_nest_level(new_nest_level)) + DBUG_RETURN(TRUE); + } + DBUG_RETURN(FALSE); +} + +bool st_select_lex_unit::set_nest_level(int new_nest_level) +{ + DBUG_ENTER("st_select_lex_unit::set_nest_level"); + for(SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) + { + if (sl->set_nest_level(new_nest_level)) + DBUG_RETURN(TRUE); + } + if (fake_select_lex && + fake_select_lex->set_nest_level(new_nest_level)) + DBUG_RETURN(TRUE); + DBUG_RETURN(FALSE); +} + + +bool st_select_lex::check_parameters(SELECT_LEX *main_select) +{ + DBUG_ENTER("st_select_lex::check_parameters"); + DBUG_PRINT("enter", ("select #%d %p nest level: %d", + select_number, this, nest_level)); + + + if ((options & OPTION_INTO_CLAUSE) && + (!parent_lex->selects_allow_into || + next_select() != NULL || + nest_level != 0)) + { + my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "INTO"); + DBUG_RETURN(TRUE); + } + + if (options & OPTION_PROCEDURE_CLAUSE) + { + if (!parent_lex->selects_allow_procedure || + next_select() != NULL || + this != master_unit()->first_select() || + nest_level != 0) + { + my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "PROCEDURE"); + DBUG_RETURN(TRUE); + } + if (options & OPTION_INTO_CLAUSE) + { + my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "INTO"); + DBUG_RETURN(TRUE); + } + } + + if ((options & SELECT_HIGH_PRIORITY) && this != main_select) + { + my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "HIGH_PRIORITY"); + DBUG_RETURN(TRUE); + } + if ((options & OPTION_BUFFER_RESULT) && this != main_select) + { + my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_BUFFER_RESULT"); + DBUG_RETURN(TRUE); + } + if ((options & OPTION_FOUND_ROWS) && this != main_select) + { + my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_CALC_FOUND_ROWS"); + DBUG_RETURN(TRUE); + } + if (options & OPTION_NO_QUERY_CACHE) + { + /* + Allow this flag only on the first top-level SELECT statement, if + SQL_CACHE wasn't specified. + */ + if (this != main_select) + { + my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_NO_CACHE"); + DBUG_RETURN(TRUE); + } + if (main_select->sql_cache == SELECT_LEX::SQL_CACHE) + { + my_error(ER_WRONG_USAGE, MYF(0), "SQL_CACHE", "SQL_NO_CACHE"); + DBUG_RETURN(TRUE); + } + parent_lex->safe_to_cache_query=0; + main_select->sql_cache= SELECT_LEX::SQL_NO_CACHE; + } + if (options & OPTION_TO_QUERY_CACHE) + { + /* + Allow this flag only on the first top-level SELECT statement, if + SQL_NO_CACHE wasn't specified. + */ + if (this != main_select) + { + my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_CACHE"); + DBUG_RETURN(TRUE); + } + if (main_select->sql_cache == SELECT_LEX::SQL_NO_CACHE) + { + my_error(ER_WRONG_USAGE, MYF(0), "SQL_NO_CACHE", "SQL_CACHE"); + DBUG_RETURN(TRUE); + } + parent_lex->safe_to_cache_query=1; + main_select->sql_cache= SELECT_LEX::SQL_CACHE; + } + + for (SELECT_LEX_UNIT *u= first_inner_unit(); u; u= u->next_unit()) + { + if (u->check_parameters(main_select)) + DBUG_RETURN(TRUE); + } + DBUG_RETURN(FALSE); +} + + +bool st_select_lex_unit::check_parameters(SELECT_LEX *main_select) +{ + for(SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) + { + if (sl->check_parameters(main_select)) + return TRUE; + } + return fake_select_lex && fake_select_lex->check_parameters(main_select); +} + + +bool LEX::check_main_unit_semantics() +{ + if (unit.set_nest_level(0) || + unit.check_parameters(first_select_lex())) + return TRUE; + return FALSE; +} + int set_statement_var_if_exists(THD *thd, const char *var_name, size_t var_name_length, ulonglong value) { @@ -7469,10 +8018,10 @@ bool LEX::create_or_alter_view_finalize(THD *thd, Table_ident *table_ident) { sql_command= SQLCOM_CREATE_VIEW; /* first table in list is target VIEW name */ - if (!select_lex.add_table_to_list(thd, table_ident, NULL, - TL_OPTION_UPDATING, - TL_IGNORE, - MDL_EXCLUSIVE)) + if (!first_select_lex()->add_table_to_list(thd, table_ident, NULL, + TL_OPTION_UPDATING, + TL_IGNORE, + MDL_EXCLUSIVE)) return true; query_tables->open_strategy= TABLE_LIST::OPEN_STUB; return false; @@ -7757,3 +8306,221 @@ Item *Lex_trim_st::make_item_func_trim(THD *thd) const make_item_func_trim_oracle(thd) : make_item_func_trim_std(thd); } + + +void st_select_lex_unit::reset_distinct() +{ + union_distinct= NULL; + for(SELECT_LEX *sl= first_select()->next_select(); + sl; + sl= sl->next_select()) + { + if (sl->distinct) + { + union_distinct= sl; + return; + } + } +} + + +void st_select_lex_unit::fix_distinct(st_select_lex_unit *new_unit) +{ + if (union_distinct) + { + if (this != union_distinct->master_unit()) + { + DBUG_ASSERT(new_unit == union_distinct->master_unit()); + new_unit->union_distinct= union_distinct; + reset_distinct(); + } + else + new_unit->reset_distinct(); + } +} + + +void st_select_lex_unit::register_select_chain(SELECT_LEX *first_sel) +{ + DBUG_ASSERT(first_sel != 0); + slave= first_sel; + first_sel->prev= &slave; + for(SELECT_LEX *sel=first_sel; sel; sel= sel->next_select()) + { + sel->master= (st_select_lex_node *)this; + uncacheable|= sel->uncacheable; + } +} + + +void st_select_lex::register_unit(SELECT_LEX_UNIT *unit, + Name_resolution_context *outer_context) +{ + if ((unit->next= slave)) + slave->prev= &unit->next; + unit->prev= &slave; + slave= unit; + unit->master= this; + uncacheable|= unit->uncacheable; + + for(SELECT_LEX *sel= unit->first_select();sel; sel= sel->next_select()) + { + sel->context.outer_context= outer_context; + } +} + + +void st_select_lex::add_statistics(SELECT_LEX_UNIT *unit) +{ + for (; + unit; + unit= unit->next_unit()) + for(SELECT_LEX *child= unit->first_select(); + child; + child= child->next_select()) + { + /* + A subselect can add fields to an outer select. + Reserve space for them. + */ + select_n_where_fields+= child->select_n_where_fields; + /* + Aggregate functions in having clause may add fields + to an outer select. Count them also. + */ + select_n_having_items+= child->select_n_having_items; + } +} + + +bool LEX::main_select_push() +{ + DBUG_ENTER("LEX::main_select_push"); + current_select_number= 1; + builtin_select.select_number= 1; + if (push_select(&builtin_select)) + DBUG_RETURN(TRUE); + DBUG_RETURN(FALSE); +} + +bool Lex_order_limit_lock::set_to(SELECT_LEX *sel) +{ + /*TODO: lock */ + //if (lock.defined_lock && sel == sel->master_unit()->fake_select_lex) + // return TRUE; + if (lock.defined_timeout) + { + THD *thd= sel->parent_lex->thd; + if (set_statement_var_if_exists(thd, + C_STRING_WITH_LEN("lock_wait_timeout"), + lock.timeout) || + set_statement_var_if_exists(thd, + C_STRING_WITH_LEN("innodb_lock_wait_timeout"), + lock.timeout)) + return TRUE; + } + if (lock.defined_lock) + { + sel->parent_lex->safe_to_cache_query= 0; + if (lock.update_lock) + { + sel->lock_type= TL_WRITE; + sel->set_lock_for_tables(TL_WRITE); + } + else + { + sel->lock_type= TL_READ_WITH_SHARED_LOCKS; + sel->set_lock_for_tables(TL_READ_WITH_SHARED_LOCKS); + } + } + sel->explicit_limit= limit.explicit_limit; + sel->select_limit= limit.select_limit; + sel->offset_limit= limit.offset_limit; + if (order_list) + { + if (sel->linkage != GLOBAL_OPTIONS_TYPE && + sel->olap != UNSPECIFIED_OLAP_TYPE && + (sel->linkage != UNION_TYPE || sel->braces)) + { + my_error(ER_WRONG_USAGE, MYF(0), + "CUBE/ROLLUP", "ORDER BY"); + return TRUE; + } + sel->order_list= *(order_list); + } + sel->is_set_query_expr_tail= true; + return FALSE; +} + + +static void change_item_list_context(List<Item> *list, + Name_resolution_context *context) +{ + List_iterator_fast<Item> it (*list); + Item *item; + while((item= it++)) + { + item->walk(&Item::change_context_processor, FALSE, (void *)context); + } +} + + +bool LEX::insert_select_hack(SELECT_LEX *sel) +{ + DBUG_ENTER("LEX::insert_select_hack"); + + DBUG_ASSERT(first_select_lex() == &builtin_select); + DBUG_ASSERT(sel != NULL); + + DBUG_ASSERT(builtin_select.first_inner_unit() == NULL); + + if (builtin_select.link_prev) + { + if ((*builtin_select.link_prev= builtin_select.link_next)) + ((st_select_lex *)builtin_select.link_next)->link_prev= + builtin_select.link_prev; + builtin_select.link_prev= NULL; // indicator of removal + } + + set_main_unit(sel->master_unit()); + + DBUG_ASSERT(builtin_select.table_list.elements == 1); + TABLE_LIST *insert_table= builtin_select.table_list.first; + + if (!(insert_table->next_local= sel->table_list.first)) + { + sel->table_list.next= &insert_table->next_local; + } + sel->table_list.first= insert_table; + sel->table_list.elements++; + insert_table->select_lex= sel; + + sel->context.first_name_resolution_table= insert_table; + builtin_select.context= sel->context; + change_item_list_context(&field_list, &sel->context); + + if (sel->tvc && !sel->next_select() && + (sql_command == SQLCOM_INSERT_SELECT || + sql_command == SQLCOM_REPLACE_SELECT)) + { + DBUG_PRINT("info", ("'Usual' INSERT detected")); + many_values= sel->tvc->lists_of_values; + sel->options= sel->tvc->select_options; + sel->tvc= NULL; + if (sql_command == SQLCOM_INSERT_SELECT) + sql_command= SQLCOM_INSERT; + else + sql_command= SQLCOM_REPLACE; + } + + + for (SELECT_LEX *sel= all_selects_list; + sel; + sel= sel->next_select_in_list()) + { + if (sel->select_number != 1) + sel->select_number--; + }; + + DBUG_RETURN(FALSE); +} diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 02c2ffb6a12..5c053022317 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -74,6 +74,16 @@ enum sub_select_type UNION_TYPE, INTERSECT_TYPE, EXCEPT_TYPE, GLOBAL_OPTIONS_TYPE, DERIVED_TABLE_TYPE, OLAP_TYPE }; + +inline int cmp_unit_op(enum sub_select_type op1, enum sub_select_type op2) +{ + DBUG_ASSERT(op1 >= UNION_TYPE && op1 <= EXCEPT_TYPE); + DBUG_ASSERT(op2 >= UNION_TYPE && op2 <= EXCEPT_TYPE); + return (op1 == INTERSECT_TYPE ? 1 : 0) - (op2 == INTERSECT_TYPE ? 1 : 0); +} + +bool check_intersect_prefix(SELECT_LEX* first_in_unit); + enum unit_common_op {OP_MIX, OP_UNION, OP_INTERSECT, OP_EXCEPT}; enum enum_view_suid @@ -193,6 +203,7 @@ struct LEX_TYPE additional "partitions" column even if partitioning is not compiled in. */ #define DESCRIBE_PARTITIONS 4 +#define DESCRIBE_EXTENDED2 8 #ifdef MYSQL_SERVER @@ -431,7 +442,7 @@ public: unit is container of either - One SELECT - UNION of selects - select_lex and unit are both inherited form select_lex_node + select_lex and unit are both inherited form st_select_lex_node neighbors are two select_lex or units on the same level All select describing structures linked with following pointers: @@ -577,6 +588,7 @@ public: { return linkage == UNION_TYPE || linkage == INTERSECT_TYPE || linkage == EXCEPT_TYPE; } + bool distinct; bool no_table_names_allowed; /* used for global order by */ static void *operator new(size_t size, MEM_ROOT *mem_root) throw () @@ -597,10 +609,29 @@ public: void include_down(st_select_lex_node *upper); void add_slave(st_select_lex_node *slave_arg); void include_neighbour(st_select_lex_node *before); + void link_chain_down(st_select_lex_node *first); + void link_neighbour(st_select_lex_node *neighbour) + { + DBUG_ASSERT(next == NULL); + DBUG_ASSERT(neighbour != NULL); + next= neighbour; + neighbour->prev= &next; + } + void cut_next() { next= NULL; } void include_standalone(st_select_lex_node *sel, st_select_lex_node **ref); void include_global(st_select_lex_node **plink); void exclude(); void exclude_from_tree(); + void exclude_from_global() + { + if (!link_prev) + return; + if (((*link_prev)= link_next)) + link_next->link_prev= link_prev; + link_next= NULL; + link_prev= NULL; + } + void set_slave(st_select_lex_node *slave_arg) { slave= slave_arg; } void move_node(st_select_lex_node *where_to_move) @@ -616,6 +647,22 @@ public: st_select_lex_node *insert_chain_before(st_select_lex_node **ptr_pos_to_insert, st_select_lex_node *end_chain_node); void move_as_slave(st_select_lex_node *new_master); + void set_linkage(enum sub_select_type l) + { + DBUG_ENTER("st_select_lex_node::set_linkage"); + DBUG_PRINT("info", ("node: %p linkage: %d->%d", this, linkage, l)); + linkage= l; + DBUG_VOID_RETURN; + } + /* + This method created for reiniting LEX in mysql_admin_table() and can be + used only if you are going remove all SELECT_LEX & units except belonger + to LEX (LEX::unit & LEX::select, for other purposes there are + SELECT_LEX_UNIT::exclude_level & SELECT_LEX_UNIT::exclude_tree. + + It is also used in parsing to detach builtin select. + */ + void cut_subtree() { slave= 0; } friend class st_select_lex_unit; friend bool mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *sel); friend bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, @@ -625,6 +672,8 @@ public: friend bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *orig_table_list); friend bool TABLE_LIST::init_derived(THD *thd, bool init_view); + + friend class st_select_lex; private: void fast_exclude(); }; @@ -670,9 +719,9 @@ public: { } - TABLE *table; /* temporary table using for appending UNION results */ select_result *result; + st_select_lex *pre_last_parse; bool prepared, // prepare phase already performed for UNION (unit) optimized, // optimize phase already performed for UNION (unit) optimized_2, @@ -759,7 +808,7 @@ public: { return reinterpret_cast<st_select_lex*>(slave); } - inline void set_with_clause(With_clause *with_cl); + void set_with_clause(With_clause *with_cl); st_select_lex_unit* next_unit() { return reinterpret_cast<st_select_lex_unit*>(next); @@ -801,6 +850,16 @@ public: int save_union_explain(Explain_query *output); int save_union_explain_part2(Explain_query *output); unit_common_op common_op(); + + void reset_distinct(); + void fix_distinct(st_select_lex_unit *new_unit); + + void register_select_chain(SELECT_LEX *first_sel); + + bool set_nest_level(int new_nest_level); + bool check_parameters(SELECT_LEX *main_select); + + friend class st_select_lex; }; typedef class st_select_lex_unit SELECT_LEX_UNIT; @@ -922,6 +981,7 @@ public: SQL_I_List<ORDER> order_list; /* ORDER clause */ SQL_I_List<ORDER> gorder_list; Item *select_limit, *offset_limit; /* LIMIT clause parameters */ + bool is_set_query_expr_tail; /// Array of pointers to top elements of all_fields list Ref_ptr_array ref_pointer_array; @@ -1051,6 +1111,10 @@ public: void init_query(); void init_select(); st_select_lex_unit* master_unit() { return (st_select_lex_unit*) master; } + inline void set_master_unit(st_select_lex_unit *master_unit) + { + master= (st_select_lex_node *)master_unit; + } st_select_lex_unit* first_inner_unit() { return (st_select_lex_unit*) slave; @@ -1283,6 +1347,32 @@ public: DBUG_ASSERT(this != sel); select_n_where_fields+= sel->select_n_where_fields; } + inline void set_linkage_and_distinct(enum sub_select_type l, bool d) + { + DBUG_ENTER("SELECT_LEX::set_linkage_and_distinct"); + DBUG_PRINT("info", ("select: %p distinct %d", this, d)); + set_linkage(l); + DBUG_ASSERT(l == UNION_TYPE || + l == INTERSECT_TYPE || + l == EXCEPT_TYPE); + if (d && master_unit() && master_unit()->union_distinct != this) + master_unit()->union_distinct= this; + distinct= d; + DBUG_VOID_RETURN; + } + bool set_nest_level(int new_nest_level); + bool check_parameters(SELECT_LEX *main_select); + void mark_select() + { + DBUG_ENTER("st_select_lex::mark_select()"); + DBUG_PRINT("info", ("Select #%d", select_number)); + DBUG_VOID_RETURN; + } + void register_unit(SELECT_LEX_UNIT *unit, + Name_resolution_context *outer_context); + SELECT_LEX_UNIT *attach_selects_chain(SELECT_LEX *sel, + Name_resolution_context *context); + void add_statistics(SELECT_LEX_UNIT *unit); }; typedef class st_select_lex SELECT_LEX; @@ -2664,7 +2754,8 @@ class Query_arena_memroot; struct LEX: public Query_tables_list { SELECT_LEX_UNIT unit; /* most upper unit */ - SELECT_LEX select_lex; /* first SELECT_LEX */ + inline SELECT_LEX *first_select_lex() {return unit.first_select();} + SELECT_LEX builtin_select; /* current SELECT_LEX in parsing */ SELECT_LEX *current_select; /* list of all SELECT_LEX */ @@ -2774,6 +2865,9 @@ public: required a local context, the parser pops the top-most context. */ List<Name_resolution_context> context_stack; + List<SELECT_LEX> last_select_stack; + SELECT_LEX *select_stack[MAX_SELECT_NESTING]; + uint select_stack_top; SQL_I_List<ORDER> proc_list; SQL_I_List<TABLE_LIST> auxiliary_table_list, save_list; @@ -2813,6 +2907,8 @@ public: syntax error back. */ bool expr_allows_subselect; + bool selects_allow_into; + bool selects_allow_procedure; /* A special command "PARSE_VCOL_EXPR" is defined for the parser to translate a defining expression of a virtual column into an @@ -2867,6 +2963,8 @@ public: enum enum_yes_no_unknown tx_chain, tx_release; bool safe_to_cache_query; bool subqueries, ignore; + bool next_is_main; // use "main" SELECT_LEX for nrxt allocation; + bool next_is_down; // use "main" SELECT_LEX for nrxt allocation; st_parsing_options parsing_options; Alter_info alter_info; /* @@ -3068,20 +3166,24 @@ public: SELECT_LEX *sl; SELECT_LEX_UNIT *un; for (sl= current_select, un= sl->master_unit(); - un != &unit; - sl= sl->outer_select(), un= sl->master_unit()) + un && un != &unit; + sl= sl->outer_select(), un= (sl ? sl->master_unit() : NULL)) { - sl->uncacheable|= cause; - un->uncacheable|= cause; + sl->uncacheable|= cause; + un->uncacheable|= cause; } - select_lex.uncacheable|= cause; + if (sl) + sl->uncacheable|= cause; } + if (first_select_lex()) + first_select_lex()->uncacheable|= cause; } void set_trg_event_type_for_tables(); TABLE_LIST *unlink_first_table(bool *link_to_local); void link_first_table_back(TABLE_LIST *first, bool link_to_local); void first_lists_tables_same(); + void fix_first_select_number(); bool can_be_merged(); bool can_use_merged(); @@ -3119,14 +3221,90 @@ public: void cleanup_after_one_table_open(); - bool push_context(Name_resolution_context *context, MEM_ROOT *mem_root) + bool push_context(Name_resolution_context *context); + + void pop_context() { - return context_stack.push_front(context, mem_root); + DBUG_ENTER("LEX::pop_context"); + Name_resolution_context *context= context_stack.pop(); + DBUG_PRINT("info", ("Pop context %p Select: %p (%d)", + context, context->select_lex, + (context->select_lex ? + context->select_lex->select_number: + 0))); + DBUG_VOID_RETURN; } - void pop_context() + bool push_new_select(SELECT_LEX *last); + + SELECT_LEX *pop_new_select() + { + DBUG_ENTER("LEX::pop_new_select"); + SELECT_LEX* last= last_select_stack.pop(); + DBUG_PRINT("info", ("Pop last elect: %p (%d)", + last, last->select_number)); + DBUG_RETURN(last); + } + + SELECT_LEX *select_stack_head() + { + if (likely(select_stack_top)) + return select_stack[select_stack_top - 1]; + return NULL; + } + + + bool push_select(SELECT_LEX *select_lex) + { + DBUG_ENTER("LEX::push_select"); + DBUG_PRINT("info", ("Top Select was %p (%d) depth: %u pushed: %p (%d)", + select_stack_head(), + select_stack_top, + (select_stack_top ? + select_stack_head()->select_number : + 0), + select_lex, select_lex->select_number)); + if (unlikely(select_stack_top == MAX_SELECT_NESTING)) + { + my_error(ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT, MYF(0)); + DBUG_RETURN(TRUE); + } + if (push_context(&select_lex->context)) + DBUG_RETURN(TRUE); + select_stack[select_stack_top++]= select_lex; + current_select= select_lex; + DBUG_RETURN(FALSE); + } + + SELECT_LEX *pop_select() { - context_stack.pop(); + DBUG_ENTER("LEX::pop_select"); + SELECT_LEX *select_lex; + if (likely(select_stack_top)) + select_lex= select_stack[--select_stack_top]; + else + select_lex= 0; + DBUG_PRINT("info", ("Top Select is %p (%d) depth: %u poped: %p (%d)", + select_stack_head(), + select_stack_top, + (select_stack_top ? + select_stack_head()->select_number : + 0), + select_lex, + (select_lex ? select_lex->select_number : 0))); + DBUG_ASSERT(select_lex); + + pop_context(); + + if (unlikely(!select_stack_top)) + { + current_select= NULL; + DBUG_PRINT("info", ("Top Select is empty")); + } + else + current_select= select_stack[select_stack_top - 1]; + + DBUG_RETURN(select_lex); } bool copy_db_to(LEX_CSTRING *to); @@ -3160,9 +3338,8 @@ public: on its top. So select_lex (as the first added) will be at the tail of the list. */ - if (&select_lex == all_selects_list && !sroutines.records) + if (first_select_lex() == all_selects_list && !sroutines.records) { - DBUG_ASSERT(!all_selects_list->next_select_in_list()); return TRUE; } return FALSE; @@ -3731,6 +3908,7 @@ public: bool if_exists() const { return create_info.if_exists(); } SELECT_LEX *exclude_last_select(); + SELECT_LEX *exclude_not_first_select(SELECT_LEX *exclude); bool add_unit_in_brackets(SELECT_LEX *nselect); void check_automatic_up(enum sub_select_type type); bool create_or_alter_view_finalize(THD *thd, Table_ident *table_ident); @@ -3739,7 +3917,6 @@ public: bool add_create_view(THD *thd, DDL_options_st ddl, uint16 algorithm, enum_view_suid suid, Table_ident *table_ident); - bool add_grant_command(THD *thd, enum_sql_command sql_command_arg, stored_procedure_type type_arg); @@ -3748,6 +3925,31 @@ public: return create_info.vers_info; } sp_package *get_sp_package() const; + + bool make_select_in_brackets(SELECT_LEX* dummy_select, + SELECT_LEX *nselect, bool automatic); + + SELECT_LEX_UNIT *alloc_unit(); + SELECT_LEX *alloc_select(bool is_select); + SELECT_LEX_UNIT *create_unit(SELECT_LEX*); + SELECT_LEX *wrap_unit_into_derived(SELECT_LEX_UNIT *unit); + SELECT_LEX *link_selects_chain_down(SELECT_LEX *sel); + bool main_select_push(); + bool insert_select_hack(SELECT_LEX *sel); + SELECT_LEX *pop_new_select_and_wrap(); + + void set_main_unit(st_select_lex_unit *u) + { + unit.options= u->options; + unit.uncacheable= u->uncacheable; + unit.register_select_chain(u->first_select()); + unit.first_select()->options|= builtin_select.options; + unit.fake_select_lex= u->fake_select_lex; + unit.union_distinct= u->union_distinct; + unit.set_with_clause(u->with_clause); + builtin_select.exclude_from_global(); + } + bool check_main_unit_semantics(); }; diff --git a/sql/sql_load.cc b/sql/sql_load.cc index cfa92f170ab..c81a8203be9 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -390,10 +390,13 @@ int mysql_load(THD *thd, const sql_exchange *ex, TABLE_LIST *table_list, if (mysql_handle_single_derived(thd->lex, table_list, DT_MERGE_FOR_INSERT) || mysql_handle_single_derived(thd->lex, table_list, DT_PREPARE)) DBUG_RETURN(TRUE); - if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context, - &thd->lex->select_lex.top_join_list, + if (setup_tables_and_check_access(thd, + &thd->lex->first_select_lex()->context, + &thd->lex->first_select_lex()-> + top_join_list, table_list, - thd->lex->select_lex.leaf_tables, FALSE, + thd->lex->first_select_lex()->leaf_tables, + FALSE, INSERT_ACL | UPDATE_ACL, INSERT_ACL | UPDATE_ACL, FALSE)) DBUG_RETURN(-1); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f85d25525d4..d2a4a7a1e9a 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1999,10 +1999,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd, Init TABLE_LIST members necessary when the undelrying table is view. */ - table_list.select_lex= &(thd->lex->select_lex); + table_list.select_lex= thd->lex->first_select_lex(); thd->lex-> - select_lex.table_list.link_in_list(&table_list, - &table_list.next_local); + first_select_lex()->table_list.link_in_list(&table_list, + &table_list.next_local); thd->lex->add_to_query_tables(&table_list); if (is_infoschema_db(&table_list.db)) @@ -2565,23 +2565,24 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, DBUG_RETURN(1); #else { - if (lex->select_lex.db.str == NULL && - lex->copy_db_to(&lex->select_lex.db)) + if (lex->first_select_lex()->db.str == NULL && + lex->copy_db_to(&lex->first_select_lex()->db)) { DBUG_RETURN(1); } schema_select_lex= new (thd->mem_root) SELECT_LEX(); schema_select_lex->table_list.first= NULL; if (lower_case_table_names == 1) - lex->select_lex.db.str= thd->strdup(lex->select_lex.db.str); - schema_select_lex->db= lex->select_lex.db; + lex->first_select_lex()->db.str= + thd->strdup(lex->first_select_lex()->db.str); + schema_select_lex->db= lex->first_select_lex()->db; /* check_db_name() may change db.str if lower_case_table_names == 1, but that's ok as the db is allocted above in this case. */ - if (check_db_name((LEX_STRING*) &lex->select_lex.db)) + if (check_db_name((LEX_STRING*) &lex->first_select_lex()->db)) { - my_error(ER_WRONG_DB_NAME, MYF(0), lex->select_lex.db.str); + my_error(ER_WRONG_DB_NAME, MYF(0), lex->first_select_lex()->db.str); DBUG_RETURN(1); } break; @@ -2620,7 +2621,8 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, default: break; } - + if (schema_select_lex) + schema_select_lex->set_master_unit(&lex->unit); SELECT_LEX *select_lex= lex->current_select; if (make_schema_select(thd, select_lex, get_schema_table(schema_table_idx))) DBUG_RETURN(1); @@ -3217,7 +3219,7 @@ mysql_execute_command(THD *thd) int up_result= 0; LEX *lex= thd->lex; /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */ - SELECT_LEX *select_lex= &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); /* first table of first SELECT_LEX */ TABLE_LIST *first_table= select_lex->table_list.first; /* list of all tables in query */ @@ -3260,6 +3262,7 @@ mysql_execute_command(THD *thd) DBUG_ASSERT(first_table == all_tables && first_table != 0); */ lex->first_lists_tables_same(); + lex->fix_first_select_number(); /* should be assigned after making first tables same */ all_tables= lex->query_tables; /* set context for commands which do not use setup_tables */ @@ -7530,7 +7533,7 @@ void THD::reset_for_next_command(bool do_clear_error) We also assign stmt_lex in lex_start(), but during bootstrap this code is executed first. */ - stmt_lex= &main_lex; stmt_lex->current_select_number= 1; + stmt_lex= &main_lex; stmt_lex->current_select_number= 0; DBUG_PRINT("info", ("Lex %p stmt_lex: %p", lex, stmt_lex)); /* Those two lines below are theoretically unneeded as @@ -7617,11 +7620,7 @@ mysql_init_select(LEX *lex) SELECT_LEX *select_lex= lex->current_select; select_lex->init_select(); lex->wild= 0; - if (select_lex == &lex->select_lex) - { - DBUG_ASSERT(lex->result == 0); - lex->exchange= 0; - } + lex->exchange= 0; } @@ -7642,6 +7641,7 @@ mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *select_lex) { THD *thd= lex->thd; bool new_select= select_lex == NULL; + int old_nest_level= lex->current_select->nest_level; DBUG_ENTER("mysql_new_select"); if (new_select) @@ -7653,27 +7653,19 @@ mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *select_lex) select_lex->init_query(); select_lex->init_select(); } - lex->nest_level++; - if (lex->nest_level > (int) MAX_SELECT_NESTING) - { - my_error(ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT, MYF(0)); - DBUG_RETURN(1); - } - select_lex->nest_level= lex->nest_level; select_lex->nest_level_base= &thd->lex->unit; if (move_down) { + lex->nest_level++; + if (select_lex->set_nest_level(old_nest_level + 1)) + DBUG_RETURN(1); SELECT_LEX_UNIT *unit; lex->subqueries= TRUE; /* first select_lex of subselect or derived table */ - if (!(unit= new (thd->mem_root) SELECT_LEX_UNIT())) + if (!(unit= lex->alloc_unit())) DBUG_RETURN(1); - unit->init_query(); - unit->thd= thd; unit->include_down(lex->current_select); - unit->link_next= 0; - unit->link_prev= 0; unit->return_to= lex->current_select; select_lex->include_down(unit); /* @@ -7707,15 +7699,13 @@ mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *select_lex) "SELECT ... PROCEDURE ANALYSE()"); DBUG_RETURN(TRUE); } - // SELECT 1 FROM t1 ORDER BY 1 UNION SELECT 1 FROM t1 -- not possible - DBUG_ASSERT(!lex->current_select->order_list.first || - lex->current_select->braces); - // SELECT 1 FROM t1 LIMIT 1 UNION SELECT 1 FROM t1; -- not possible - DBUG_ASSERT(!lex->current_select->explicit_limit || - lex->current_select->braces); + SELECT_LEX_NODE *save_slave= select_lex->slave; select_lex->include_neighbour(lex->current_select); - SELECT_LEX_UNIT *unit= select_lex->master_unit(); + select_lex->slave= save_slave; + SELECT_LEX_UNIT *unit= select_lex->master_unit(); + if (select_lex->set_nest_level(old_nest_level)) + DBUG_RETURN(1); if (!unit->fake_select_lex && unit->add_fake_select_lex(lex->thd)) DBUG_RETURN(1); select_lex->context.outer_context= @@ -7771,9 +7761,10 @@ void mysql_init_multi_delete(LEX *lex) { lex->sql_command= SQLCOM_DELETE_MULTI; mysql_init_select(lex); - lex->select_lex.select_limit= 0; + lex->first_select_lex()->select_limit= 0; lex->unit.select_limit_cnt= HA_POS_ERROR; - lex->select_lex.table_list.save_and_clear(&lex->auxiliary_table_list); + lex->first_select_lex()->table_list. + save_and_clear(&lex->auxiliary_table_list); lex->query_tables= 0; lex->query_tables_last= &lex->query_tables; } @@ -8058,7 +8049,7 @@ bool mysql_test_parse_for_slave(THD *thd, char *rawbuf, uint length) thd->reset_for_next_command(); if (!parse_sql(thd, & parser_state, NULL, true) && - all_tables_not_ok(thd, lex->select_lex.table_list.first)) + all_tables_not_ok(thd, lex->first_select_lex()->table_list.first)) error= 1; /* Ignore question */ thd->end_statement(); } @@ -8140,6 +8131,10 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, LEX_CSTRING alias_str; LEX *lex= thd->lex; DBUG_ENTER("add_table_to_list"); + DBUG_PRINT("enter", ("Table '%s' (%p) Select %p (%u)", + (alias ? alias->str : table->table.str), + table, + this, select_number)); if (!table) DBUG_RETURN(0); // End of memory @@ -8233,7 +8228,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, ptr->schema_table_name= ptr->table_name; ptr->schema_table= schema_table; } - ptr->select_lex= lex->current_select; + ptr->select_lex= this; /* We can't cache internal temporary tables between prepares as the table may be deleted before next exection. @@ -8339,7 +8334,6 @@ bool st_select_lex::init_nested_join(THD *thd) nested_join= ptr->nested_join= ((NESTED_JOIN*) ((uchar*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST)))); - join_list->push_front(ptr, thd->mem_root); ptr->embedding= embedding; ptr->join_list= join_list; ptr->alias.str="(nested_join)"; @@ -8447,7 +8441,6 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd) ptr->join_using_fields= prev_join_using; } } - join_list->push_front(ptr, thd->mem_root); nested_join->used_tables= nested_join->not_null_tables= (table_map) 0; DBUG_RETURN(ptr); } @@ -8639,7 +8632,7 @@ void st_select_lex::set_lock_for_tables(thr_lock_type lock_type) bool st_select_lex_unit::add_fake_select_lex(THD *thd_arg) { SELECT_LEX *first_sl= first_select(); - DBUG_ENTER("add_fake_select_lex"); + DBUG_ENTER("st_select_lex_unit::add_fake_select_lex"); DBUG_ASSERT(!fake_select_lex); if (!(fake_select_lex= new (thd_arg->mem_root) SELECT_LEX())) @@ -8649,16 +8642,19 @@ bool st_select_lex_unit::add_fake_select_lex(THD *thd_arg) fake_select_lex->select_number= INT_MAX; fake_select_lex->parent_lex= thd_arg->lex; /* Used in init_query. */ fake_select_lex->make_empty_select(); - fake_select_lex->linkage= GLOBAL_OPTIONS_TYPE; + fake_select_lex->set_linkage(GLOBAL_OPTIONS_TYPE); fake_select_lex->select_limit= 0; + fake_select_lex->no_table_names_allowed= 1; + fake_select_lex->context.outer_context=first_sl->context.outer_context; /* allow item list resolving in fake select for ORDER BY */ fake_select_lex->context.resolve_in_select_list= TRUE; fake_select_lex->context.select_lex= fake_select_lex; fake_select_lex->nest_level_base= first_select()->nest_level_base; - fake_select_lex->nest_level=first_select()->nest_level; + if (fake_select_lex->set_nest_level(first_select()->nest_level)) + DBUG_RETURN(1); if (!is_unit_op()) { @@ -8671,7 +8667,7 @@ bool st_select_lex_unit::add_fake_select_lex(THD *thd_arg) fake_select_lex->no_table_names_allowed= 1; thd_arg->lex->current_select= fake_select_lex; } - thd_arg->lex->pop_context(); + //thd_arg->lex->pop_context("add fake"); DBUG_RETURN(0); } @@ -8707,7 +8703,7 @@ push_new_name_resolution_context(THD *thd, left_op->first_leaf_for_name_resolution(); on_context->last_name_resolution_table= right_op->last_leaf_for_name_resolution(); - return thd->lex->push_context(on_context, thd->mem_root); + return thd->lex->push_context(on_context); } @@ -9062,7 +9058,7 @@ bool check_simple_select() { THD *thd= current_thd; LEX *lex= thd->lex; - if (lex->current_select != &lex->select_lex) + if (lex->current_select != lex->first_select_lex()) { char command[80]; Lex_input_stream *lip= & thd->m_parser_state->m_lip; @@ -9161,7 +9157,7 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables) { TABLE_LIST *table; LEX *lex= thd->lex; - SELECT_LEX *select_lex= &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); DBUG_ENTER("multi_update_precheck"); if (select_lex->item_list.elements != lex->value_list.elements) @@ -9197,7 +9193,7 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables) /* Is there tables of subqueries? */ - if (&lex->select_lex != lex->all_selects_list) + if (lex->first_select_lex() != lex->all_selects_list) { DBUG_PRINT("info",("Checking sub query list")); for (table= tables; table; table= table->next_global) @@ -9231,7 +9227,7 @@ bool multi_update_precheck(THD *thd, TABLE_LIST *tables) bool multi_delete_precheck(THD *thd, TABLE_LIST *tables) { - SELECT_LEX *select_lex= &thd->lex->select_lex; + SELECT_LEX *select_lex= thd->lex->first_select_lex(); TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first; TABLE_LIST **save_query_tables_own_last= thd->lex->query_tables_own_last; DBUG_ENTER("multi_delete_precheck"); @@ -9348,7 +9344,7 @@ static TABLE_LIST *multi_delete_table_match(LEX *lex, TABLE_LIST *tbl, bool multi_delete_set_locks_and_link_aux_tables(LEX *lex) { - TABLE_LIST *tables= lex->select_lex.table_list.first; + TABLE_LIST *tables= lex->first_select_lex()->table_list.first; TABLE_LIST *target_tbl; DBUG_ENTER("multi_delete_set_locks_and_link_aux_tables"); @@ -9390,7 +9386,8 @@ bool multi_delete_set_locks_and_link_aux_tables(LEX *lex) bool update_precheck(THD *thd, TABLE_LIST *tables) { DBUG_ENTER("update_precheck"); - if (thd->lex->select_lex.item_list.elements != thd->lex->value_list.elements) + if (thd->lex->first_select_lex()->item_list.elements != + thd->lex->value_list.elements) { my_message(ER_WRONG_VALUE_COUNT, ER_THD(thd, ER_WRONG_VALUE_COUNT), MYF(0)); DBUG_RETURN(TRUE); @@ -9481,7 +9478,7 @@ void create_table_set_open_action_and_adjust_tables(LEX *lex) else create_table->open_type= OT_BASE_ONLY; - if (!lex->select_lex.item_list.elements) + if (!lex->first_select_lex()->item_list.elements) { /* Avoid opening and locking target table for ordinary CREATE TABLE @@ -9512,7 +9509,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *create_table) { LEX *lex= thd->lex; - SELECT_LEX *select_lex= &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); ulong want_priv; bool error= TRUE; // Error message is given DBUG_ENTER("create_table_precheck"); @@ -10022,6 +10019,8 @@ bool parse_sql(THD *thd, Parser_state *parser_state, ((thd->variables.sql_mode & MODE_ORACLE) ? ORAparse(thd) : MYSQLparse(thd)) != 0; + DBUG_ASSERT(opt_bootstrap | mysql_parse_status || thd->lex->select_stack_top == 0); + thd->lex->current_select= thd->lex->first_select_lex(); /* Check that if MYSQLparse() failed either thd->is_error() is set, or an diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 09c59c862ad..ef226526e8c 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -833,7 +833,8 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, goto end; table->get_fields_in_item_tree= true; - func_expr->walk(&Item::change_context_processor, 0, &lex.select_lex.context); + func_expr->walk(&Item::change_context_processor, 0, + &lex.first_select_lex()->context); thd->where= "partition function"; /* In execution we must avoid the use of thd->change_item_tree since diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc index 6e176a40e6c..b4a42dd6bb2 100644 --- a/sql/sql_partition_admin.cc +++ b/sql/sql_partition_admin.cc @@ -51,7 +51,7 @@ bool Sql_cmd_alter_table_exchange_partition::execute(THD *thd) /* Moved from mysql_execute_command */ LEX *lex= thd->lex; /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */ - SELECT_LEX *select_lex= &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); /* first table of first SELECT_LEX */ TABLE_LIST *first_table= (TABLE_LIST*) select_lex->table_list.first; /* @@ -735,7 +735,7 @@ bool Sql_cmd_alter_table_truncate_partition::execute(THD *thd) int error; ha_partition *partition; ulong timeout= thd->variables.lock_wait_timeout; - TABLE_LIST *first_table= thd->lex->select_lex.table_list.first; + TABLE_LIST *first_table= thd->lex->first_select_lex()->table_list.first; Alter_info *alter_info= &thd->lex->alter_info; uint table_counter, i; List<String> partition_names_list; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 24f3cc66c6b..bdc817b7432 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1340,7 +1340,7 @@ static int mysql_test_update(Prepared_statement *stmt, THD *thd= stmt->thd; uint table_count= 0; TABLE_LIST *update_source_table; - SELECT_LEX *select= &stmt->lex->select_lex; + SELECT_LEX *select= stmt->lex->first_select_lex(); #ifndef NO_EMBEDDED_ACCESS_CHECKS uint want_privilege; #endif @@ -1396,10 +1396,10 @@ static int mysql_test_update(Prepared_statement *stmt, table_list->table->grant.want_privilege= want_privilege; table_list->register_want_access(want_privilege); #endif - thd->lex->select_lex.no_wrap_view_item= TRUE; + thd->lex->first_select_lex()->no_wrap_view_item= TRUE; res= setup_fields(thd, Ref_ptr_array(), select->item_list, MARK_COLUMNS_READ, 0, NULL, 0); - thd->lex->select_lex.no_wrap_view_item= FALSE; + thd->lex->first_select_lex()->no_wrap_view_item= FALSE; if (res) goto error; #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -1464,10 +1464,10 @@ static bool mysql_test_delete(Prepared_statement *stmt, goto error; } - DBUG_RETURN(mysql_prepare_delete(thd, table_list, - lex->select_lex.with_wild, - lex->select_lex.item_list, - &lex->select_lex.where, + DBUG_RETURN(mysql_prepare_delete(thd, table_list, + lex->first_select_lex()->with_wild, + lex->first_select_lex()->item_list, + &lex->first_select_lex()->where, &delete_while_scanning)); error: DBUG_RETURN(TRUE); @@ -1499,7 +1499,7 @@ static int mysql_test_select(Prepared_statement *stmt, SELECT_LEX_UNIT *unit= &lex->unit; DBUG_ENTER("mysql_test_select"); - lex->select_lex.context.resolve_in_select_list= TRUE; + lex->first_select_lex()->context.resolve_in_select_list= TRUE; ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL; if (tables) @@ -1533,7 +1533,7 @@ static int mysql_test_select(Prepared_statement *stmt, if (!lex->describe && !thd->lex->analyze_stmt && !stmt->is_sql_prepare()) { /* Make copy of item list, as change_columns may change it */ - List<Item> fields(lex->select_lex.item_list); + List<Item> fields(lex->first_select_lex()->item_list); /* Change columns if a procedure like analyse() */ if (unit->last_procedure && unit->last_procedure->change_columns(thd, fields)) @@ -1691,7 +1691,7 @@ static bool select_like_stmt_test(Prepared_statement *stmt, THD *thd= stmt->thd; LEX *lex= stmt->lex; - lex->select_lex.context.resolve_in_select_list= TRUE; + lex->first_select_lex()->context.resolve_in_select_list= TRUE; if (specific_prepare && (*specific_prepare)(thd)) DBUG_RETURN(TRUE); @@ -1759,7 +1759,7 @@ static bool mysql_test_create_table(Prepared_statement *stmt) DBUG_ENTER("mysql_test_create_table"); THD *thd= stmt->thd; LEX *lex= stmt->lex; - SELECT_LEX *select_lex= &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); bool res= FALSE; bool link_to_local; TABLE_LIST *create_table= lex->query_tables; @@ -2079,7 +2079,7 @@ static bool mysql_test_multidelete(Prepared_statement *stmt, { THD *thd= stmt->thd; - thd->lex->current_select= &thd->lex->select_lex; + thd->lex->current_select= thd->lex->first_select_lex(); if (add_item_to_list(thd, new (thd->mem_root) Item_null(thd))) { @@ -2118,13 +2118,14 @@ error: static int mysql_insert_select_prepare_tester(THD *thd) { - SELECT_LEX *first_select= &thd->lex->select_lex; + SELECT_LEX *first_select= thd->lex->first_select_lex(); TABLE_LIST *second_table= first_select->table_list.first->next_local; /* Skip first table, which is the table we are inserting in */ first_select->table_list.first= second_table; - thd->lex->select_lex.context.table_list= - thd->lex->select_lex.context.first_name_resolution_table= second_table; + thd->lex->first_select_lex()->context.table_list= + thd->lex->first_select_lex()->context.first_name_resolution_table= + second_table; return mysql_insert_select_prepare(thd); } @@ -2159,7 +2160,7 @@ static bool mysql_test_insert_select(Prepared_statement *stmt, return 1; /* store it, because mysql_insert_select_prepare_tester change it */ - first_local_table= lex->select_lex.table_list.first; + first_local_table= lex->first_select_lex()->table_list.first; DBUG_ASSERT(first_local_table != 0); res= @@ -2167,7 +2168,7 @@ static bool mysql_test_insert_select(Prepared_statement *stmt, &mysql_insert_select_prepare_tester, OPTION_SETUP_TABLES_DONE); /* revert changes made by mysql_insert_select_prepare_tester */ - lex->select_lex.table_list.first= first_local_table; + lex->first_select_lex()->table_list.first= first_local_table; return res; } @@ -2193,7 +2194,7 @@ static int mysql_test_handler_read(Prepared_statement *stmt, SQL_HANDLER *ha_table; DBUG_ENTER("mysql_test_handler_read"); - lex->select_lex.context.resolve_in_select_list= TRUE; + lex->first_select_lex()->context.resolve_in_select_list= TRUE; /* We don't have to test for permissions as this is already done during @@ -2202,7 +2203,7 @@ static int mysql_test_handler_read(Prepared_statement *stmt, if (!(ha_table= mysql_ha_read_prepare(thd, tables, lex->ha_read_mode, lex->ident.str, lex->insert_list, - lex->select_lex.where))) + lex->first_select_lex()->where))) DBUG_RETURN(1); if (!stmt->is_sql_prepare()) @@ -2241,7 +2242,7 @@ static bool check_prepared_statement(Prepared_statement *stmt) { THD *thd= stmt->thd; LEX *lex= stmt->lex; - SELECT_LEX *select_lex= &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); TABLE_LIST *tables; enum enum_sql_command sql_command= lex->sql_command; int res= 0; @@ -2250,10 +2251,11 @@ static bool check_prepared_statement(Prepared_statement *stmt) sql_command, stmt->param_count)); lex->first_lists_tables_same(); + lex->fix_first_select_number(); tables= lex->query_tables; /* set context for commands which do not use setup_tables */ - lex->select_lex.context.resolve_in_table_list_only(select_lex-> + lex->first_select_lex()->context.resolve_in_table_list_only(select_lex-> get_table_list()); /* Reset warning count for each query that uses tables */ @@ -2999,7 +3001,7 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) { tables->reinit_before_use(thd); } - lex->current_select= &lex->select_lex; + lex->current_select= lex->first_select_lex(); if (lex->result) @@ -4535,8 +4537,8 @@ bool Prepared_statement::validate_metadata(Prepared_statement *copy) if (is_sql_prepare() || lex->describe) return FALSE; - if (lex->select_lex.item_list.elements != - copy->lex->select_lex.item_list.elements) + if (lex->first_select_lex()->item_list.elements != + copy->lex->first_select_lex()->item_list.elements) { /** Column counts mismatch, update the client */ thd->server_status|= SERVER_STATUS_METADATA_CHANGED; diff --git a/sql/sql_priv.h b/sql/sql_priv.h index ba37d933f12..4de8b8c9961 100644 --- a/sql/sql_priv.h +++ b/sql/sql_priv.h @@ -184,6 +184,9 @@ #define OPTION_SKIP_REPLICATION (1ULL << 37) // THD, user #define OPTION_RPL_SKIP_PARALLEL (1ULL << 38) #define OPTION_FOUND_COMMENT (1ULL << 39) // SELECT, intern, parser +#define OPTION_NO_QUERY_CACHE (1ULL << 40) // SELECT, user +#define OPTION_INTO_CLAUSE (1ULL << 41) // Internal usage +#define OPTION_PROCEDURE_CLAUSE (1ULL << 42) // Internal usage /* The rest of the file is included in the server only */ #ifndef MYSQL_CLIENT @@ -356,6 +359,8 @@ enum enum_parsing_place IN_ORDER_BY, IN_UPDATE_ON_DUP_KEY, IN_PART_FUNC, + BEFORE_OPT_LIST, + AFTER_LIST, PARSING_PLACE_SIZE /* always should be the last */ }; diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 13f03fed5f3..6ca21aebb37 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -110,7 +110,7 @@ int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table) }; ST_FIELD_INFO *field_info; - Name_resolution_context *context= &thd->lex->select_lex.context; + Name_resolution_context *context= &thd->lex->first_select_lex()->context; int i; for (i= 0; schema_table->fields_info[i].field_name != NULL; i++) @@ -402,7 +402,7 @@ bool PROFILING::show_profiles() QUERY_PROFILE *prof; List<Item> field_list; MEM_ROOT *mem_root= thd->mem_root; - SELECT_LEX *sel= &thd->lex->select_lex; + SELECT_LEX *sel= thd->lex->first_select_lex(); SELECT_LEX_UNIT *unit= &thd->lex->unit; ha_rows idx= 0; Protocol *protocol= thd->protocol; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 796ea569e64..8695d227b14 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -351,7 +351,7 @@ bool handle_select(THD *thd, LEX *lex, select_result *result, ulong setup_tables_done_option) { bool res; - register SELECT_LEX *select_lex = &lex->select_lex; + register SELECT_LEX *select_lex= lex->first_select_lex(); DBUG_ENTER("handle_select"); MYSQL_SELECT_START(thd->query()); @@ -1388,13 +1388,14 @@ err: bool JOIN::build_explain() { + DBUG_ENTER("JOIN::build_explain"); create_explain_query_if_not_exists(thd->lex, thd->mem_root); have_query_plan= QEP_AVAILABLE; if (save_explain_data(thd->lex->explain, false /* can overwrite */, need_tmp, !skip_sort_order && !no_order && (order || group_list), select_distinct)) - return 1; + DBUG_RETURN(1); uint select_nr= select_lex->select_number; JOIN_TAB *curr_tab= join_tab + exec_join_tab_cnt(); for (uint i= 0; i < aggr_tables; i++, curr_tab++) @@ -1412,7 +1413,7 @@ bool JOIN::build_explain() get_using_temporary_read_tracker(); } } - return 0; + DBUG_RETURN(0); } @@ -3678,6 +3679,15 @@ bool JOIN::save_explain_data(Explain_query *output, bool can_overwrite, bool need_tmp_table, bool need_order, bool distinct) { + DBUG_ENTER("JOIN::save_explain_data"); + DBUG_PRINT("enter", ("Save explain Select_lex: %u (%p) parent lex: %p stmt_lex: %p present select: %u (%p)", + select_lex->select_number, select_lex, + select_lex->parent_lex, thd->stmt_lex, + (output->get_select(select_lex->select_number) ? + select_lex->select_number : 0), + (output->get_select(select_lex->select_number) ? + output->get_select(select_lex->select_number) + ->select_lex : NULL))); /* If there is SELECT in this statemet with the same number it must be the same SELECT @@ -3704,8 +3714,9 @@ bool JOIN::save_explain_data(Explain_query *output, bool can_overwrite, /* It's a degenerate join */ message= zero_result_cause ? zero_result_cause : "No tables used"; } - return save_explain_data_intern(thd->lex->explain, need_tmp_table, need_order, - distinct, message); + bool rc= save_explain_data_intern(thd->lex->explain, need_tmp_table, + need_order, distinct, message); + DBUG_RETURN(rc); } /* @@ -3727,11 +3738,11 @@ bool JOIN::save_explain_data(Explain_query *output, bool can_overwrite, { if (!(join_tab[i].filesort->tracker= new Filesort_tracker(thd->lex->analyze_stmt))) - return 1; + DBUG_RETURN(1); } } } - return 0; + DBUG_RETURN(0); } @@ -12574,7 +12585,8 @@ void JOIN::join_free() !(select_options & SELECT_NO_UNLOCK) && !select_lex->subquery_in_having && (select_lex == (thd->lex->unit.fake_select_lex ? - thd->lex->unit.fake_select_lex : &thd->lex->select_lex))) + thd->lex->unit.fake_select_lex : + thd->lex->first_select_lex()))) { /* TODO: unlock tables even if the join isn't top level select in the @@ -18386,7 +18398,7 @@ create_internal_tmp_table_from_heap(THD *thd, TABLE *table, new_table.no_rows= table->no_rows; if (create_internal_tmp_table(&new_table, table->key_info, start_recinfo, recinfo, - thd->lex->select_lex.options | + thd->lex->builtin_select.options | thd->variables.option_bits)) goto err2; if (open_tmp_table(&new_table)) @@ -24902,7 +24914,8 @@ bool JOIN_TAB::save_explain_data(Explain_table_access *eta, */ if (real_table->merged_for_insert) { - TABLE_LIST *view_child= real_table->view->select_lex.table_list.first; + TABLE_LIST *view_child= + real_table->view->first_select_lex()->table_list.first; for (;view_child; view_child= view_child->next_local) { if (view_child->table == table) @@ -25355,8 +25368,9 @@ int JOIN::save_explain_data_intern(Explain_query *output, { JOIN *join= this; /* Legacy: this code used to be a non-member function */ DBUG_ENTER("JOIN::save_explain_data_intern"); - DBUG_PRINT("info", ("Select %p, type %s, message %s", - join->select_lex, join->select_lex->type, + DBUG_PRINT("info", ("Select %p (%u), type %s, message %s", + join->select_lex, join->select_lex->select_number, + join->select_lex->type, message ? message : "NULL")); DBUG_ASSERT(have_query_plan == QEP_AVAILABLE); /* fake_select_lex is created/printed by Explain_union */ @@ -26010,6 +26024,18 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) { str->append("/* select#"); str->append_ulonglong(select_number); + if (thd->lex->describe & DESCRIBE_EXTENDED2) + { + str->append("/"); + str->append_ulonglong(nest_level); + + if (master_unit()->fake_select_lex && + master_unit()->first_select() == this) + { + str->append(" Filter Select: "); + master_unit()->fake_select_lex->print(thd, str, query_type); + } + } str->append(" */ "); } diff --git a/sql/sql_sequence.cc b/sql/sql_sequence.cc index 18f0028908f..1ee20785e9c 100644 --- a/sql/sql_sequence.cc +++ b/sql/sql_sequence.cc @@ -220,8 +220,8 @@ bool check_sequence_fields(LEX *lex, List<Create_field> *fields) err: my_error(ER_SEQUENCE_INVALID_TABLE_STRUCTURE, MYF(0), - lex->select_lex.table_list.first->db.str, - lex->select_lex.table_list.first->table_name.str, reason); + lex->first_select_lex()->table_list.first->db.str, + lex->first_select_lex()->table_list.first->table_name.str, reason); DBUG_RETURN(TRUE); } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 38a13c49278..fb7a023e817 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -4144,8 +4144,9 @@ bool get_lookup_field_values(THD *thd, COND *cond, TABLE_LIST *tables, case SQLCOM_SHOW_TABLE_STATUS: case SQLCOM_SHOW_TRIGGERS: case SQLCOM_SHOW_EVENTS: - thd->make_lex_string(&lookup_field_values->db_value, - lex->select_lex.db.str, lex->select_lex.db.length); + thd->make_lex_string(&lookup_field_values->db_value, + lex->first_select_lex()->db.str, + lex->first_select_lex()->db.length); if (wild) { thd->make_lex_string(&lookup_field_values->table_value, @@ -4538,10 +4539,10 @@ fill_schema_table_by_open(THD *thd, MEM_ROOT *mem_root, temporary LEX. The latter is required to correctly open views and produce table describing their structure. */ - if (make_table_list(thd, &lex->select_lex, &db_name, &table_name)) + if (make_table_list(thd, lex->first_select_lex(), &db_name, &table_name)) goto end; - table_list= lex->select_lex.table_list.first; + table_list= lex->first_select_lex()->table_list.first; if (is_show_fields_or_keys) { @@ -6746,7 +6747,7 @@ static int get_schema_views_record(THD *thd, TABLE_LIST *tables, & 'field_translation_end' are uninitialized is this case. */ - List<Item> *fields= &tables->view->select_lex.item_list; + List<Item> *fields= &tables->view->first_select_lex()->item_list; List_iterator<Item> it(*fields); Item *item; Item_field *field; @@ -7725,7 +7726,8 @@ int fill_open_tables(THD *thd, TABLE_LIST *tables, COND *cond) TABLE *table= tables->table; CHARSET_INFO *cs= system_charset_info; OPEN_TABLE_LIST *open_list; - if (!(open_list=list_open_tables(thd,thd->lex->select_lex.db.str, wild)) + if (!(open_list=list_open_tables(thd, thd->lex->first_select_lex()->db.str, + wild)) && thd->is_fatal_error) DBUG_RETURN(1); @@ -8220,7 +8222,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) tmp_table_param->table_charset= cs; tmp_table_param->field_count= field_count; tmp_table_param->schema_table= 1; - SELECT_LEX *select_lex= thd->lex->current_select; + SELECT_LEX *select_lex= table_list->select_lex; bool keep_row_order= is_show_command(thd); if (!(table= create_tmp_table(thd, tmp_table_param, field_list, (ORDER*) 0, 0, 0, @@ -8257,7 +8259,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) static int make_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) { ST_FIELD_INFO *field_info= schema_table->fields_info; - Name_resolution_context *context= &thd->lex->select_lex.context; + Name_resolution_context *context= &thd->lex->first_select_lex()->context; for (; field_info->field_name; field_info++) { if (field_info->old_name) @@ -8317,14 +8319,14 @@ int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) char tmp[128]; String buffer(tmp,sizeof(tmp), thd->charset()); LEX *lex= thd->lex; - Name_resolution_context *context= &lex->select_lex.context; + Name_resolution_context *context= &lex->first_select_lex()->context; ST_FIELD_INFO *field_info= &schema_table->fields_info[2]; LEX_CSTRING field_name= {field_info->field_name, strlen(field_info->field_name) }; buffer.length(0); buffer.append(field_info->old_name); - buffer.append(&lex->select_lex.db); + buffer.append(&lex->first_select_lex()->db); if (lex->wild && lex->wild->ptr()) { buffer.append(STRING_WITH_LEN(" (")); @@ -8357,7 +8359,7 @@ int make_columns_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) int fields_arr[]= {3, 15, 14, 6, 16, 5, 17, 18, 19, -1}; int *field_num= fields_arr; ST_FIELD_INFO *field_info; - Name_resolution_context *context= &thd->lex->select_lex.context; + Name_resolution_context *context= &thd->lex->first_select_lex()->context; for (; *field_num >= 0; field_num++) { @@ -8388,7 +8390,7 @@ int make_character_sets_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) int fields_arr[]= {0, 2, 1, 3, -1}; int *field_num= fields_arr; ST_FIELD_INFO *field_info; - Name_resolution_context *context= &thd->lex->select_lex.context; + Name_resolution_context *context= &thd->lex->first_select_lex()->context; for (; *field_num >= 0; field_num++) { @@ -8415,7 +8417,7 @@ int make_proc_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) int fields_arr[]= {2, 3, 4, 27, 24, 23, 22, 26, 28, 29, 30, -1}; int *field_num= fields_arr; ST_FIELD_INFO *field_info; - Name_resolution_context *context= &thd->lex->select_lex.context; + Name_resolution_context *context= &thd->lex->first_select_lex()->context; for (; *field_num >= 0; field_num++) { diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 448d095c876..1322d86302e 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4890,7 +4890,7 @@ int create_table_impl(THD *thd, /* Restart statement transactions for the case of CREATE ... SELECT. */ - if (thd->lex->select_lex.item_list.elements && + if (thd->lex->first_select_lex()->item_list.elements && restart_trans_for_tables(thd, thd->lex->query_tables)) goto err; } @@ -10237,8 +10237,8 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, Filesort_tracker dummy_tracker(false); Filesort fsort(order, HA_POS_ERROR, true, NULL); - if (thd->lex->select_lex.setup_ref_array(thd, order_num) || - setup_order(thd, thd->lex->select_lex.ref_pointer_array, + if (thd->lex->first_select_lex()->setup_ref_array(thd, order_num) || + setup_order(thd, thd->lex->first_select_lex()->ref_pointer_array, &tables, fields, all_fields, order)) goto err; diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc index 2ddb4bc042c..dabd88e90a4 100644 --- a/sql/sql_truncate.cc +++ b/sql/sql_truncate.cc @@ -489,7 +489,7 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref) bool Sql_cmd_truncate_table::execute(THD *thd) { bool res= TRUE; - TABLE_LIST *table= thd->lex->select_lex.table_list.first; + TABLE_LIST *table= thd->lex->first_select_lex()->table_list.first; DBUG_ENTER("Sql_cmd_truncate_table::execute"); if (check_one_table_access(thd, DROP_ACL, table)) diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 0149c2848c2..5b84ec45dba 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -1387,7 +1387,7 @@ bool st_select_lex_unit::exec() union_result->change_select(); if (fake_select_lex) { - if (sl != &thd->lex->select_lex) + if (sl != thd->lex->first_select_lex()) fake_select_lex->uncacheable|= sl->uncacheable; else fake_select_lex->uncacheable= 0; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 38638d3aa1d..8e7bbadf902 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -318,7 +318,7 @@ int mysql_update(THD *thd, SQL_SELECT *select= NULL; SORT_INFO *file_sort= 0; READ_RECORD info; - SELECT_LEX *select_lex= &thd->lex->select_lex; + SELECT_LEX *select_lex= thd->lex->first_select_lex(); ulonglong id; List<Item> all_fields; killed_state killed_status= NOT_KILLED; @@ -375,7 +375,7 @@ int mysql_update(THD *thd, table->covering_keys= table->s->keys_in_use; table->quick_keys.clear_all(); - query_plan.select_lex= &thd->lex->select_lex; + query_plan.select_lex= thd->lex->first_select_lex(); query_plan.table= table; #ifndef NO_EMBEDDED_ACCESS_CHECKS /* Force privilege re-checking for views after they have been opened. */ @@ -1241,7 +1241,7 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, TABLE *table= table_list->table; #endif List<Item> all_fields; - SELECT_LEX *select_lex= &thd->lex->select_lex; + SELECT_LEX *select_lex= thd->lex->first_select_lex(); DBUG_ENTER("mysql_prepare_update"); #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -1518,7 +1518,7 @@ int mysql_multi_update_prepare(THD *thd) LEX *lex= thd->lex; TABLE_LIST *table_list= lex->query_tables; TABLE_LIST *tl; - List<Item> *fields= &lex->select_lex.item_list; + List<Item> *fields= &lex->first_select_lex()->item_list; table_map tables_for_update; bool update_view= 0; /* @@ -1560,14 +1560,15 @@ int mysql_multi_update_prepare(THD *thd) if (mysql_handle_derived(lex, DT_PREPARE)) DBUG_RETURN(TRUE); - if (setup_tables_and_check_access(thd, &lex->select_lex.context, - &lex->select_lex.top_join_list, + if (setup_tables_and_check_access(thd, + &lex->first_select_lex()->context, + &lex->first_select_lex()->top_join_list, table_list, - lex->select_lex.leaf_tables, FALSE, - UPDATE_ACL, SELECT_ACL, FALSE)) + lex->first_select_lex()->leaf_tables, + FALSE, UPDATE_ACL, SELECT_ACL, FALSE)) DBUG_RETURN(TRUE); - if (lex->select_lex.handle_derived(thd->lex, DT_MERGE)) + if (lex->first_select_lex()->handle_derived(thd->lex, DT_MERGE)) DBUG_RETURN(TRUE); if (setup_fields_with_no_wrap(thd, Ref_ptr_array(), @@ -1590,13 +1591,14 @@ int mysql_multi_update_prepare(THD *thd) thd->table_map_for_update= tables_for_update= get_table_map(fields); - if (unsafe_key_update(lex->select_lex.leaf_tables, tables_for_update)) + if (unsafe_key_update(lex->first_select_lex()->leaf_tables, + tables_for_update)) DBUG_RETURN(true); /* Setup timestamp handling and locking mode */ - List_iterator<TABLE_LIST> ti(lex->select_lex.leaf_tables); + List_iterator<TABLE_LIST> ti(lex->first_select_lex()->leaf_tables); while ((tl= ti++)) { TABLE *table= tl->table; @@ -1689,7 +1691,7 @@ int mysql_multi_update_prepare(THD *thd) Check that we are not using table that we are updating, but we should skip all tables of UPDATE SELECT itself */ - lex->select_lex.exclude_from_table_unique_test= TRUE; + lex->first_select_lex()->exclude_from_table_unique_test= TRUE; /* We only need SELECT privilege for columns in the values list */ ti.rewind(); while ((tl= ti++)) @@ -1711,7 +1713,7 @@ int mysql_multi_update_prepare(THD *thd) Set exclude_from_table_unique_test value back to FALSE. It is needed for further check in multi_update::prepare whether to use record cache. */ - lex->select_lex.exclude_from_table_unique_test= FALSE; + lex->first_select_lex()->exclude_from_table_unique_test= FALSE; if (lex->save_prep_leaf_tables()) DBUG_RETURN(TRUE); @@ -1740,7 +1742,7 @@ bool mysql_multi_update(THD *thd, DBUG_ENTER("mysql_multi_update"); if (!(*result= new (thd->mem_root) multi_update(thd, table_list, - &thd->lex->select_lex.leaf_tables, + &thd->lex->first_select_lex()->leaf_tables, fields, values, handle_duplicates, ignore))) { diff --git a/sql/sql_view.cc b/sql/sql_view.cc index e910d48c75c..d1795f9c80f 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -254,7 +254,7 @@ bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view, LEX *lex= thd->lex; /* first table in list is target VIEW name => cut off it */ TABLE_LIST *tbl; - SELECT_LEX *select_lex= &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); SELECT_LEX *sl; bool res= TRUE; DBUG_ENTER("create_view_precheck"); @@ -323,7 +323,9 @@ bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view, } } - if (&lex->select_lex != lex->all_selects_list) +#if 0 + if (lex->first_select_lex() != lex->all_selects_list) +#endif { /* check tables of subqueries */ for (tbl= tables; tbl; tbl= tbl->next_global) @@ -399,7 +401,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, TABLE_LIST *view= lex->unlink_first_table(&link_to_local); TABLE_LIST *tables= lex->query_tables; TABLE_LIST *tbl; - SELECT_LEX *select_lex= &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); SELECT_LEX *sl; SELECT_LEX_UNIT *unit= &lex->unit; bool res= FALSE; @@ -995,7 +997,7 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, view->algorithm != VIEW_ALGORITHM_TMPTABLE))) { /* TODO: change here when we will support UNIONs */ - for (TABLE_LIST *tbl= lex->select_lex.table_list.first; + for (TABLE_LIST *tbl= lex->first_select_lex()->table_list.first; tbl; tbl= tbl->next_local) { @@ -1114,8 +1116,8 @@ loop_out: UNION */ if (view->updatable_view && - !lex->select_lex.master_unit()->is_unit_op() && - !(lex->select_lex.table_list.first)->next_local && + !lex->first_select_lex()->master_unit()->is_unit_op() && + !(lex->first_select_lex()->table_list.first)->next_local && find_table_in_global_list(lex->query_tables->next_global, &lex->query_tables->db, &lex->query_tables->table_name)) @@ -1162,7 +1164,8 @@ err: bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, bool open_view_no_parse) { - SELECT_LEX *end, *UNINIT_VAR(view_select); + SELECT_LEX_NODE *end; + SELECT_LEX *UNINIT_VAR(view_select); LEX *old_lex, *lex; Query_arena *arena, backup; TABLE_LIST *top_view= table->top_table(); @@ -1359,8 +1362,6 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, goto end; lex_start(thd); - view_select= &lex->select_lex; - view_select->select_number= ++thd->stmt_lex->current_select_number; sql_mode_t saved_mode= thd->variables.sql_mode; /* switch off modes which can prevent normal parsing of VIEW @@ -1395,6 +1396,8 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, parse_status= parse_sql(thd, & parser_state, table->view_creation_ctx); + view_select= lex->first_select_lex(); + /* Restore environment. */ if ((old_lex->sql_command == SQLCOM_SHOW_FIELDS) || @@ -1544,7 +1547,7 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, This may change in future, for example if we enable merging of views with subqueries in select list. */ - view_main_select_tables= lex->select_lex.table_list.first; + view_main_select_tables= lex->first_select_lex()->table_list.first; /* Let us set proper lock type for tables of the view's main @@ -1572,7 +1575,7 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, /* Fields in this view can be used in upper select in case of merge. */ if (table->select_lex) - table->select_lex->add_where_field(&lex->select_lex); + table->select_lex->add_where_field(lex->first_select_lex()); } /* This method has a dependency on the proper lock type being set, @@ -1594,8 +1597,8 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, old_lex->safe_to_cache_query= (old_lex->safe_to_cache_query && lex->safe_to_cache_query); /* move SQL_CACHE to whole query */ - if (view_select->options & OPTION_TO_QUERY_CACHE) - old_lex->select_lex.options|= OPTION_TO_QUERY_CACHE; + if (lex->first_select_lex()->options & OPTION_TO_QUERY_CACHE) + old_lex->first_select_lex()->options|= OPTION_TO_QUERY_CACHE; #ifndef NO_EMBEDDED_ACCESS_CHECKS if (table->view_suid) @@ -1677,9 +1680,10 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, tbl->grant.want_privilege= top_view->grant.orig_want_privilege; /* prepare view context */ - lex->select_lex.context.resolve_in_table_list_only(view_main_select_tables); - lex->select_lex.context.outer_context= 0; - lex->select_lex.select_n_having_items+= + lex->first_select_lex()-> + context.resolve_in_table_list_only(view_main_select_tables); + lex->first_select_lex()->context.outer_context= 0; + lex->first_select_lex()->select_n_having_items+= table->select_lex->select_n_having_items; table->where= view_select->where; @@ -1690,12 +1694,13 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table, */ if (!table->select_lex->master_unit()->is_unit_op() && table->select_lex->order_list.elements == 0) - table->select_lex->order_list.push_back(&lex->select_lex.order_list); + table->select_lex->order_list. + push_back(&lex->first_select_lex()->order_list); else { if (old_lex->sql_command == SQLCOM_SELECT && (old_lex->describe & DESCRIBE_EXTENDED) && - lex->select_lex.order_list.elements && + lex->first_select_lex()->order_list.elements && !table->select_lex->master_unit()->is_unit_op()) { push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, @@ -1730,7 +1735,11 @@ ok: lex->unit.include_down(table->select_lex); lex->unit.slave= view_select; // fix include_down initialisation /* global SELECT list linking */ - end= view_select; // primary SELECT_LEX is always last + /* + The primary SELECT_LEX is always last (because parsed first) if WITH not + used, otherwise it is good start point for last element finding + */ + for (end= view_select; end->link_next; end= end->link_next); end->link_next= old_lex->all_selects_list; old_lex->all_selects_list->link_prev= &end->link_next; old_lex->all_selects_list= lex->all_selects_list; @@ -1913,7 +1922,7 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) */ if ((!view->view && !view->belong_to_view) || thd->lex->sql_command == SQLCOM_INSERT || - thd->lex->select_lex.select_limit == 0) + thd->lex->first_select_lex()->select_limit == 0) DBUG_RETURN(FALSE); /* it is normal table or query without LIMIT */ table= view->table; view= view->top_table(); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index d69156ced9b..b5e3bb4f73d 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -511,6 +511,7 @@ bool LEX::add_select_to_union_list(bool is_union_distinct, { const char *type_name= (type == INTERSECT_TYPE ? "INTERSECT" : (type == EXCEPT_TYPE ? "EXCEPT" : "UNION")); + DBUG_ENTER("LEX::add_select_to_union_list"); /* Only the last SELECT can have INTO. Since the grammar won't allow INTO in a nested SELECT, we make this check only when creating a top-level SELECT. @@ -518,28 +519,28 @@ bool LEX::add_select_to_union_list(bool is_union_distinct, if (is_top_level && result) { my_error(ER_WRONG_USAGE, MYF(0), type_name, "INTO"); - return TRUE; + DBUG_RETURN(TRUE); } if (current_select->order_list.first && !current_select->braces) { my_error(ER_WRONG_USAGE, MYF(0), type_name, "ORDER BY"); - return TRUE; + DBUG_RETURN(TRUE); } if (current_select->explicit_limit && !current_select->braces) { my_error(ER_WRONG_USAGE, MYF(0), type_name, "LIMIT"); - return TRUE; + DBUG_RETURN(TRUE); } if (current_select->linkage == GLOBAL_OPTIONS_TYPE) { thd->parse_error(); - return TRUE; + DBUG_RETURN(TRUE); } if (!is_union_distinct && (type == INTERSECT_TYPE || type == EXCEPT_TYPE)) { my_error(ER_WRONG_USAGE, MYF(0), type_name, "ALL"); - return TRUE; + DBUG_RETURN(TRUE); } /* Priority implementation, but also trying to keep things as flat @@ -554,27 +555,24 @@ bool LEX::add_select_to_union_list(bool is_union_distinct, */ SELECT_LEX *prev= exclude_last_select(); if (add_unit_in_brackets(prev)) - return TRUE; - return add_select_to_union_list(is_union_distinct, type, 0); + DBUG_RETURN(TRUE); + bool res= add_select_to_union_list(is_union_distinct, type, 0); + DBUG_RETURN(res); } else { check_automatic_up(type); } - /* This counter shouldn't be incremented for UNION parts */ - nest_level--; if (mysql_new_select(this, 0, NULL)) - return TRUE; + DBUG_RETURN(TRUE); mysql_init_select(this); - current_select->linkage= type; + current_select->set_linkage(type); if (is_union_distinct) /* UNION DISTINCT - remember position */ { current_select->master_unit()->union_distinct= current_select; } - else - DBUG_ASSERT(type == UNION_TYPE); - return FALSE; + DBUG_RETURN(FALSE); } @@ -619,6 +617,7 @@ void sp_create_assignment_lex(THD *thd, bool no_lookahead) lex->sphead->m_tmp_query= lip->get_tok_end(); /* Inherit from outer lex. */ lex->option_type= old_lex->option_type; + lex->main_select_push(); } } @@ -678,6 +677,9 @@ bool sp_create_assignment_instr(THD *thd, bool no_lookahead) if (sp->add_instr(i)) return true; } + lex->pop_select(); + if (Lex->check_main_unit_semantics()) + return true; enum_var_type inner_option_type= lex->option_type; if (lex->sphead->restore_lex(thd)) return true; @@ -796,6 +798,20 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr) uint offset; } sp_cursor_name_and_offset; vers_history_point_t vers_history_point; + 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; @@ -841,6 +857,7 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr) 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; @@ -849,7 +866,6 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr) /* enums */ enum enum_view_suid view_suid; - enum sub_select_type unit_type; enum Condition_information_item::Name cond_info_item_name; enum enum_diag_condition_item_name diag_condition_item_name; enum Diagnostics_information::Which_area diag_area; @@ -888,10 +904,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); %parse-param { THD *thd } %lex-param { THD *thd } /* - Currently there are 139 shift/reduce conflicts. + Currently there are 135 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 139 +%expect 135 /* Comments for TOKENS. @@ -1210,6 +1226,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 @@ -1671,7 +1690,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 @@ -1716,7 +1736,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 @@ -1834,11 +1854,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_simple_table - derived_query_specification - derived_table_value_constructor + derived_table_list table_reference_list_parens + nested_table_reference_list join_table_parens %type <date_time_type> date_time_type; %type <interval> interval @@ -1876,14 +1893,16 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); UNDERSCORE_CHARSET %type <select_lex> subselect - get_select_lex get_select_lex_derived - simple_table query_specification - query_term_union_not_ready - query_term_union_ready - query_expression_body - select_paren_derived table_value_constructor + simple_table + query_primary + query_primary_parens + +%type <select_lex_unit> + query_expression_body + query_expression + query_expression_unit %type <boolfunc2creator> comp_op @@ -1895,7 +1914,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 @@ -1915,7 +1948,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 @@ -1935,9 +1968,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 @@ -2066,7 +2098,7 @@ query: END_OF_INPUT { if (!thd->bootstrap && - (!(thd->lex->select_lex.options & OPTION_FOUND_COMMENT))) + (!(thd->lex->builtin_select.options & OPTION_FOUND_COMMENT))) my_yyabort_error((ER_EMPTY_QUERY, MYF(0))); thd->lex->sql_command= SQLCOM_EMPTY_QUERY; @@ -2190,14 +2222,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 } ; @@ -2216,10 +2256,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), @@ -2227,7 +2278,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: @@ -2512,15 +2567,22 @@ 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->select_lex.add_table_to_list(thd, $5, NULL, - TL_OPTION_UPDATING, - TL_WRITE, MDL_EXCLUSIVE)) + } + 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; lex->alter_info.reset(); /* @@ -2535,7 +2597,7 @@ create: create_body { LEX *lex= thd->lex; - lex->current_select= &lex->select_lex; + lex->current_select= &lex->builtin_select; if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) && !lex->create_info.db_type) { @@ -2544,20 +2606,23 @@ 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; - if (!lex->select_lex.add_table_to_list(thd, $5, NULL, - TL_OPTION_UPDATING, - TL_WRITE, MDL_EXCLUSIVE)) + if (!lex->builtin_select.add_table_to_list(thd, $5, NULL, + TL_OPTION_UPDATING, + TL_WRITE, MDL_EXCLUSIVE)) MYSQL_YYABORT; /* @@ -2580,8 +2645,8 @@ create: if (lex->create_info.seq_create_info->check_and_adjust(1)) { my_error(ER_SEQUENCE_INVALID_DATA, MYF(0), - lex->select_lex.table_list.first->db.str, - lex->select_lex.table_list.first->table_name.str); + lex->builtin_select.table_list.first->db.str, + lex->builtin_select.table_list.first->table_name.str); MYSQL_YYABORT; } @@ -2593,7 +2658,7 @@ create: Lex->create_info.used_fields|= HA_CREATE_USED_SEQUENCE; Lex->create_info.sequence= 1; - lex->current_select= &lex->select_lex; + lex->current_select= &lex->builtin_select; if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) && !lex->create_info.db_type) { @@ -2605,42 +2670,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 + { + if (Lex->main_select_push()) + MYSQL_YYABORT; } - | create_or_replace opt_unique INDEX_SYM opt_if_not_exists ident + 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 { @@ -2648,58 +2740,104 @@ create: if (lex->set_command_with_check(SQLCOM_CREATE_DB, 0, $1 | $3)) MYSQL_YYABORT; lex->name= $4; + Lex->pop_select(); //main select } | create_or_replace definer_opt opt_view_suid VIEW_SYM opt_if_not_exists table_ident { + if (Lex->main_select_push()) + MYSQL_YYABORT; if (Lex->add_create_view(thd, $1 | $5, DTYPE_ALGORITHM_UNDEFINED, $3, $6)) MYSQL_YYABORT; } view_list_opt AS view_select - { } + { + Lex->pop_select(); //main select + } | create_or_replace view_algorithm definer_opt opt_view_suid VIEW_SYM opt_if_not_exists table_ident { if (Lex->add_create_view(thd, $1 | $6, $2, $4, $7)) MYSQL_YYABORT; + if (Lex->main_select_push()) + MYSQL_YYABORT; } view_list_opt AS view_select - { } + { + Lex->pop_select(); //main select + } | create_or_replace definer_opt TRIGGER_SYM - { Lex->create_info.set($1); } + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + Lex->create_info.set($1); + } trigger_tail - { } + { + Lex->pop_select(); //main select + } | create_or_replace definer_opt PROCEDURE_SYM - { Lex->create_info.set($1); } + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + Lex->create_info.set($1); + } sp_tail - { } + { + Lex->pop_select(); //main select + } | create_or_replace definer_opt EVENT_SYM - { Lex->create_info.set($1); } + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + Lex->create_info.set($1); + } event_tail - { } + { + Lex->pop_select(); //main select + } | create_or_replace definer FUNCTION_SYM { + if (Lex->main_select_push()) + MYSQL_YYABORT; Lex->create_info.set($1); } - sf_tail_not_aggregate - { } + sf_tail + { + Lex->pop_select(); //main select + } | create_or_replace definer AGGREGATE_SYM FUNCTION_SYM { + if (Lex->main_select_push()) + MYSQL_YYABORT; Lex->create_info.set($1); + } sf_tail_aggregate - { } + { + 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); } create_aggregate_function_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 { @@ -3098,7 +3236,7 @@ clear_privileges: lex->columns.empty(); lex->grant= lex->grant_tot_col= 0; lex->all_privileges= 0; - lex->select_lex.db= null_clex_str; + lex->builtin_select.db= null_clex_str; lex->ssl_type= SSL_TYPE_NOT_SPECIFIED; lex->ssl_cipher= lex->x509_subject= lex->x509_issuer= 0; bzero((char *)&(lex->mqh),sizeof(lex->mqh)); @@ -3168,8 +3306,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 */ @@ -3586,10 +3729,16 @@ sp_hcond: ; signal_stmt: - SIGNAL_SYM signal_value opt_set_signal_information + SIGNAL_SYM + { + if (Lex->main_select_push()) + YYABORT; + } + signal_value opt_set_signal_information { - if (Lex->add_signal_statement(thd, $2)) + if (Lex->add_signal_statement(thd, $3)) MYSQL_YYABORT; + Lex->pop_select(); //main select } ; @@ -3715,9 +3864,14 @@ resignal_stmt: ; get_diagnostics: - GET_SYM which_area DIAGNOSTICS_SYM diagnostics_information + GET_SYM which_area DIAGNOSTICS_SYM { - Diagnostics_information *info= $4; + if (Lex->main_select_push()) + YYABORT; + } + diagnostics_information + { + Diagnostics_information *info= $5; info->set_which_da($2); @@ -3726,6 +3880,7 @@ get_diagnostics: if (Lex->m_sql_cmd == NULL) MYSQL_YYABORT; + Lex->pop_select(); //main select } ; @@ -3893,7 +4048,16 @@ sp_decl_idents: sp_opt_default: /* Empty */ { $$ = NULL; } - | DEFAULT expr { $$ = $2; } + | DEFAULT + { + if (Lex->main_select_push()) + MYSQL_YYABORT; + } + expr + { + Lex->pop_select(); //main select + $$ = $3; + } ; /* @@ -3995,10 +4159,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) || @@ -4036,6 +4205,8 @@ assignment_source_expr: { DBUG_ASSERT(thd->free_list == NULL); Lex->sphead->reset_lex(thd, $1); + if (Lex->main_select_push()) + MYSQL_YYABORT; } expr { @@ -4044,6 +4215,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; } @@ -4176,9 +4348,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; @@ -4290,12 +4467,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; } @@ -4319,6 +4502,9 @@ simple_when_clause: WHEN_SYM { Lex->sphead->reset_lex(thd); /* For expr $3 */ + + if (Lex->main_select_push()) + MYSQL_YYABORT; } expr { @@ -4327,6 +4513,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; @@ -4343,12 +4531,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; @@ -4497,6 +4690,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; } @@ -4509,7 +4703,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; @@ -4520,6 +4719,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 */ @@ -4548,8 +4749,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 + { } | sp_label FOR_SYM { @@ -4601,9 +4806,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 @@ -5030,25 +5239,15 @@ 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 { Lex->create_info.add(DDL_options_st::OPT_LIKE); - TABLE_LIST *src_table= Lex->select_lex.add_table_to_list(thd, + TABLE_LIST *src_table= Lex->builtin_select.add_table_to_list(thd, $1, NULL, 0, TL_READ, MDL_SHARED_READ); if (! src_table) MYSQL_YYABORT; @@ -5059,7 +5258,7 @@ create_body: create_like: LIKE table_ident { $$= $2; } - | '(' LIKE table_ident ')' { $$= $3; } + | LEFT_PAREN_LIKE LIKE table_ident ')' { $$= $3; } ; opt_create_select: @@ -5068,23 +5267,51 @@ 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; + + // fix "main" select + SELECT_LEX *blt= Lex->pop_select(); + DBUG_ASSERT(blt == &Lex->builtin_select); + Lex->push_select(first_select); } - 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); + + 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; + + // fix "main" select + SELECT_LEX *blt= Lex->pop_select(); + DBUG_ASSERT(blt == &Lex->builtin_select); + Lex->push_select(first_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: @@ -5170,13 +5397,17 @@ partition_entry: thd->parse_error(ER_PARTITION_ENTRY_ERROR); MYSQL_YYABORT; } - DBUG_ASSERT(Lex->part_info->table); + if (Lex->main_select_push()) + MYSQL_YYABORT; /* We enter here when opening the frm file to translate partition info string into part_info data structure. */ } - partition {} + partition + { + Lex->pop_select(); //main select + } ; partition: @@ -5898,56 +6129,6 @@ opt_versioning_interval_start: 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 {} @@ -6165,7 +6346,7 @@ create_table_option: } | UNION_SYM opt_equal { - Lex->select_lex.table_list.save_and_clear(&Lex->save_list); + Lex->builtin_select.table_list.save_and_clear(&Lex->save_list); } '(' opt_table_list ')' { @@ -6174,8 +6355,8 @@ create_table_option: from the global list. */ LEX *lex=Lex; - lex->create_info.merge_list= lex->select_lex.table_list; - lex->select_lex.table_list= lex->save_list; + lex->create_info.merge_list= lex->builtin_select.table_list; + lex->builtin_select.table_list= lex->save_list; /* When excluding union list from the global list we assume that elements of the former immediately follow elements which represent @@ -6376,6 +6557,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 @@ -6702,6 +6890,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 { @@ -6709,13 +6899,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; } @@ -7636,22 +7842,24 @@ alter: Lex->table_type= TABLE_TYPE_UNKNOWN; Lex->sql_command= SQLCOM_ALTER_TABLE; Lex->duplicates= DUP_ERROR; - Lex->select_lex.init_order(); + Lex->builtin_select.init_order(); Lex->create_info.init(); Lex->create_info.row_type= ROW_TYPE_NOT_USED; Lex->alter_info.reset(); Lex->no_write_to_binlog= 0; Lex->create_info.storage_media= HA_SM_DEFAULT; + if (Lex->main_select_push()) + MYSQL_YYABORT; DBUG_ASSERT(!Lex->m_sql_cmd); } alter_options TABLE_SYM table_ident opt_lock_wait_timeout { - if (!Lex->select_lex.add_table_to_list(thd, $5, NULL, + if (!Lex->builtin_select.add_table_to_list(thd, $5, NULL, TL_OPTION_UPDATING, TL_READ_NO_INSERT, MDL_SHARED_UPGRADABLE)) MYSQL_YYABORT; - Lex->select_lex.db= (Lex->select_lex.table_list.first)->db; + Lex->builtin_select.db= (Lex->builtin_select.table_list.first)->db; Lex->create_last_non_select_table= Lex->last_table(); } alter_commands @@ -7663,11 +7871,14 @@ alter: 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 { @@ -7676,6 +7887,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 { @@ -7691,6 +7903,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 @@ -7699,6 +7913,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 { @@ -7706,6 +7923,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 @@ -7714,14 +7933,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 @@ -7729,14 +7957,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 @@ -7768,6 +8004,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 { @@ -7811,15 +8049,17 @@ alter: lex->create_info.init(); lex->no_write_to_binlog= 0; DBUG_ASSERT(!lex->m_sql_cmd); + if (Lex->main_select_push()) + MYSQL_YYABORT; } table_ident { LEX *lex= Lex; if (!(lex->create_info.seq_create_info= new (thd->mem_root) sequence_definition()) || - !lex->select_lex.add_table_to_list(thd, $5, NULL, - TL_OPTION_SEQUENCE, - TL_WRITE, MDL_EXCLUSIVE)) + !lex->builtin_select.add_table_to_list(thd, $5, NULL, + TL_OPTION_SEQUENCE, + TL_WRITE, MDL_EXCLUSIVE)) MYSQL_YYABORT; } sequence_defs @@ -7828,6 +8068,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; } ; @@ -7977,18 +8220,18 @@ alter_commands: WITH TABLE_SYM table_ident have_partitioning { LEX *lex= thd->lex; - lex->select_lex.db= $6->db; - if (lex->select_lex.db.str == NULL && - lex->copy_db_to(&lex->select_lex.db)) + lex->builtin_select.db=$6->db; + if (lex->builtin_select.db.str == NULL && + lex->copy_db_to(&lex->builtin_select.db)) { MYSQL_YYABORT; } lex->name= $6->table; lex->alter_info.partition_flags|= ALTER_PARTITION_EXCHANGE; - if (!lex->select_lex.add_table_to_list(thd, $6, NULL, - TL_OPTION_UPDATING, - TL_READ_NO_INSERT, - MDL_SHARED_NO_WRITE)) + if (!lex->builtin_select.add_table_to_list(thd, $6, NULL, + TL_OPTION_UPDATING, + TL_READ_NO_INSERT, + MDL_SHARED_NO_WRITE)) MYSQL_YYABORT; DBUG_ASSERT(!lex->m_sql_cmd); lex->m_sql_cmd= new (thd->mem_root) @@ -8233,9 +8476,9 @@ alter_list_item: | RENAME opt_to table_ident { LEX *lex=Lex; - lex->select_lex.db= $3->db; - if (lex->select_lex.db.str == NULL && - lex->copy_db_to(&lex->select_lex.db)) + lex->builtin_select.db= $3->db; + if (lex->builtin_select.db.str == NULL && + lex->copy_db_to(&lex->builtin_select.db)) { MYSQL_YYABORT; } @@ -8522,9 +8765,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: @@ -8550,6 +8797,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 { @@ -8558,6 +8807,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 } ; @@ -8586,6 +8836,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(); @@ -8600,6 +8852,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 } ; @@ -8716,6 +8969,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 { @@ -8726,6 +8981,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 } ; @@ -8763,6 +9019,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 { @@ -8771,6 +9029,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 } ; @@ -8784,9 +9043,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; @@ -8880,9 +9143,13 @@ preload: LEX *lex=Lex; lex->sql_command=SQLCOM_PRELOAD_KEYS; lex->alter_info.reset(); + if (Lex->main_select_push()) + MYSQL_YYABORT; } preload_list_or_parts - {} + { + Lex->pop_select(); //main select + } ; preload_list_or_parts: @@ -8925,8 +9192,8 @@ adm_partition: cache_keys_spec: { - Lex->select_lex.alloc_index_hints(thd); - Select->set_index_hint_type(INDEX_HINT_USE, + Lex->builtin_select.alloc_index_hints(thd); + Select->set_index_hint_type(INDEX_HINT_USE, INDEX_HINT_MASK_ALL); } cache_key_list_or_empty @@ -8947,217 +9214,347 @@ opt_ignore_leaves: Select : retrieve data from table */ - 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; + + Lex->sql_command= SQLCOM_SELECT; } ; -select_init: - SELECT_SYM select_options_and_item_list select_init3 - | table_value_constructor - | table_value_constructor union_list - | table_value_constructor union_order_or_limit - | '(' 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 - | table_value_constructor - | table_value_constructor union_list - | table_value_constructor union_order_or_limit - | '(' 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 { - 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; } - table_value_constructor + select_options { - DBUG_ASSERT(Lex->current_select->braces); + Select->parsing_place= SELECT_LIST; } - | + 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 - 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 ')' ; -select_paren_union_query_term: - { - /* - In order to correctly parse UNION's global ORDER BY we need to - set braces before parsing the clause. - */ - Lex->current_select->set_braces(true); - } - SELECT_SYM select_options_and_item_list select_part3_union_query_term - opt_select_lock_type - { - DBUG_ASSERT(Lex->current_select->braces); - } - | '(' select_paren_union_query_term ')' +opt_from_clause: + /* Empty */ + | from_clause ; -select_paren_view: - { - /* - In order to correctly parse UNION's global ORDER BY we need to - set braces before parsing the clause. - */ - Lex->current_select->set_braces(true); - } - SELECT_SYM select_options_and_item_list select_part3_view - opt_select_lock_type - { - DBUG_ASSERT(Lex->current_select->braces); - } - | '(' select_paren_view ')' + +query_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); } - table_value_constructor + 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(); } - | + | '(' query_primary { - Lex->current_select->set_braces(true); + Lex->push_select($2); } - 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(); + $$= $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_paren_derived ')' { $$= $2; } ; -select_init3: - 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 - 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(); -select_init3_union_query_term: - opt_table_expression - opt_select_lock_type - { - /* Parentheses carry no meaning here */ - Lex->current_select->set_braces(false); - } - union_clause - | select_part3_union_not_ready_noproc - opt_select_lock_type - { - /* Parentheses carry no meaning here */ - Lex->current_select->set_braces(false); + 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(); } ; @@ -9165,18 +9562,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 @@ -9274,59 +9659,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->select_lex) - my_yyabort_error((ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_NO_CACHE")); - if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_CACHE) - my_yyabort_error((ER_WRONG_USAGE, MYF(0), "SQL_CACHE", "SQL_NO_CACHE")); - if (Lex->select_lex.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->select_lex.options&= ~OPTION_TO_QUERY_CACHE; - Lex->select_lex.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->select_lex) - my_yyabort_error((ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_CACHE")); - if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_NO_CACHE) - my_yyabort_error((ER_WRONG_USAGE, MYF(0), "SQL_NO_CACHE", "SQL_CACHE")); - if (Lex->select_lex.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->select_lex.options|= OPTION_TO_QUERY_CACHE; - Lex->select_lex.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 @@ -11563,10 +11952,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); } ; @@ -11585,11 +11979,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; @@ -11606,6 +12007,8 @@ join_table: USING { MYSQL_YYABORT_UNLESS($1 && $3); + Select->add_joined_table($1); + Select->add_joined_table($3); } '(' using_list ')' { @@ -11616,6 +12019,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); } @@ -11625,6 +12030,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; @@ -11641,6 +12048,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 ')' { @@ -11651,6 +12060,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; @@ -11661,6 +12072,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; @@ -11678,6 +12091,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 ')' { @@ -11689,6 +12104,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())) @@ -11724,42 +12141,71 @@ use_partition: } ; -/* - 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_for_system_time_clause + opt_table_alias_clause opt_key_definition { - DBUG_ASSERT(Select); SELECT_LEX *sel= Select; sel->table_join_options= 0; - } - table_ident opt_use_partition opt_for_system_time_clause opt_table_alias opt_key_definition - { - if (!($$= Select->add_table_to_list(thd, $2, $5, + if (!($$= Select->add_table_to_list(thd, $1, $4, 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($$); - if ($4) + if ($3) $$->vers_conditions= Lex->vers_conditions; } ; - /* Represents a flattening of the following rules from the SQL:2003 standard. This sub-rule corresponds to the sub-rule @@ -11777,289 +12223,66 @@ table_primary_ident: */ table_primary_derived: - '(' get_select_lex select_derived_union ')' opt_for_system_time_clause opt_table_alias + query_primary_parens opt_for_system_time_clause table_alias_clause { - /* Use $2 instead of Lex->current_select as derived table will - alter value of Lex->current_select. */ - if (!($3 || $6) && $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, $6, 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(); - lex->nest_level--; - } - else if ($6 != 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()); - if ($5) - { - MYSQL_YYABORT_UNLESS(!$3); - $$->vers_conditions= Lex->vers_conditions; - } - } - /* Represents derived table with WITH clause */ - | '(' get_select_lex subselect_start - with_clause query_expression_body - subselect_end ')' opt_for_system_time_clause 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, $9, 0, - TL_READ, MDL_SHARED_READ))) + if (!($$= curr_sel->add_table_to_list(lex->thd, + ti, $3, 0, + TL_READ, MDL_SHARED_READ))) MYSQL_YYABORT; - sel->add_joined_table($$); - if ($8) - $$->vers_conditions= Lex->vers_conditions; - } - ; - -/* - 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) + if ($2) { - thd->parse_error(); - MYSQL_YYABORT; + $$->vers_conditions= Lex->vers_conditions; } } - union_list_derived_part2 - | derived_simple_table opt_select_lock_type - | derived_simple_table order_or_limit opt_select_lock_type - | derived_simple_table 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 + ')' opt_for_system_time_clause 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; - } - } - ; -derived_simple_table: - derived_query_specification { $$= $1; } - | derived_table_value_constructor { $$= $1; } - ; -/* - 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); -derived_table_value_constructor: - VALUES - { - LEX *lex=Lex; - lex->field_list.empty(); - lex->many_values.empty(); - lex->insert_list=0; - } - values_list - { - LEX *lex= Lex; - lex->derived_tables|= DERIVED_SUBQUERY; - if (!lex->expr_allows_subselect || - lex->sql_command == (int)SQLCOM_PURGE) - { - thd->parse_error(); + Table_ident *ti= new (thd->mem_root) Table_ident($2); + if (ti == NULL) MYSQL_YYABORT; - } - if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE || - mysql_new_select(lex, 1, NULL)) + if (!($$= curr_sel->add_table_to_list(lex->thd, + ti, $5, 0, + TL_READ, MDL_SHARED_READ))) MYSQL_YYABORT; - mysql_init_select(lex); - lex->current_select->linkage= DERIVED_TABLE_TYPE; - - if (!(lex->current_select->tvc= - new (lex->thd->mem_root) table_value_constr(lex->many_values, - lex->current_select, - lex->current_select->options))) - MYSQL_YYABORT; - lex->many_values.empty(); - $$= NULL; - } - ; - - -select_derived2: - { - LEX *lex= Lex; - lex->derived_tables|= DERIVED_SUBQUERY; - if (!lex->expr_allows_subselect || - lex->sql_command == (int)SQLCOM_PURGE) + if ($4) { - thd->parse_error(); - MYSQL_YYABORT; + $$->vers_conditions= Lex->vers_conditions; } - if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE || - mysql_new_select(lex, 1, NULL)) - MYSQL_YYABORT; - mysql_init_select(lex); - lex->current_select->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)) - 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: /* empty */ {} @@ -12190,9 +12413,14 @@ table_alias: | '=' ; -opt_table_alias: +opt_table_alias_clause: /* empty */ { $$=0; } - | table_alias ident_table_alias + + | table_alias_clause { $$= $1; } + ; + +table_alias_clause: + table_alias ident_table_alias { $$= (LEX_CSTRING*) thd->memdup(&$2,sizeof(LEX_STRING)); if ($$ == NULL) @@ -12359,7 +12587,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: @@ -12483,64 +12711,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: @@ -12550,63 +12749,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; } ; @@ -12675,6 +12872,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 */ | '+' @@ -12744,14 +13001,11 @@ bool: | TRUE_SYM { $$= 1; } | FALSE_SYM { $$= 0; } - procedure_clause: PROCEDURE_SYM ident /* Procedure name */ { LEX *lex=Lex; - DBUG_ASSERT(&lex->select_lex == lex->current_select); - lex->proc_list.elements=0; lex->proc_list.first=0; lex->proc_list.next= &lex->proc_list.first; @@ -12771,6 +13025,7 @@ procedure_clause: parameters are reduced. */ Lex->expr_allows_subselect= false; + Select->options|= OPTION_PROCEDURE_CLAUSE; } '(' procedure_list ')' { @@ -12851,8 +13106,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: @@ -12898,10 +13166,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; } ; @@ -13118,16 +13391,23 @@ insert: LEX *lex= Lex; lex->sql_command= SQLCOM_INSERT; 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->select_lex; + 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: @@ -13136,15 +13416,22 @@ replace: LEX *lex=Lex; lex->sql_command = SQLCOM_REPLACE; lex->duplicates= DUP_REPLACE; + 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->select_lex; + 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: @@ -13190,35 +13477,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: @@ -13328,6 +13627,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; @@ -13336,13 +13637,14 @@ update: SET update_list { LEX *lex= Lex; - if (lex->select_lex.table_list.elements > 1) + if (lex->builtin_select.table_list.elements > 1) lex->sql_command= SQLCOM_UPDATE_MULTI; - else if (lex->select_lex.get_table_list()->derived) + else if (lex->builtin_select.get_table_list()->derived) { /* it is single table update and it is update of derived table */ my_error(ER_NON_UPDATABLE_TABLE, MYF(0), - lex->select_lex.get_table_list()->alias.str, "UPDATE"); + lex->builtin_select.get_table_list()->alias.str, + "UPDATE"); MYSQL_YYABORT; } /* @@ -13352,7 +13654,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: @@ -13398,9 +13707,11 @@ delete: mysql_init_select(lex); YYPS->m_lock_type= TL_WRITE_DEFAULT; YYPS->m_mdl_type= MDL_SHARED_WRITE; + if (Lex->main_select_push()) + MYSQL_YYABORT; lex->ignore= 0; - lex->select_lex.init_order(); + lex->builtin_select.init_order(); } delete_part2 ; @@ -13421,6 +13732,7 @@ delete_part2: | HISTORY_SYM delete_single_table opt_delete_system_time { Lex->last_table()->vers_conditions= Lex->vers_conditions; + Lex->pop_select(); //main select } ; @@ -13443,9 +13755,18 @@ single_multi: opt_where_clause opt_order_clause delete_limit_clause - opt_select_expressions {} + opt_select_expressions + { + if ($3) + Select->order_list= *($3); + Lex->pop_select(); //main select + } | 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; @@ -13454,9 +13775,16 @@ 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 { + /* 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; @@ -13465,6 +13793,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; } ; @@ -13528,10 +13859,12 @@ truncate: { LEX* lex= Lex; lex->sql_command= SQLCOM_TRUNCATE; + if (lex->main_select_push()) + MYSQL_YYABORT; lex->alter_info.reset(); - lex->select_lex.options= 0; - lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED; - lex->select_lex.init_order(); + lex->builtin_select.options= 0; + lex->builtin_select.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED; + lex->builtin_select.init_order(); YYPS->m_lock_type= TL_WRITE; YYPS->m_mdl_type= MDL_EXCLUSIVE; } @@ -13542,6 +13875,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 } ; @@ -13616,6 +13950,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(); @@ -13623,6 +13959,7 @@ show: show_param { Select->parsing_place= NO_MATTER; + Lex->pop_select(); //main select } ; @@ -13638,7 +13975,7 @@ show_param: { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_TABLES; - lex->select_lex.db= $3; + lex->first_select_lex()->db= $3; if (prepare_schema_table(thd, lex, 0, SCH_TABLE_NAMES)) MYSQL_YYABORT; } @@ -13646,7 +13983,7 @@ show_param: { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_TRIGGERS; - lex->select_lex.db= $3; + lex->first_select_lex()->db= $3; if (prepare_schema_table(thd, lex, 0, SCH_TRIGGERS)) MYSQL_YYABORT; } @@ -13654,7 +13991,7 @@ show_param: { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_EVENTS; - lex->select_lex.db= $2; + lex->first_select_lex()->db= $2; if (prepare_schema_table(thd, lex, 0, SCH_EVENTS)) MYSQL_YYABORT; } @@ -13662,7 +13999,7 @@ show_param: { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_TABLE_STATUS; - lex->select_lex.db= $3; + lex->first_select_lex()->db= $3; if (prepare_schema_table(thd, lex, 0, SCH_TABLES)) MYSQL_YYABORT; } @@ -13670,7 +14007,7 @@ show_param: { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_OPEN_TABLES; - lex->select_lex.db= $3; + lex->first_select_lex()->db= $3; if (prepare_schema_table(thd, lex, 0, SCH_OPEN_TABLES)) MYSQL_YYABORT; } @@ -13720,12 +14057,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; @@ -13767,13 +14105,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; @@ -13834,7 +14172,7 @@ show_param: { LEX *lex= Lex; lex->sql_command = SQLCOM_SHOW_CREATE; - if (!lex->select_lex.add_table_to_list(thd, $3, NULL,0)) + if (!lex->builtin_select.add_table_to_list(thd, $3, NULL,0)) MYSQL_YYABORT; lex->create_info.storage_media= HA_SM_DEFAULT; } @@ -13842,7 +14180,7 @@ show_param: { LEX *lex= Lex; lex->sql_command = SQLCOM_SHOW_CREATE; - if (!lex->select_lex.add_table_to_list(thd, $3, NULL, 0)) + if (!lex->builtin_select.add_table_to_list(thd, $3, NULL, 0)) MYSQL_YYABORT; lex->table_type= TABLE_TYPE_VIEW; } @@ -13850,7 +14188,7 @@ show_param: { LEX *lex= Lex; lex->sql_command = SQLCOM_SHOW_CREATE; - if (!lex->select_lex.add_table_to_list(thd, $3, NULL, 0)) + if (!lex->builtin_select.add_table_to_list(thd, $3, NULL, 0)) MYSQL_YYABORT; lex->table_type= TABLE_TYPE_SEQUENCE; } @@ -14066,7 +14404,7 @@ describe: mysql_init_select(lex); lex->current_select->parsing_place= SELECT_LIST; lex->sql_command= SQLCOM_SHOW_FIELDS; - lex->select_lex.db= null_clex_str; + lex->builtin_select.db= null_clex_str; lex->verbose= 0; if (prepare_schema_table(thd, lex, $2, SCH_COLUMNS)) MYSQL_YYABORT; @@ -14080,7 +14418,7 @@ describe: explainable_command { LEX *lex=Lex; - lex->select_lex.options|= SELECT_DESCRIBE; + lex->first_select_lex()->options|= SELECT_DESCRIBE; } ; @@ -14106,6 +14444,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 {} ; @@ -14148,8 +14488,7 @@ flush: lex->type= 0; lex->no_write_to_binlog= $2; } - flush_options - {} + flush_options {} ; flush_options: @@ -14166,6 +14505,7 @@ flush_options: opt_table_list opt_flush_lock {} | flush_options_list + {} ; opt_flush_lock: @@ -14339,9 +14679,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: @@ -14359,6 +14703,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; } ; @@ -14368,6 +14714,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; @@ -14376,6 +14724,7 @@ kill: kill_type kill_option kill_expr { Lex->kill_signal= (killed_state) ($3 | $4); + Lex->pop_select(); //main select } ; @@ -14419,7 +14768,7 @@ use: { LEX *lex=Lex; lex->sql_command=SQLCOM_CHANGE_DB; - lex->select_lex.db= $2; + lex->builtin_select.db= $2; } ; @@ -14436,6 +14785,9 @@ load: $2 == FILETYPE_CSV ? "LOAD DATA" : "LOAD XML"); MYSQL_YYABORT; } + if (lex->main_select_push()) + MYSQL_YYABORT; + mysql_init_select(lex); } load_data_lock opt_local INFILE TEXT_STRING_filesystem { @@ -14462,7 +14814,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: @@ -14854,17 +15210,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(); @@ -14893,9 +15253,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)) @@ -15775,14 +16135,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 @@ -15792,6 +16160,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 {} @@ -16173,9 +16544,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: @@ -16206,7 +16581,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); @@ -16240,9 +16615,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 + } ; /* @@ -16250,25 +16629,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) @@ -16276,20 +16666,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"); @@ -16920,219 +17314,27 @@ 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(); - } - ; + { $$.unit_type= EXCEPT_TYPE; $$.distinct= 1; } -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 - ; /* 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; } | DISTINCT { $$=1; } | ALL { $$=0; } ; -simple_table: - query_specification { $$= $1; } - | table_value_constructor { $$= $1; } - ; - -table_value_constructor: - VALUES - { - LEX *lex=Lex; - lex->field_list.empty(); - lex->many_values.empty(); - lex->insert_list=0; - } - values_list - { - LEX *lex=Lex; - $$= lex->current_select; - mysql_init_select(Lex); - if (!($$->tvc= - new (lex->thd->mem_root) table_value_constr(lex->many_values, $$, $$->options))) - MYSQL_YYABORT; - lex->many_values.empty(); - } - ; - -/* - 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: - simple_table order_or_limit opt_select_lock_type { $$= $1; } - | '(' select_paren_derived ')' union_order_or_limit { $$= $2; } - ; - -query_term_union_ready: - simple_table 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; @@ -17140,18 +17342,8 @@ query_expression_option: | DISTINCT { 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; } ; @@ -17239,35 +17431,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, ¬_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 - | table_value_constructor - | table_value_constructor union_order_or_limit - | table_value_constructor union_list_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; } @@ -17371,11 +17556,11 @@ trigger_tail: sp_proc_stmt alternatives are not saving/restoring LEX, so lex->query_tables can be wiped out. */ - if (!lex->select_lex.add_table_to_list(thd, $10, - (LEX_CSTRING*) 0, - TL_OPTION_UPDATING, - TL_READ_NO_INSERT, - MDL_SHARED_NO_WRITE)) + if (!lex->builtin_select.add_table_to_list(thd, $10, + (LEX_CSTRING*) 0, + TL_OPTION_UPDATING, + TL_READ_NO_INSERT, + MDL_SHARED_NO_WRITE)) MYSQL_YYABORT; } ; diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index ec2aeeaefba..7dd065d59ab 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 @@ -1481,7 +1515,7 @@ query: END_OF_INPUT { if (!thd->bootstrap && - (!(thd->lex->select_lex.options & OPTION_FOUND_COMMENT))) + (!(thd->lex->builtin_select.options & OPTION_FOUND_COMMENT))) my_yyabort_error((ER_EMPTY_QUERY, MYF(0))); thd->lex->sql_command= SQLCOM_EMPTY_QUERY; @@ -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,15 +1985,22 @@ 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->select_lex.add_table_to_list(thd, $5, NULL, - TL_OPTION_UPDATING, - TL_WRITE, MDL_EXCLUSIVE)) + } + 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; lex->alter_info.reset(); /* @@ -1951,7 +2015,7 @@ create: create_body { LEX *lex= thd->lex; - lex->current_select= &lex->select_lex; + lex->current_select= &lex->builtin_select; if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) && !lex->create_info.db_type) { @@ -1960,20 +2024,23 @@ 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; - if (!lex->select_lex.add_table_to_list(thd, $5, NULL, - TL_OPTION_UPDATING, - TL_WRITE, MDL_EXCLUSIVE)) + if (!lex->builtin_select.add_table_to_list(thd, $5, NULL, + TL_OPTION_UPDATING, + TL_WRITE, MDL_EXCLUSIVE)) MYSQL_YYABORT; /* @@ -1996,8 +2063,8 @@ create: if (lex->create_info.seq_create_info->check_and_adjust(1)) { my_error(ER_SEQUENCE_INVALID_DATA, MYF(0), - lex->select_lex.table_list.first->db.str, - lex->select_lex.table_list.first->table_name.str); + lex->builtin_select.table_list.first->db.str, + lex->builtin_select.table_list.first->table_name.str); MYSQL_YYABORT; } @@ -2009,7 +2076,7 @@ create: Lex->create_info.used_fields|= HA_CREATE_USED_SEQUENCE; Lex->create_info.sequence= 1; - lex->current_select= &lex->select_lex; + lex->current_select= &lex->builtin_select; if ((lex->create_info.used_fields & HA_CREATE_USED_ENGINE) && !lex->create_info.db_type) { @@ -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 + { + if (Lex->main_select_push()) + MYSQL_YYABORT; } - | create_or_replace opt_unique INDEX_SYM opt_if_not_exists ident + 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 { @@ -2724,7 +2861,7 @@ clear_privileges: lex->columns.empty(); lex->grant= lex->grant_tot_col= 0; lex->all_privileges= 0; - lex->select_lex.db= null_clex_str; + lex->builtin_select.db= null_clex_str; lex->ssl_type= SSL_TYPE_NOT_SPECIFIED; lex->ssl_cipher= lex->x509_subject= lex->x509_issuer= 0; bzero((char *)&(lex->mqh),sizeof(lex->mqh)); @@ -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) || @@ -3804,7 +3981,14 @@ sp_proc_stmt_return: ; reset_lex_expr: - { Lex->sphead->reset_lex(thd); } expr { $$= $2; } + { + Lex->sphead->reset_lex(thd); + // will be poped in sp_proc_stmt_exit or sp_proc_stmt_continue + if (Lex->main_select_push()) + MYSQL_YYABORT; + } + expr + { $$= $2; } ; sp_proc_stmt_exit: @@ -3820,12 +4004,14 @@ sp_proc_stmt_exit: } | EXIT_SYM WHEN_SYM reset_lex_expr { + Lex->pop_select(); //main select pushed in reset_lex_expr if (Lex->sp_exit_statement(thd, $3) || Lex->sphead->restore_lex(thd)) MYSQL_YYABORT; } | EXIT_SYM label_ident WHEN_SYM reset_lex_expr { + Lex->pop_select(); //main select pushed in reset_lex_expr if (Lex->sp_exit_statement(thd, &$2, $4) || Lex->sphead->restore_lex(thd)) MYSQL_YYABORT; @@ -3845,12 +4031,14 @@ sp_proc_stmt_continue: } | CONTINUE_SYM WHEN_SYM reset_lex_expr { + Lex->pop_select(); //main select pushed in reset_lex_expr if (Lex->sp_continue_statement(thd, $3) || Lex->sphead->restore_lex(thd)) MYSQL_YYABORT; } | CONTINUE_SYM label_ident WHEN_SYM reset_lex_expr { + Lex->pop_select(); //main select pushed in reset_lex_expr if (Lex->sp_continue_statement(thd, &$2, $4) || Lex->sphead->restore_lex(thd)) MYSQL_YYABORT; @@ -3902,6 +4090,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 +4100,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 +4221,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 +4340,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 +4375,9 @@ simple_when_clause: WHEN_SYM { Lex->sphead->reset_lex(thd); /* For expr $3 */ + + if (Lex->main_select_push()) + MYSQL_YYABORT; } expr { @@ -4181,6 +4386,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 +4404,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 +4654,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 +4667,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 +4683,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 +4713,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 +4770,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,25 +5209,15 @@ 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 { Lex->create_info.add(DDL_options_st::OPT_LIKE); - TABLE_LIST *src_table= Lex->select_lex.add_table_to_list(thd, + TABLE_LIST *src_table= Lex->builtin_select.add_table_to_list(thd, $1, NULL, 0, TL_READ, MDL_SHARED_READ); if (! src_table) MYSQL_YYABORT; @@ -5010,7 +5228,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 +5237,51 @@ 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; + + // fix "main" select + SELECT_LEX *blt= Lex->pop_select(); + DBUG_ASSERT(blt == &Lex->builtin_select); + Lex->push_select(first_select); } - 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); + + 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; + + // fix "main" select + SELECT_LEX *blt= Lex->pop_select(); + DBUG_ASSERT(blt == &Lex->builtin_select); + Lex->push_select(first_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 +5372,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 +5993,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 {} @@ -6009,7 +6210,7 @@ create_table_option: } | UNION_SYM opt_equal { - Lex->select_lex.table_list.save_and_clear(&Lex->save_list); + Lex->builtin_select.table_list.save_and_clear(&Lex->save_list); } '(' opt_table_list ')' { @@ -6018,8 +6219,8 @@ create_table_option: from the global list. */ LEX *lex=Lex; - lex->create_info.merge_list= lex->select_lex.table_list; - lex->select_lex.table_list= lex->save_list; + lex->create_info.merge_list= lex->builtin_select.table_list; + lex->builtin_select.table_list= lex->save_list; /* When excluding union list from the global list we assume that elements of the former immediately follow elements which represent @@ -6195,6 +6396,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 +6670,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 +6679,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; } @@ -7468,22 +7694,24 @@ alter: Lex->table_type= TABLE_TYPE_UNKNOWN; Lex->sql_command= SQLCOM_ALTER_TABLE; Lex->duplicates= DUP_ERROR; - Lex->select_lex.init_order(); + Lex->builtin_select.init_order(); Lex->create_info.init(); Lex->create_info.row_type= ROW_TYPE_NOT_USED; Lex->alter_info.reset(); Lex->no_write_to_binlog= 0; Lex->create_info.storage_media= HA_SM_DEFAULT; + if (Lex->main_select_push()) + MYSQL_YYABORT; DBUG_ASSERT(!Lex->m_sql_cmd); } alter_options TABLE_SYM table_ident opt_lock_wait_timeout { - if (!Lex->select_lex.add_table_to_list(thd, $5, NULL, - TL_OPTION_UPDATING, - TL_READ_NO_INSERT, - MDL_SHARED_UPGRADABLE)) + if (!Lex->builtin_select.add_table_to_list(thd, $5, NULL, + TL_OPTION_UPDATING, + TL_READ_NO_INSERT, + MDL_SHARED_UPGRADABLE)) MYSQL_YYABORT; - Lex->select_lex.db= (Lex->select_lex.table_list.first)->db; + Lex->builtin_select.db= (Lex->builtin_select.table_list.first)->db; Lex->create_last_non_select_table= Lex->last_table(); } alter_commands @@ -7495,11 +7723,14 @@ alter: 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 +7739,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 +7755,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 +7765,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 +7775,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 +7785,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 +7809,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 +7856,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,15 +7901,17 @@ alter: lex->create_info.init(); lex->no_write_to_binlog= 0; DBUG_ASSERT(!lex->m_sql_cmd); + if (Lex->main_select_push()) + MYSQL_YYABORT; } table_ident { LEX *lex= Lex; if (!(lex->create_info.seq_create_info= new (thd->mem_root) sequence_definition()) || - !lex->select_lex.add_table_to_list(thd, $5, NULL, - TL_OPTION_SEQUENCE, - TL_WRITE, MDL_EXCLUSIVE)) + !lex->builtin_select.add_table_to_list(thd, $5, NULL, + TL_OPTION_SEQUENCE, + TL_WRITE, MDL_EXCLUSIVE)) MYSQL_YYABORT; } sequence_defs @@ -7660,6 +7920,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; } ; @@ -7809,18 +8072,17 @@ alter_commands: WITH TABLE_SYM table_ident have_partitioning { LEX *lex= thd->lex; - lex->select_lex.db= $6->db; - if (lex->select_lex.db.str == NULL && - lex->copy_db_to(&lex->select_lex.db)) + if (lex->builtin_select.db.str == NULL && + lex->copy_db_to(&lex->builtin_select.db)) { MYSQL_YYABORT; } lex->name= $6->table; lex->alter_info.partition_flags|= ALTER_PARTITION_EXCHANGE; - if (!lex->select_lex.add_table_to_list(thd, $6, NULL, - TL_OPTION_UPDATING, - TL_READ_NO_INSERT, - MDL_SHARED_NO_WRITE)) + if (!lex->builtin_select.add_table_to_list(thd, $6, NULL, + TL_OPTION_UPDATING, + TL_READ_NO_INSERT, + MDL_SHARED_NO_WRITE)) MYSQL_YYABORT; DBUG_ASSERT(!lex->m_sql_cmd); lex->m_sql_cmd= new (thd->mem_root) @@ -8061,9 +8323,9 @@ alter_list_item: | RENAME opt_to table_ident { LEX *lex=Lex; - lex->select_lex.db= $3->db; - if (lex->select_lex.db.str == NULL && - lex->copy_db_to(&lex->select_lex.db)) + lex->builtin_select.db= $3->db; + if (lex->builtin_select.db.str == NULL && + lex->copy_db_to(&lex->builtin_select.db)) { MYSQL_YYABORT; } @@ -8337,9 +8599,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: @@ -8365,6 +8631,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 { @@ -8373,6 +8641,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 } ; @@ -8401,6 +8670,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(); @@ -8415,6 +8686,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 } ; @@ -8531,6 +8803,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 { @@ -8541,6 +8815,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 } ; @@ -8578,6 +8853,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 { @@ -8586,6 +8863,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 } ; @@ -8599,9 +8877,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; @@ -8695,9 +8977,13 @@ preload: LEX *lex=Lex; lex->sql_command=SQLCOM_PRELOAD_KEYS; lex->alter_info.reset(); + if (Lex->main_select_push()) + MYSQL_YYABORT; } preload_list_or_parts - {} + { + Lex->pop_select(); //main select + } ; preload_list_or_parts: @@ -8740,8 +9026,8 @@ adm_partition: cache_keys_spec: { - Lex->select_lex.alloc_index_hints(thd); - Select->set_index_hint_type(INDEX_HINT_USE, + Lex->builtin_select.alloc_index_hints(thd); + Select->set_index_hint_type(INDEX_HINT_USE, INDEX_HINT_MASK_ALL); } cache_key_list_or_empty @@ -8764,192 +9050,345 @@ 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; + + 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(); } ; @@ -8957,18 +9396,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 @@ -9006,59 +9433,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->select_lex) - my_yyabort_error((ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_NO_CACHE")); - if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_CACHE) - my_yyabort_error((ER_WRONG_USAGE, MYF(0), "SQL_CACHE", "SQL_NO_CACHE")); - if (Lex->select_lex.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->select_lex.options&= ~OPTION_TO_QUERY_CACHE; - Lex->select_lex.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->select_lex) - my_yyabort_error((ER_CANT_USE_OPTION_HERE, MYF(0), "SQL_CACHE")); - if (Lex->select_lex.sql_cache == SELECT_LEX::SQL_NO_CACHE) - my_yyabort_error((ER_WRONG_USAGE, MYF(0), "SQL_NO_CACHE", "SQL_CACHE")); - if (Lex->select_lex.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->select_lex.options|= OPTION_TO_QUERY_CACHE; - Lex->select_lex.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 @@ -11362,10 +11793,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); } ; @@ -11384,11 +11820,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; @@ -11405,6 +11848,8 @@ join_table: USING { MYSQL_YYABORT_UNLESS($1 && $3); + Select->add_joined_table($1); + Select->add_joined_table($3); } '(' using_list ')' { @@ -11415,6 +11860,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); } @@ -11424,6 +11871,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; @@ -11440,6 +11889,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 ')' { @@ -11450,6 +11901,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; @@ -11460,6 +11913,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; @@ -11477,6 +11932,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 ')' { @@ -11488,6 +11945,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())) @@ -11522,40 +11981,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 @@ -11573,241 +12062,55 @@ 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(); - 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(); + Table_ident *ti= new (thd->mem_root) Table_ident($2); + if (ti == NULL) MYSQL_YYABORT; - } - if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE || - mysql_new_select(lex, 1, NULL)) + if (!($$= curr_sel->add_table_to_list(lex->thd, + ti, $4, 0, + TL_READ, MDL_SHARED_READ))) MYSQL_YYABORT; - mysql_init_select(lex); - lex->current_select->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)) - 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 */ } ; @@ -11940,9 +12243,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) @@ -12109,7 +12417,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: @@ -12233,64 +12541,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: @@ -12300,63 +12579,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; } ; @@ -12425,6 +12702,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 */ | '+' @@ -12494,14 +12831,11 @@ bool: | TRUE_SYM { $$= 1; } | FALSE_SYM { $$= 0; } - procedure_clause: PROCEDURE_SYM ident /* Procedure name */ { LEX *lex=Lex; - DBUG_ASSERT(&lex->select_lex == lex->current_select); - lex->proc_list.elements=0; lex->proc_list.first=0; lex->proc_list.next= &lex->proc_list.first; @@ -12521,6 +12855,7 @@ procedure_clause: parameters are reduced. */ Lex->expr_allows_subselect= false; + Select->options|= OPTION_PROCEDURE_CLAUSE; } '(' procedure_list ')' { @@ -12601,8 +12936,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: @@ -12648,10 +12996,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; } ; @@ -12883,17 +13236,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->select_lex; + 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: @@ -12902,15 +13262,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->select_lex; + 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: @@ -12956,35 +13323,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: @@ -13094,6 +13473,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; @@ -13102,13 +13483,14 @@ update: SET update_list { LEX *lex= Lex; - if (lex->select_lex.table_list.elements > 1) + if (lex->builtin_select.table_list.elements > 1) lex->sql_command= SQLCOM_UPDATE_MULTI; - else if (lex->select_lex.get_table_list()->derived) + else if (lex->builtin_select.get_table_list()->derived) { /* it is single table update and it is update of derived table */ my_error(ER_NON_UPDATABLE_TABLE, MYF(0), - lex->select_lex.get_table_list()->alias.str, "UPDATE"); + lex->builtin_select.get_table_list()->alias.str, + "UPDATE"); MYSQL_YYABORT; } /* @@ -13118,7 +13500,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,9 +13553,11 @@ delete: mysql_init_select(lex); YYPS->m_lock_type= TL_WRITE_DEFAULT; YYPS->m_mdl_type= MDL_SHARED_WRITE; + if (Lex->main_select_push()) + MYSQL_YYABORT; lex->ignore= 0; - lex->select_lex.init_order(); + lex->builtin_select.init_order(); } opt_delete_options single_multi ; @@ -13185,7 +13576,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 +13592,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 +13606,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; } ; @@ -13270,10 +13672,12 @@ truncate: { LEX* lex= Lex; lex->sql_command= SQLCOM_TRUNCATE; + if (lex->main_select_push()) + MYSQL_YYABORT; lex->alter_info.reset(); - lex->select_lex.options= 0; - lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED; - lex->select_lex.init_order(); + lex->builtin_select.options= 0; + lex->builtin_select.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED; + lex->builtin_select.init_order(); YYPS->m_lock_type= TL_WRITE; YYPS->m_mdl_type= MDL_EXCLUSIVE; } @@ -13284,6 +13688,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 +13770,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 +13779,7 @@ show: show_param { Select->parsing_place= NO_MATTER; + Lex->pop_select(); //main select } ; @@ -13387,7 +13795,7 @@ show_param: { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_TABLES; - lex->select_lex.db= $3; + lex->first_select_lex()->db= $3; if (prepare_schema_table(thd, lex, 0, SCH_TABLE_NAMES)) MYSQL_YYABORT; } @@ -13395,7 +13803,7 @@ show_param: { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_TRIGGERS; - lex->select_lex.db= $3; + lex->first_select_lex()->db= $3; if (prepare_schema_table(thd, lex, 0, SCH_TRIGGERS)) MYSQL_YYABORT; } @@ -13403,7 +13811,7 @@ show_param: { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_EVENTS; - lex->select_lex.db= $2; + lex->first_select_lex()->db= $2; if (prepare_schema_table(thd, lex, 0, SCH_EVENTS)) MYSQL_YYABORT; } @@ -13411,7 +13819,7 @@ show_param: { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_TABLE_STATUS; - lex->select_lex.db= $3; + lex->first_select_lex()->db= $3; if (prepare_schema_table(thd, lex, 0, SCH_TABLES)) MYSQL_YYABORT; } @@ -13419,7 +13827,7 @@ show_param: { LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_OPEN_TABLES; - lex->select_lex.db= $3; + lex->first_select_lex()->db= $3; if (prepare_schema_table(thd, lex, 0, SCH_OPEN_TABLES)) MYSQL_YYABORT; } @@ -13469,12 +13877,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 +13925,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; @@ -13583,7 +13992,7 @@ show_param: { LEX *lex= Lex; lex->sql_command = SQLCOM_SHOW_CREATE; - if (!lex->select_lex.add_table_to_list(thd, $3, NULL,0)) + if (!lex->builtin_select.add_table_to_list(thd, $3, NULL,0)) MYSQL_YYABORT; lex->create_info.storage_media= HA_SM_DEFAULT; } @@ -13591,7 +14000,7 @@ show_param: { LEX *lex= Lex; lex->sql_command = SQLCOM_SHOW_CREATE; - if (!lex->select_lex.add_table_to_list(thd, $3, NULL, 0)) + if (!lex->builtin_select.add_table_to_list(thd, $3, NULL, 0)) MYSQL_YYABORT; lex->table_type= TABLE_TYPE_VIEW; } @@ -13599,7 +14008,7 @@ show_param: { LEX *lex= Lex; lex->sql_command = SQLCOM_SHOW_CREATE; - if (!lex->select_lex.add_table_to_list(thd, $3, NULL, 0)) + if (!lex->builtin_select.add_table_to_list(thd, $3, NULL, 0)) MYSQL_YYABORT; lex->table_type= TABLE_TYPE_SEQUENCE; } @@ -13815,7 +14224,7 @@ describe: mysql_init_select(lex); lex->current_select->parsing_place= SELECT_LIST; lex->sql_command= SQLCOM_SHOW_FIELDS; - lex->select_lex.db= null_clex_str; + lex->builtin_select.db= null_clex_str; lex->verbose= 0; if (prepare_schema_table(thd, lex, $2, SCH_COLUMNS)) MYSQL_YYABORT; @@ -13829,7 +14238,7 @@ describe: explainable_command { LEX *lex=Lex; - lex->select_lex.options|= SELECT_DESCRIBE; + lex->first_select_lex()->options|= SELECT_DESCRIBE; } ; @@ -13855,6 +14264,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 +14308,7 @@ flush: lex->type= 0; lex->no_write_to_binlog= $2; } - flush_options - {} + flush_options {} ; flush_options: @@ -13915,6 +14325,7 @@ flush_options: opt_table_list opt_flush_lock {} | flush_options_list + {} ; opt_flush_lock: @@ -14070,9 +14481,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 +14505,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 +14516,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 +14526,7 @@ kill: kill_type kill_option kill_expr { Lex->kill_signal= (killed_state) ($3 | $4); + Lex->pop_select(); //main select } ; @@ -14150,7 +14570,7 @@ use: { LEX *lex=Lex; lex->sql_command=SQLCOM_CHANGE_DB; - lex->select_lex.db= $2; + lex->builtin_select.db= $2; } ; @@ -14167,6 +14587,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 +14615,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 +15023,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 +15066,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 +16019,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 +16044,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 +16479,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 +16516,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 +16550,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 +16564,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 +16601,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 +17264,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 +17281,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 +17293,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 +17382,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, ¬_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; } @@ -17221,11 +17504,11 @@ trigger_tail: sp_proc_stmt alternatives are not saving/restoring LEX, so lex->query_tables can be wiped out. */ - if (!lex->select_lex.add_table_to_list(thd, $10, - (LEX_CSTRING*) 0, - TL_OPTION_UPDATING, - TL_READ_NO_INSERT, - MDL_SHARED_NO_WRITE)) + if (!lex->builtin_select.add_table_to_list(thd, $10, + (LEX_CSTRING*) 0, + TL_OPTION_UPDATING, + TL_READ_NO_INSERT, + MDL_SHARED_NO_WRITE)) MYSQL_YYABORT; } ; diff --git a/sql/structs.h b/sql/structs.h index 01d99517fed..19c2405e75d 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -759,6 +759,59 @@ struct Lex_string_with_pos_st: public LEX_CSTRING const char *m_pos; }; +class Lex_select_lock +{ +public: + struct + { + uint defined_lock:1; + uint update_lock:1; + uint defined_timeout:1; + }; + ulong timeout; + + + void empty() + { + defined_lock= update_lock= defined_timeout= FALSE; + timeout= 0; + } +}; + +class Lex_select_limit +{ +public: + bool explicit_limit; + Item *select_limit, *offset_limit; + + void empty() + { + explicit_limit= FALSE; + select_limit= offset_limit= NULL; + } +}; + +struct st_order; +class st_select_lex; + +/** + ORDER BY ... LIMIT parameters; +*/ +class Lex_order_limit_lock +{ +public: + SQL_I_List<st_order> *order_list; /* ORDER clause */ + Lex_select_lock lock; + Lex_select_limit limit; + + static void *operator new(size_t size, MEM_ROOT *mem_root) throw () + { return alloc_root(mem_root, size); } + Lex_order_limit_lock() :order_list(NULL) + {} + + bool set_to(st_select_lex *sel); +}; + class Load_data_param { diff --git a/sql/table.cc b/sql/table.cc index 577ed20a87e..ce9e2365011 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2689,7 +2689,7 @@ static bool sql_unusable_for_discovery(THD *thd, handlerton *engine, if (lex->create_info.like()) return 1; // ... create select - if (lex->select_lex.item_list.elements) + if (lex->first_select_lex()->item_list.elements) return 1; // ... temporary if (create_info->tmp_table()) @@ -4938,13 +4938,13 @@ bool TABLE_LIST::single_table_updatable() { if (!updatable) return false; - if (view && view->select_lex.table_list.elements == 1) + if (view && view->first_select_lex()->table_list.elements == 1) { /* We need to check deeply only single table views. Multi-table views will be turned to multi-table updates and then checked by leaf tables */ - return (((TABLE_LIST *)view->select_lex.table_list.first)-> + return (((TABLE_LIST *)view->first_select_lex()->table_list.first)-> single_table_updatable()); } return true; @@ -4981,7 +4981,8 @@ merge_on_conds(THD *thd, TABLE_LIST *table, bool is_cascaded) cond= table->on_expr->copy_andor_structure(thd); if (!table->view) DBUG_RETURN(cond); - for (TABLE_LIST *tbl= (TABLE_LIST*)table->view->select_lex.table_list.first; + for (TABLE_LIST *tbl= + (TABLE_LIST*)table->view->first_select_lex()->table_list.first; tbl; tbl= tbl->next_local) { @@ -5023,7 +5024,7 @@ bool TABLE_LIST::prep_check_option(THD *thd, uint8 check_opt_type) { DBUG_ENTER("TABLE_LIST::prep_check_option"); bool is_cascaded= check_opt_type == VIEW_CHECK_CASCADED; - TABLE_LIST *merge_underlying_list= view->select_lex.get_table_list(); + TABLE_LIST *merge_underlying_list= view->first_select_lex()->get_table_list(); for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local) { /* see comment of check_opt_type parameter */ @@ -5145,7 +5146,7 @@ TABLE_LIST *TABLE_LIST::find_underlying_table(TABLE *table_to_find) if (!view) return 0; - for (TABLE_LIST *tbl= view->select_lex.get_table_list(); + for (TABLE_LIST *tbl= view->first_select_lex()->get_table_list(); tbl; tbl= tbl->next_local) { @@ -5316,7 +5317,8 @@ bool TABLE_LIST::set_insert_values(MEM_ROOT *mem_root) { DBUG_PRINT("info", ("setting insert_value for view")); DBUG_ASSERT(is_view_or_derived() && is_merged_derived()); - for (TABLE_LIST *tbl= (TABLE_LIST*)view->select_lex.table_list.first; + for (TABLE_LIST *tbl= + (TABLE_LIST*)view->first_select_lex()->table_list.first; tbl; tbl= tbl->next_local) if (tbl->set_insert_values(mem_root)) @@ -5483,7 +5485,7 @@ void TABLE_LIST::register_want_access(ulong want_access) } if (!view) return; - for (TABLE_LIST *tbl= view->select_lex.get_table_list(); + for (TABLE_LIST *tbl= view->first_select_lex()->get_table_list(); tbl; tbl= tbl->next_local) tbl->register_want_access(want_access); @@ -5675,6 +5677,7 @@ void TABLE_LIST::set_check_materialized() The subtree should be already excluded */ DBUG_ASSERT(!derived->first_select()->first_inner_unit() || + derived->first_select()->first_inner_unit()->with_element || derived->first_select()->first_inner_unit()->first_select()-> exclude_from_table_unique_test); } @@ -5691,14 +5694,14 @@ TABLE *TABLE_LIST::get_real_join_table() break; /* we do not support merging of union yet */ DBUG_ASSERT(tbl->view == NULL || - tbl->view->select_lex.next_select() == NULL); + tbl->view->first_select_lex()->next_select() == NULL); DBUG_ASSERT(tbl->derived == NULL || tbl->derived->first_select()->next_select() == NULL); { List_iterator_fast<TABLE_LIST> ti(tbl->view != NULL ? - tbl->view->select_lex.top_join_list : + tbl->view->first_select_lex()->top_join_list : tbl->derived->first_select()->top_join_list); for (;;) { @@ -5869,7 +5872,7 @@ Item *Field_iterator_view::create_item(THD *thd) Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref, LEX_CSTRING *name) { - bool save_wrapper= thd->lex->select_lex.no_wrap_view_item; + bool save_wrapper= thd->lex->first_select_lex()->no_wrap_view_item; Item *field= *field_ref; DBUG_ENTER("create_view_field"); @@ -5900,8 +5903,9 @@ Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref, { DBUG_RETURN(field); } - Name_resolution_context *context= view->view ? &view->view->select_lex.context : - &thd->lex->select_lex.context; + Name_resolution_context *context= (view->view ? + &view->view->first_select_lex()->context: + &thd->lex->first_select_lex()->context); Item *item= (new (thd->mem_root) Item_direct_view_ref(thd, context, field_ref, view->alias.str, name, view)); @@ -8618,7 +8622,7 @@ bool TR_table::query(ulonglong trx_id) READ_RECORD info; int error; List<TABLE_LIST> dummy; - SELECT_LEX &slex= thd->lex->select_lex; + SELECT_LEX &slex= *(thd->lex->first_select_lex()); Name_resolution_context_backup backup(slex.context, *this); Item *field= newx Item_field(thd, &slex.context, (*this)[FLD_TRX_ID]); Item *value= newx Item_int(thd, trx_id); @@ -8648,7 +8652,7 @@ bool TR_table::query(MYSQL_TIME &commit_time, bool backwards) READ_RECORD info; int error; List<TABLE_LIST> dummy; - SELECT_LEX &slex= thd->lex->select_lex; + SELECT_LEX &slex= *(thd->lex->first_select_lex()); Name_resolution_context_backup backup(slex.context, *this); Item *field= newx Item_field(thd, &slex.context, (*this)[FLD_COMMIT_TS]); Item *value= newx Item_datetime_literal(thd, &commit_time, 6); diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index def52cb2675..4f9ff51eaf7 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -1329,7 +1329,7 @@ static int create_view_query(THD *thd, uchar** buf, size_t* buf_len) { LEX *lex= thd->lex; - SELECT_LEX *select_lex= &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); TABLE_LIST *first_table= select_lex->table_list.first; TABLE_LIST *views = first_table; LEX_USER *definer; @@ -1421,7 +1421,7 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table, DBUG_ASSERT(table_list || db); LEX* lex= thd->lex; - SELECT_LEX* select_lex= &lex->select_lex; + SELECT_LEX* select_lex= lex->first_select_lex(); TABLE_LIST* first_table= select_lex->table_list.first; switch (lex->sql_command) |