summaryrefslogtreecommitdiff
path: root/sql/sql_delete.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_delete.cc')
-rw-r--r--sql/sql_delete.cc119
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) &&