diff options
Diffstat (limited to 'sql/sql_delete.cc')
-rw-r--r-- | sql/sql_delete.cc | 119 |
1 files changed, 77 insertions, 42 deletions
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 72a5b9703b3..84e88196f20 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -25,6 +25,7 @@ #include "sql_select.h" #include "sp_head.h" #include "sql_trigger.h" +#include "sql_handler.h" /** Implement DELETE SQL word. @@ -50,7 +51,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, bool triggers_applicable; uint usable_index= MAX_KEY; SELECT_LEX *select_lex= &thd->lex->select_lex; - THD::killed_state killed_status= THD::NOT_KILLED; + killed_state killed_status= NOT_KILLED; DBUG_ENTER("mysql_delete"); bool save_binlog_row_based; @@ -61,10 +62,21 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, if (open_and_lock_tables(thd, table_list)) DBUG_RETURN(TRUE); - if (!(table= table_list->table)) + + if (mysql_handle_list_of_derived(thd->lex, table_list, DT_MERGE_FOR_INSERT)) + DBUG_RETURN(TRUE); + if (mysql_handle_list_of_derived(thd->lex, table_list, DT_PREPARE)) + DBUG_RETURN(TRUE); + + if (!table_list->single_table_updatable()) { - my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), - table_list->view_db.str, table_list->view_name.str); + my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "DELETE"); + DBUG_RETURN(TRUE); + } + if (!(table= table_list->table) || !table->created) + { + my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), + table_list->view_db.str, table_list->view_name.str); DBUG_RETURN(TRUE); } thd_proc_info(thd, "init"); @@ -73,6 +85,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, if (mysql_prepare_delete(thd, table_list, &conds)) DBUG_RETURN(TRUE); + if (thd->lex->current_select->first_cond_optimization) + { + thd->lex->current_select->save_leaf_tables(thd); + thd->lex->current_select->first_cond_optimization= 0; + } /* check ORDER BY even if it can be ignored */ if (order && order->elements) { @@ -94,6 +111,10 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, } } + /* Apply the IN=>EXISTS transformation to all subqueries and optimize them. */ + if (select_lex->optimize_unflattened_subqueries()) + DBUG_RETURN(TRUE); + const_cond= (!conds || conds->const_item()); safe_update=test(thd->options & OPTION_SAFE_UPDATES); if (safe_update && const_cond) @@ -103,8 +124,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, DBUG_RETURN(TRUE); } - select_lex->no_error= thd->lex->ignore; - const_cond_result= const_cond && (!conds || conds->val_int()); if (thd->is_error()) { @@ -344,16 +363,9 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, } else { - table->file->print_error(error,MYF(0)); - /* - In < 4.0.14 we set the error number to 0 here, but that - was not sensible, because then MySQL would not roll back the - failed DELETE, and also wrote it to the binlog. For MyISAM - tables a DELETE probably never should fail (?), but for - InnoDB it can fail in a FOREIGN KEY error or an - out-of-tablespace error. - */ - if (!select_lex->no_error) + table->file->print_error(error, + MYF(thd->lex->ignore ? ME_JUST_WARNING : 0)); + if (thd->is_error()) { error= 1; break; @@ -364,7 +376,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, table->file->unlock_row(); // Row failed selection, release lock on it } killed_status= thd->killed; - if (killed_status != THD::NOT_KILLED || thd->is_error()) + if (killed_status != NOT_KILLED || thd->is_error()) error= 1; // Aborted if (will_batch && (loc_error= table->file->end_bulk_delete())) { @@ -402,6 +414,12 @@ cleanup: query_cache_invalidate3(thd, table_list, 1); } + if (thd->lex->current_select->first_cond_optimization) + { + thd->lex->current_select->save_leaf_tables(thd); + thd->lex->current_select->first_cond_optimization= 0; + } + delete select; transactional_table= table->file->has_transactions(); @@ -425,7 +443,7 @@ cleanup: if (error < 0) thd->clear_error(); else - errcode= query_error_code(thd, killed_status == THD::NOT_KILLED); + errcode= query_error_code(thd, killed_status == NOT_KILLED); /* [binlog]: If 'handler::delete_all_rows()' was called and the @@ -503,8 +521,8 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds) if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context, &thd->lex->select_lex.top_join_list, table_list, - &select_lex->leaf_tables, FALSE, - DELETE_ACL, SELECT_ACL) || + select_lex->leaf_tables, FALSE, + DELETE_ACL, SELECT_ACL, TRUE) || setup_conds(thd, table_list, select_lex->leaf_tables, conds) || setup_ftfuncs(select_lex)) DBUG_RETURN(TRUE); @@ -527,7 +545,7 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds) fix_inner_refs(thd, all_fields, select_lex, select_lex->ref_pointer_array)) DBUG_RETURN(TRUE); - select_lex->fix_prepare_information(thd, conds, &fake_conds); + select_lex->fix_prepare_information(thd, conds, &fake_conds); DBUG_RETURN(FALSE); } @@ -563,6 +581,12 @@ int mysql_multi_delete_prepare(THD *thd) TABLE_LIST *target_tbl; DBUG_ENTER("mysql_multi_delete_prepare"); + if (mysql_handle_derived(lex, DT_INIT)) + DBUG_RETURN(TRUE); + if (mysql_handle_derived(lex, DT_MERGE_FOR_INSERT)) + DBUG_RETURN(TRUE); + if (mysql_handle_derived(lex, DT_PREPARE)) + DBUG_RETURN(TRUE); /* setup_tables() need for VIEWs. JOIN::prepare() will not do it second time. @@ -572,10 +596,12 @@ int mysql_multi_delete_prepare(THD *thd) if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context, &thd->lex->select_lex.top_join_list, lex->query_tables, - &lex->select_lex.leaf_tables, FALSE, - DELETE_ACL, SELECT_ACL)) + lex->select_lex.leaf_tables, FALSE, + DELETE_ACL, SELECT_ACL, FALSE)) DBUG_RETURN(TRUE); + if (lex->select_lex.handle_derived(thd->lex, DT_MERGE)) + DBUG_RETURN(TRUE); /* Multi-delete can't be constructed over-union => we always have @@ -587,16 +613,14 @@ int mysql_multi_delete_prepare(THD *thd) target_tbl; target_tbl= target_tbl->next_local) { - if (!(target_tbl->table= target_tbl->correspondent_table->table)) + + target_tbl->table= target_tbl->correspondent_table->table; + if (target_tbl->correspondent_table->is_multitable()) { - DBUG_ASSERT(target_tbl->correspondent_table->view && - target_tbl->correspondent_table->merge_underlying_list && - target_tbl->correspondent_table->merge_underlying_list-> - next_local); - my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), - target_tbl->correspondent_table->view_db.str, - target_tbl->correspondent_table->view_name.str); - DBUG_RETURN(TRUE); + my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), + target_tbl->correspondent_table->view_db.str, + target_tbl->correspondent_table->view_name.str); + DBUG_RETURN(TRUE); } if (!target_tbl->correspondent_table->single_table_updatable() || @@ -626,6 +650,10 @@ int mysql_multi_delete_prepare(THD *thd) with further calls to unique_table */ lex->select_lex.exclude_from_table_unique_test= FALSE; + + if (lex->select_lex.save_prep_leaf_tables(thd)) + DBUG_RETURN(TRUE); + DBUG_RETURN(FALSE); } @@ -646,6 +674,12 @@ multi_delete::prepare(List<Item> &values, SELECT_LEX_UNIT *u) unit= u; do_delete= 1; thd_proc_info(thd, "deleting from main table"); + SELECT_LEX *select_lex= u->first_select(); + if (select_lex->first_cond_optimization) + { + if (select_lex->handle_derived(thd->lex, DT_MERGE)) + DBUG_RETURN(TRUE); + } DBUG_RETURN(0); } @@ -679,9 +713,10 @@ multi_delete::initialize_tables(JOIN *join) walk= delete_tables; - for (JOIN_TAB *tab=join->join_tab, *end=join->join_tab+join->tables; - tab < end; - tab++) + + for (JOIN_TAB *tab= first_linear_tab(join, WITH_CONST_TABLES); + tab; + tab= next_linear_tab(join, tab, WITHOUT_BUSH_ROOTS)) { if (tab->table->map & tables_to_delete_from) { @@ -766,7 +801,7 @@ int multi_delete::send_data(List<Item> &values) TABLE_LIST *del_table; DBUG_ENTER("multi_delete::send_data"); - bool ignore= thd->lex->current_select->no_error; + bool ignore= thd->lex->ignore; for (del_table= delete_tables; del_table; @@ -875,7 +910,7 @@ void multi_delete::abort() */ if (mysql_bin_log.is_open()) { - int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); + int errcode= query_error_code(thd, thd->killed == NOT_KILLED); /* possible error of writing binary log is ignored deliberately */ (void) thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(), thd->query_length(), @@ -915,11 +950,11 @@ int multi_delete::do_deletes() table_being_deleted= table_being_deleted->next_local, counter++) { TABLE *table = table_being_deleted->table; + int local_error; if (tempfiles[counter]->get(table)) DBUG_RETURN(1); - int local_error= - do_table_deletes(table, thd->lex->current_select->no_error); + local_error= do_table_deletes(table, thd->lex->ignore); if (thd->killed && !local_error) DBUG_RETURN(1); @@ -1025,7 +1060,7 @@ int multi_delete::do_table_deletes(TABLE *table, bool ignore) bool multi_delete::send_eof() { - THD::killed_state killed_status= THD::NOT_KILLED; + killed_state killed_status= NOT_KILLED; thd_proc_info(thd, "deleting from reference tables"); /* Does deletes for the last n - 1 tables, returns 0 if ok */ @@ -1033,7 +1068,7 @@ bool multi_delete::send_eof() /* compute a total error to know if something failed */ local_error= local_error || error; - killed_status= (local_error == 0)? THD::NOT_KILLED : thd->killed; + killed_status= (local_error == 0)? NOT_KILLED : thd->killed; /* reset used flags */ thd_proc_info(thd, "end"); @@ -1053,7 +1088,7 @@ bool multi_delete::send_eof() if (local_error == 0) thd->clear_error(); else - errcode= query_error_code(thd, killed_status == THD::NOT_KILLED); + errcode= query_error_code(thd, killed_status == NOT_KILLED); if (thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(), thd->query_length(), transactional_tables, FALSE, errcode) && |