summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/opt_subselect.cc31
-rw-r--r--sql/sql_class.h1
-rw-r--r--sql/sql_delete.cc76
-rw-r--r--sql/sql_lex.h1
-rw-r--r--sql/sql_select.cc3
-rw-r--r--sql/sql_update.cc12
-rw-r--r--sql/sql_yacc.yy13
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;
}