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.cc85
1 files changed, 65 insertions, 20 deletions
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 3a7cc38b097..9cc63f7b33d 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -36,8 +36,8 @@
#include "sql_trigger.h"
#include "transaction.h"
#include "records.h" // init_read_record,
+#include "sql_derived.h" // mysql_handle_list_of_derived
// end_read_record
-
/**
Implement DELETE SQL word.
@@ -69,10 +69,21 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (open_and_lock_tables(thd, table_list, TRUE, 0))
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->updatable)
+ {
+ 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);
+ 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");
@@ -81,6 +92,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)
{
@@ -102,6 +118,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->variables.option_bits & OPTION_SAFE_UPDATES);
if (safe_update && const_cond)
@@ -382,6 +402,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();
@@ -453,8 +479,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);
@@ -476,7 +502,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);
}
@@ -512,6 +538,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.
@@ -521,10 +553,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
@@ -536,14 +570,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->multitable_view);
- 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->updatable ||
@@ -573,6 +607,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);
}
@@ -593,6 +631,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);
}
@@ -626,9 +670,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, WITH_BUSH_ROOTS))
{
if (tab->table->map & tables_to_delete_from)
{
@@ -707,7 +752,7 @@ multi_delete::~multi_delete()
}
-bool multi_delete::send_data(List<Item> &values)
+int multi_delete::send_data(List<Item> &values)
{
int secure_counter= delete_while_scanning ? -1 : 0;
TABLE_LIST *del_table;