diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/opt_subselect.cc | 31 | ||||
-rw-r--r-- | sql/sql_class.h | 1 | ||||
-rw-r--r-- | sql/sql_delete.cc | 76 | ||||
-rw-r--r-- | sql/sql_lex.h | 1 | ||||
-rw-r--r-- | sql/sql_select.cc | 3 | ||||
-rw-r--r-- | sql/sql_update.cc | 12 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 13 |
7 files changed, 95 insertions, 42 deletions
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 58d86876388..df8f8088811 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -675,9 +675,8 @@ int check_and_do_in_subquery_rewrites(JOIN *join) 3. Subquery does not have GROUP BY or ORDER BY 4. Subquery does not use aggregate functions or HAVING 5. Subquery predicate is at the AND-top-level of ON/WHERE clause - 6. We are not in a subquery of a single table UPDATE/DELETE that - doesn't have a JOIN (TODO: We should handle this at some - point by switching to multi-table UPDATE/DELETE) + 6. We are not in a top level subquery of a single table DELETE + with RETURNING 7. We're not in a table-less subquery like "SELECT 1" 8. No execution method was already chosen (by a prepared statement) 9. Parent select is not a table-less select @@ -692,9 +691,9 @@ int check_and_do_in_subquery_rewrites(JOIN *join) !select_lex->group_list.elements && !join->order && // 3 !join->having && !select_lex->with_sum_func && // 4 in_subs->emb_on_expr_nest && // 5 - select_lex->outer_select()->join && // 6 - (!thd->lex->m_sql_cmd || - thd->lex->m_sql_cmd->sql_command_code() == SQLCOM_UPDATE_MULTI) && + !(thd->lex->sql_command == SQLCOM_DELETE && // 6 + thd->lex->has_returning() && // 6 + !select_lex->outer_select()->outer_select()) && // 6 parent_unit->first_select()->leaf_tables.elements && // 7 !in_subs->has_strategy() && // 8 select_lex->outer_select()->table_list.first && // 9 @@ -7192,3 +7191,23 @@ bool TABLE_LIST::is_sjm_scan_table() { return is_active_sjm() && sj_mat_info->is_sj_scan; } + + +bool SELECT_LEX::is_sj_subselect_lifted_to_top() +{ + st_select_lex *sl= this; + st_select_lex *outer_sl= outer_select(); + for ( ; outer_sl; sl= outer_sl, outer_sl= outer_sl->outer_select()) + { + List_iterator_fast<Item_in_subselect> it(outer_sl->sj_subselects); + Item_in_subselect *in_subs; + while ((in_subs= it++)) + { + if (in_subs->unit->first_select() == sl) + break; + } + if (!in_subs) + return false; + } + return true; +} diff --git a/sql/sql_class.h b/sql/sql_class.h index 5d1f97a78bf..f0160ebc365 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -6931,6 +6931,7 @@ public: // Methods used by ColumnStore uint get_num_of_tables() const { return num_of_tables; } TABLE_LIST* get_tables() const { return delete_tables; } + void set_delete_tables (TABLE_LIST *tbl) { delete_tables= tbl; } public: multi_delete(THD *thd_arg, TABLE_LIST *dt, uint num_of_tables); ~multi_delete(); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 7ac47971e44..611ce481a57 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -1511,6 +1511,47 @@ bool Sql_cmd_delete::prepare_inner(THD *thd) table_list->delete_while_scanning= false; } + + { + if (thd->lex->describe) + select_options|= SELECT_DESCRIBE; + + /* + When in EXPLAIN, delay deleting the joins so that they are still + available when we're producing EXPLAIN EXTENDED warning text. + */ + if (select_options & SELECT_DESCRIBE) + free_join= 0; + select_options|= + SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | OPTION_SETUP_TABLES_DONE; + + if (!(join= new (thd->mem_root) JOIN(thd, empty_list, + select_options, result))) + DBUG_RETURN(TRUE); + THD_STAGE_INFO(thd, stage_init); + select_lex->join= join; + thd->lex->used_tables=0; + if ((err= join->prepare(table_list, select_lex->where, + select_lex->order_list.elements, + select_lex->order_list.first, + false, NULL, NULL, NULL, + select_lex, &lex->unit))) + + { + goto err; + } + + if (!multitable && + select_lex->sj_subselects.elements && + !select_lex->order_list.elements && + select_lex->master_unit()->lim.get_select_limit() == HA_POS_ERROR && + !thd->lex->has_returning()) + multitable= true; + + if (!multitable) + ((multi_delete *)result)->set_delete_tables(0); + } + if (multitable) { /* @@ -1552,7 +1593,8 @@ bool Sql_cmd_delete::prepare_inner(THD *thd) { TABLE_LIST *duplicate; if ((duplicate= unique_table(thd, target_tbl->correspondent_table, - lex->query_tables, 0))) + lex->query_tables, 0)) && + !duplicate->select_lex->is_sj_subselect_lifted_to_top()) { update_non_unique_table_error(target_tbl->correspondent_table, "DELETE", duplicate); @@ -1567,38 +1609,6 @@ bool Sql_cmd_delete::prepare_inner(THD *thd) lex->first_select_lex()->exclude_from_table_unique_test= FALSE; } - { - if (thd->lex->describe) - select_options|= SELECT_DESCRIBE; - - /* - When in EXPLAIN, delay deleting the joins so that they are still - available when we're producing EXPLAIN EXTENDED warning text. - */ - if (select_options & SELECT_DESCRIBE) - free_join= 0; - select_options|= - SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | OPTION_SETUP_TABLES_DONE; - - if (!(join= new (thd->mem_root) JOIN(thd, empty_list, - select_options, result))) - DBUG_RETURN(TRUE); - THD_STAGE_INFO(thd, stage_init); - select_lex->join= join; - thd->lex->used_tables=0; - if ((err= join->prepare(table_list, select_lex->where, - select_lex->order_list.elements, - select_lex->order_list.first, - false, NULL, NULL, NULL, - select_lex, &lex->unit))) - - { - goto err; - } - - } - - if (setup_returning_fields(thd, table_list) || setup_ftfuncs(select_lex)) goto err; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 5436bfd0a59..f760ea14f72 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1642,6 +1642,7 @@ public: void lex_start(LEX *plex); bool is_unit_nest() { return (nest_flags & UNIT_NEST_FL); } void mark_as_unit_nest() { nest_flags= UNIT_NEST_FL; } + bool is_sj_subselect_lifted_to_top(); }; typedef class st_select_lex SELECT_LEX; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index ffd2efe74a7..8360e365ffc 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -5800,8 +5800,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list, s->needed_reg=select->needed_reg; select->quick=0; impossible_range= records == 0 && s->table->reginfo.impossible_range; - if (join->thd->lex->sql_command == SQLCOM_SELECT && - optimizer_flag(join->thd, OPTIMIZER_SWITCH_USE_ROWID_FILTER)) + if (optimizer_flag(join->thd, OPTIMIZER_SWITCH_USE_ROWID_FILTER)) s->table->init_cost_info_for_usable_range_rowid_filters(join->thd); } if (!impossible_range) diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 0ed25c3913d..7c48f8eaded 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -2671,6 +2671,8 @@ int multi_update::do_updates() table = cur_table->table; if (table == table_to_update) continue; // Already updated + if (table->file->pushed_rowid_filter) + table->file->disable_pushed_rowid_filter(); org_updated= updated; tmp_table= tmp_tables[cur_table->shared]; tmp_table->file->extra(HA_EXTRA_CACHE); // Change to read cache @@ -2865,7 +2867,8 @@ int multi_update::do_updates() check_opt_it.rewind(); while (TABLE *tbl= check_opt_it++) tbl->file->ha_rnd_end(); - + if (table->file->save_pushed_rowid_filter) + table->file->enable_pushed_rowid_filter(); } DBUG_RETURN(0); @@ -2876,6 +2879,8 @@ err: } err2: + if (table->file->save_pushed_rowid_filter) + table->file->enable_pushed_rowid_filter(); if (table->file->inited) (void) table->file->ha_rnd_end(); if (tmp_table->file->inited) @@ -3126,6 +3131,11 @@ bool Sql_cmd_update::prepare_inner(THD *thd) goto err; } + if (!multitable && + select_lex->sj_subselects.elements && + !select_lex->order_list.elements && + select_lex->master_unit()->lim.get_select_limit() == HA_POS_ERROR) + multitable= true; } free_join= false; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 4dfbfb41c9b..3953136fb72 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -13347,8 +13347,21 @@ delete_single_table: YYPS->m_lock_type, YYPS->m_mdl_type, NULL, + 0))) + MYSQL_YYABORT; + Select->table_list.save_and_clear(&Lex->auxiliary_table_list); + Lex->table_count= 1; + Lex->query_tables= 0; + Lex->query_tables_last= &Lex->query_tables; + if (unlikely(!Select-> + add_table_to_list(thd, $2, NULL, TL_OPTION_UPDATING, + YYPS->m_lock_type, + YYPS->m_mdl_type, + NULL, $3))) MYSQL_YYABORT; + Lex->auxiliary_table_list.first->correspondent_table= + Lex->query_tables; YYPS->m_lock_type= TL_READ_DEFAULT; YYPS->m_mdl_type= MDL_SHARED_READ; } |