1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-01 03:47:19 +03:00

Fixed LP bug #794901.

Also:
1. simplified the code of the function mysql_derived_merge_for_insert.
2. moved merge of views/dt for multi-update/delete to the prepare stage.
3. the list of the references to the candidates for semi-join now is
   allocated in the statement memory.
This commit is contained in:
Igor Babaev
2011-07-16 23:57:43 -07:00
parent 6e5413853e
commit d37465a9cc
13 changed files with 153 additions and 136 deletions

View File

@ -1003,3 +1003,16 @@ Warnings:
Note 1003 select `test`.`t2`.`a` AS `a`,0 AS `a`,0 AS `b` from `test`.`t1` left join `test`.`t2` on((0 <> 0)) where <expr_cache><0>(<in_optimizer>(0,<exists>(select 0 from `test`.`t1` where (<cache>(0) = 0)))) Note 1003 select `test`.`t2`.`a` AS `a`,0 AS `a`,0 AS `b` from `test`.`t1` left join `test`.`t2` on((0 <> 0)) where <expr_cache><0>(<in_optimizer>(0,<exists>(select 0 from `test`.`t1` where (<cache>(0) = 0))))
DROP VIEW v1; DROP VIEW v1;
DROP TABLE t1,t2; DROP TABLE t1,t2;
#
# LP bug #794901: insert into a multi-table view
#
CREATE TABLE t1 (a int);
CREATE TABLE t2 (a int);
CREATE TABLE t3 (a int);
CREATE VIEW v1 AS SELECT t1.a FROM t1,t2;
CREATE VIEW v2 AS SELECT a FROM t2 GROUP BY a;
CREATE VIEW v3 AS SELECT v1.a FROM v1,v2;
INSERT INTO v3(a) VALUES (1);
ERROR HY000: The target table v3 of the INSERT is not insertable-into
DROP VIEW v1,v2,v3;
DROP TABLE t1,t2,t3;

View File

@ -582,3 +582,21 @@ SELECT * FROM t2 RIGHT JOIN v1 AS t ON t.a != 0
DROP VIEW v1; DROP VIEW v1;
DROP TABLE t1,t2; DROP TABLE t1,t2;
--echo #
--echo # LP bug #794901: insert into a multi-table view
--echo #
CREATE TABLE t1 (a int);
CREATE TABLE t2 (a int);
CREATE TABLE t3 (a int);
CREATE VIEW v1 AS SELECT t1.a FROM t1,t2;
CREATE VIEW v2 AS SELECT a FROM t2 GROUP BY a;
CREATE VIEW v3 AS SELECT v1.a FROM v1,v2;
-- error ER_NON_INSERTABLE_TABLE
INSERT INTO v3(a) VALUES (1);
DROP VIEW v1,v2,v3;
DROP TABLE t1,t2,t3;

View File

@ -1146,7 +1146,8 @@ Item_in_subselect::Item_in_subselect(Item * left_exp,
st_select_lex *select_lex): st_select_lex *select_lex):
Item_exists_subselect(), left_expr_cache(0), first_execution(TRUE), Item_exists_subselect(), left_expr_cache(0), first_execution(TRUE),
optimizer(0), pushed_cond_guards(NULL), in_strategy(0), optimizer(0), pushed_cond_guards(NULL), in_strategy(0),
is_jtbm_merged(FALSE), is_flattenable_semijoin(FALSE), is_jtbm_merged(FALSE), is_flattenable_semijoin(FALSE),
is_registered_semijoin(FALSE),
upper_item(0) upper_item(0)
{ {
DBUG_ENTER("Item_in_subselect::Item_in_subselect"); DBUG_ENTER("Item_in_subselect::Item_in_subselect");

View File

@ -458,6 +458,11 @@ public:
*/ */
bool is_flattenable_semijoin; bool is_flattenable_semijoin;
/*
TRUE<=>registered in the list of semijoins in outer select
*/
bool is_registered_semijoin;
/* /*
Used to determine how this subselect item is represented in the item tree, Used to determine how this subselect item is represented in the item tree,
in case there is a need to locate it there and replace with something else. in case there is a need to locate it there and replace with something else.

View File

@ -177,8 +177,8 @@ bool subquery_types_allow_materialization(Item_in_subselect *in_subs);
static bool replace_where_subcondition(JOIN *join, Item **expr, static bool replace_where_subcondition(JOIN *join, Item **expr,
Item *old_cond, Item *new_cond, Item *old_cond, Item *new_cond,
bool do_fix_fields); bool do_fix_fields);
static int subq_sj_candidate_cmp(Item_in_subselect* const *el1, static int subq_sj_candidate_cmp(Item_in_subselect* el1, Item_in_subselect* el2,
Item_in_subselect* const *el2); void *arg);
static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred); static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred);
static bool convert_subq_to_jtbm(JOIN *parent_join, static bool convert_subq_to_jtbm(JOIN *parent_join,
Item_in_subselect *subq_pred, bool *remove); Item_in_subselect *subq_pred, bool *remove);
@ -357,8 +357,15 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
in_subs->is_flattenable_semijoin= TRUE; in_subs->is_flattenable_semijoin= TRUE;
/* Register the subquery for further processing in flatten_subqueries() */ /* Register the subquery for further processing in flatten_subqueries() */
select_lex-> if (!in_subs->is_registered_semijoin)
outer_select()->join->sj_subselects.append(thd->mem_root, in_subs); {
Query_arena *arena, backup;
arena= thd->activate_stmt_arena_if_needed(&backup);
select_lex->outer_select()->sj_subselects.push_back(in_subs);
if (arena)
thd->restore_active_arena(arena, &backup);
in_subs->is_registered_semijoin= TRUE;
}
} }
else else
{ {
@ -405,7 +412,7 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
condition also excludes multi-table update statements. condition also excludes multi-table update statements.
A note about prepared statements: we want the if-branch to be taken on A note about prepared statements: we want the if-branch to be taken on
PREPARE and each EXECUTE. The rewrites are only done once, but we need PREPARE and each EXECUTE. The rewrites are only done once, but we need
join->sj_subselects list to be populated for every EXECUTE. select_lex->sj_subselects list to be populated for every EXECUTE.
*/ */
if (optimizer_flag(thd, OPTIMIZER_SWITCH_MATERIALIZATION) && // 0 if (optimizer_flag(thd, OPTIMIZER_SWITCH_MATERIALIZATION) && // 0
@ -432,8 +439,15 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
{ {
in_subs->emb_on_expr_nest= thd->thd_marker.emb_on_expr_nest; in_subs->emb_on_expr_nest= thd->thd_marker.emb_on_expr_nest;
in_subs->is_flattenable_semijoin= FALSE; in_subs->is_flattenable_semijoin= FALSE;
select_lex->outer_select()-> if (!in_subs->is_registered_semijoin)
join->sj_subselects.append(thd->mem_root, in_subs); {
Query_arena *arena, backup;
arena= thd->activate_stmt_arena_if_needed(&backup);
select_lex->outer_select()->sj_subselects.push_back(in_subs);
if (arena)
thd->restore_active_arena(arena, &backup);
in_subs->is_registered_semijoin= TRUE;
}
} }
} }
@ -731,21 +745,19 @@ bool check_for_outer_joins(List<TABLE_LIST> *join_list)
bool convert_join_subqueries_to_semijoins(JOIN *join) bool convert_join_subqueries_to_semijoins(JOIN *join)
{ {
Query_arena *arena, backup; Query_arena *arena, backup;
Item_in_subselect **in_subq; Item_in_subselect *in_subq;
Item_in_subselect **in_subq_end;
THD *thd= join->thd; THD *thd= join->thd;
List_iterator<TABLE_LIST> ti(join->select_lex->leaf_tables); List_iterator<TABLE_LIST> ti(join->select_lex->leaf_tables);
DBUG_ENTER("convert_join_subqueries_to_semijoins"); DBUG_ENTER("convert_join_subqueries_to_semijoins");
if (join->sj_subselects.elements() == 0) if (join->select_lex->sj_subselects.is_empty())
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
for (in_subq= join->sj_subselects.front(), List_iterator_fast<Item_in_subselect> li(join->select_lex->sj_subselects);
in_subq_end= join->sj_subselects.back();
in_subq != in_subq_end; while ((in_subq= li++))
in_subq++)
{ {
SELECT_LEX *subq_sel= (*in_subq)->get_select_lex(); SELECT_LEX *subq_sel= in_subq->get_select_lex();
if (subq_sel->handle_derived(thd->lex, DT_OPTIMIZE)) if (subq_sel->handle_derived(thd->lex, DT_OPTIMIZE))
DBUG_RETURN(1); DBUG_RETURN(1);
if (subq_sel->handle_derived(thd->lex, DT_MERGE)) if (subq_sel->handle_derived(thd->lex, DT_MERGE))
@ -753,13 +765,11 @@ bool convert_join_subqueries_to_semijoins(JOIN *join)
subq_sel->update_used_tables(); subq_sel->update_used_tables();
} }
li.rewind();
/* First, convert child join's subqueries. We proceed bottom-up here */ /* First, convert child join's subqueries. We proceed bottom-up here */
for (in_subq= join->sj_subselects.front(), while ((in_subq= li++))
in_subq_end= join->sj_subselects.back();
in_subq != in_subq_end;
in_subq++)
{ {
st_select_lex *child_select= (*in_subq)->get_select_lex(); st_select_lex *child_select= in_subq->get_select_lex();
JOIN *child_join= child_select->join; JOIN *child_join= child_select->join;
child_join->outer_tables = child_join->table_count; child_join->outer_tables = child_join->table_count;
@ -773,9 +783,9 @@ bool convert_join_subqueries_to_semijoins(JOIN *join)
if (convert_join_subqueries_to_semijoins(child_join)) if (convert_join_subqueries_to_semijoins(child_join))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
(*in_subq)->sj_convert_priority= in_subq->sj_convert_priority=
test((*in_subq)->emb_on_expr_nest != NO_JOIN_NEST) * MAX_TABLES * 2 + test(in_subq->emb_on_expr_nest != NO_JOIN_NEST) * MAX_TABLES * 2 +
(*in_subq)->is_correlated * MAX_TABLES + child_join->outer_tables; in_subq->is_correlated * MAX_TABLES + child_join->outer_tables;
} }
// Temporary measure: disable semi-joins when they are together with outer // Temporary measure: disable semi-joins when they are together with outer
@ -783,7 +793,7 @@ bool convert_join_subqueries_to_semijoins(JOIN *join)
#if 0 #if 0
if (check_for_outer_joins(join->join_list)) if (check_for_outer_joins(join->join_list))
{ {
in_subq= join->sj_subselects.front(); in_subq= join->select_lex->sj_subselects.head();
arena= thd->activate_stmt_arena_if_needed(&backup); arena= thd->activate_stmt_arena_if_needed(&backup);
goto skip_conversion; goto skip_conversion;
} }
@ -795,41 +805,41 @@ bool convert_join_subqueries_to_semijoins(JOIN *join)
- prefer correlated subqueries over uncorrelated; - prefer correlated subqueries over uncorrelated;
- prefer subqueries that have greater number of outer tables; - prefer subqueries that have greater number of outer tables;
*/ */
join->sj_subselects.sort(subq_sj_candidate_cmp); bubble_sort<Item_in_subselect>(&join->select_lex->sj_subselects,
subq_sj_candidate_cmp, NULL);
// #tables-in-parent-query + #tables-in-subquery < MAX_TABLES // #tables-in-parent-query + #tables-in-subquery < MAX_TABLES
/* Replace all subqueries to be flattened with Item_int(1) */ /* Replace all subqueries to be flattened with Item_int(1) */
arena= thd->activate_stmt_arena_if_needed(&backup); arena= thd->activate_stmt_arena_if_needed(&backup);
for (in_subq= join->sj_subselects.front(); li.rewind();
in_subq != in_subq_end; while ((in_subq= li++))
in_subq++)
{ {
bool remove_item= TRUE; bool remove_item= TRUE;
/* Stop processing if we've reached a subquery that's attached to the ON clause */ /* Stop processing if we've reached a subquery that's attached to the ON clause */
if ((*in_subq)->emb_on_expr_nest != NO_JOIN_NEST) if (in_subq->emb_on_expr_nest != NO_JOIN_NEST)
break; break;
if ((*in_subq)->is_flattenable_semijoin) if (in_subq->is_flattenable_semijoin)
{ {
if (join->table_count + if (join->table_count +
(*in_subq)->unit->first_select()->join->table_count >= MAX_TABLES) in_subq->unit->first_select()->join->table_count >= MAX_TABLES)
break; break;
if (convert_subq_to_sj(join, *in_subq)) if (convert_subq_to_sj(join, in_subq))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
else else
{ {
if (join->table_count + 1 >= MAX_TABLES) if (join->table_count + 1 >= MAX_TABLES)
break; break;
if (convert_subq_to_jtbm(join, *in_subq, &remove_item)) if (convert_subq_to_jtbm(join, in_subq, &remove_item))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
if (remove_item) if (remove_item)
{ {
Item **tree= ((*in_subq)->emb_on_expr_nest == NO_JOIN_NEST)? Item **tree= (in_subq->emb_on_expr_nest == NO_JOIN_NEST)?
&join->conds : &((*in_subq)->emb_on_expr_nest->on_expr); &join->conds : &(in_subq->emb_on_expr_nest->on_expr);
Item *replace_me= (*in_subq)->original_item(); Item *replace_me= in_subq->original_item();
if (replace_where_subcondition(join, tree, replace_me, new Item_int(1), if (replace_where_subcondition(join, tree, replace_me, new Item_int(1),
FALSE)) FALSE))
DBUG_RETURN(TRUE); /* purecov: inspected */ DBUG_RETURN(TRUE); /* purecov: inspected */
@ -840,34 +850,34 @@ bool convert_join_subqueries_to_semijoins(JOIN *join)
3. Finalize (perform IN->EXISTS rewrite) the subqueries that we didn't 3. Finalize (perform IN->EXISTS rewrite) the subqueries that we didn't
convert: convert:
*/ */
for (; in_subq!= in_subq_end; in_subq++) while (in_subq)
{ {
JOIN *child_join= (*in_subq)->unit->first_select()->join; JOIN *child_join= in_subq->unit->first_select()->join;
(*in_subq)->changed= 0; in_subq->changed= 0;
(*in_subq)->fixed= 0; in_subq->fixed= 0;
SELECT_LEX *save_select_lex= thd->lex->current_select; SELECT_LEX *save_select_lex= thd->lex->current_select;
thd->lex->current_select= (*in_subq)->unit->first_select(); thd->lex->current_select= in_subq->unit->first_select();
bool res= (*in_subq)->select_transformer(child_join); bool res= in_subq->select_transformer(child_join);
thd->lex->current_select= save_select_lex; thd->lex->current_select= save_select_lex;
if (res) if (res)
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
(*in_subq)->changed= 1; in_subq->changed= 1;
(*in_subq)->fixed= 1; in_subq->fixed= 1;
Item *substitute= (*in_subq)->substitution; Item *substitute= in_subq->substitution;
bool do_fix_fields= !(*in_subq)->substitution->fixed; bool do_fix_fields= !in_subq->substitution->fixed;
Item **tree= ((*in_subq)->emb_on_expr_nest == NO_JOIN_NEST)? Item **tree= (in_subq->emb_on_expr_nest == NO_JOIN_NEST)?
&join->conds : &((*in_subq)->emb_on_expr_nest->on_expr); &join->conds : &(in_subq->emb_on_expr_nest->on_expr);
Item *replace_me= (*in_subq)->original_item(); Item *replace_me= in_subq->original_item();
if (replace_where_subcondition(join, tree, replace_me, substitute, if (replace_where_subcondition(join, tree, replace_me, substitute,
do_fix_fields)) do_fix_fields))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
(*in_subq)->substitution= NULL; in_subq->substitution= NULL;
#if 0 #if 0
/* /*
Don't do the following, because the simplify_join() call is after this Don't do the following, because the simplify_join() call is after this
@ -881,9 +891,9 @@ bool convert_join_subqueries_to_semijoins(JOIN *join)
*/ */
if (!thd->stmt_arena->is_conventional()) if (!thd->stmt_arena->is_conventional())
{ {
tree= ((*in_subq)->emb_on_expr_nest == NO_JOIN_NEST)? tree= (in_subq->emb_on_expr_nest == NO_JOIN_NEST)?
&join->select_lex->prep_where : &join->select_lex->prep_where :
&((*in_subq)->emb_on_expr_nest->prep_on_expr); &(in_subq->emb_on_expr_nest->prep_on_expr);
if (replace_where_subcondition(join, tree, replace_me, substitute, if (replace_where_subcondition(join, tree, replace_me, substitute,
FALSE)) FALSE))
@ -898,12 +908,13 @@ bool convert_join_subqueries_to_semijoins(JOIN *join)
re-run the test for materialization that was done in re-run the test for materialization that was done in
check_and_do_in_subquery_rewrites. check_and_do_in_subquery_rewrites.
*/ */
(*in_subq)->in_strategy= SUBS_IN_TO_EXISTS; in_subq->in_strategy= SUBS_IN_TO_EXISTS;
in_subq= li++;
} }
if (arena) if (arena)
thd->restore_active_arena(arena, &backup); thd->restore_active_arena(arena, &backup);
join->sj_subselects.clear(); join->select_lex->sj_subselects.empty();
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }
@ -1004,11 +1015,11 @@ static bool replace_where_subcondition(JOIN *join, Item **expr,
return TRUE; return TRUE;
} }
static int subq_sj_candidate_cmp(Item_in_subselect* const *el1, static int subq_sj_candidate_cmp(Item_in_subselect* el1, Item_in_subselect* el2,
Item_in_subselect* const *el2) void *arg)
{ {
return ((*el1)->sj_convert_priority < (*el2)->sj_convert_priority) ? 1 : return (el1->sj_convert_priority > el2->sj_convert_priority) ? 1 :
( ((*el1)->sj_convert_priority == (*el2)->sj_convert_priority)? 0 : -1); ( (el1->sj_convert_priority == el2->sj_convert_priority)? 0 : -1);
} }

View File

@ -603,9 +603,11 @@ int mysql_multi_delete_prepare(THD *thd)
&thd->lex->select_lex.top_join_list, &thd->lex->select_lex.top_join_list,
lex->query_tables, lex->query_tables,
lex->select_lex.leaf_tables, FALSE, lex->select_lex.leaf_tables, FALSE,
DELETE_ACL, SELECT_ACL, TRUE)) DELETE_ACL, SELECT_ACL, FALSE))
DBUG_RETURN(TRUE); 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 Multi-delete can't be constructed over-union => we always have

View File

@ -346,10 +346,17 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived)
if (derived->merged) if (derived->merged)
return FALSE; return FALSE;
if (thd->lex->sql_command == SQLCOM_UPDATE_MULTI ||
thd->lex->sql_command == SQLCOM_DELETE_MULTI)
thd->save_prep_leaf_list= TRUE;
arena= thd->activate_stmt_arena_if_needed(&backup); // For easier test arena= thd->activate_stmt_arena_if_needed(&backup); // For easier test
derived->merged= TRUE; derived->merged= TRUE;
if (!derived->merged_for_insert) if (!derived->merged_for_insert ||
(derived->is_multitable() &&
(thd->lex->sql_command == SQLCOM_UPDATE_MULTI ||
thd->lex->sql_command == SQLCOM_DELETE_MULTI)))
{ {
/* /*
Check whether there is enough free bits in table map to merge subquery. Check whether there is enough free bits in table map to merge subquery.
@ -392,7 +399,7 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived)
} }
/* Merge derived table's subquery in the parent select. */ /* Merge derived table's subquery in the parent select. */
if (parent_lex->merge_subquery(derived, dt_select, tablenr, map)) if (parent_lex->merge_subquery(thd, derived, dt_select, tablenr, map))
{ {
res= TRUE; res= TRUE;
goto exit_merge; goto exit_merge;
@ -468,8 +475,6 @@ exit_merge:
bool mysql_derived_merge_for_insert(THD *thd, LEX *lex, TABLE_LIST *derived) bool mysql_derived_merge_for_insert(THD *thd, LEX *lex, TABLE_LIST *derived)
{ {
SELECT_LEX *dt_select= derived->get_single_select();
if (derived->merged_for_insert) if (derived->merged_for_insert)
return FALSE; return FALSE;
if (derived->is_materialized_derived()) if (derived->is_materialized_derived())
@ -482,43 +487,13 @@ bool mysql_derived_merge_for_insert(THD *thd, LEX *lex, TABLE_LIST *derived)
{ {
if (!derived->updatable) if (!derived->updatable)
return derived->create_field_translation(thd); return derived->create_field_translation(thd);
TABLE_LIST *tl=((TABLE_LIST*)dt_select->table_list.first); if (derived->merge_underlying_list)
TABLE *table= tl->table;
/* preserve old map & tablenr. */
if (!derived->merged_for_insert && derived->table)
table->set_table_map(derived->table->map, derived->table->tablenr);
derived->table= table;
derived->schema_table=
((TABLE_LIST*)dt_select->table_list.first)->schema_table;
if (!derived->merged)
{ {
Query_arena *arena, backup; derived->table= derived->merge_underlying_list->table;
arena= thd->activate_stmt_arena_if_needed(&backup); // For easier test derived->schema_table= derived->merge_underlying_list->schema_table;
derived->select_lex->leaf_tables.push_back(tl); derived->merged_for_insert= TRUE;
derived->nested_join= (NESTED_JOIN*) thd->calloc(sizeof(NESTED_JOIN)); }
if (derived->nested_join) }
{
derived->wrap_into_nested_join(tl->select_lex->top_join_list);
derived->get_unit()->exclude_level();
}
if (arena)
thd->restore_active_arena(arena, &backup);
derived->merged= TRUE;
if (!derived->nested_join)
return TRUE;
}
}
else
{
if (thd->lex->sql_command == SQLCOM_UPDATE_MULTI ||
thd->lex->sql_command == SQLCOM_DELETE_MULTI)
thd->save_prep_leaf_list= TRUE;
if (!derived->merged_for_insert && mysql_derived_merge(thd, lex, derived))
return TRUE;
}
derived->merged_for_insert= TRUE;
return FALSE; return FALSE;
} }

View File

@ -135,7 +135,7 @@ bool check_view_single_update(List<Item> &fields, List<Item> *values,
A buffer for the insert values was allocated for the merged view. A buffer for the insert values was allocated for the merged view.
Use it. Use it.
*/ */
//tbl->table->insert_values= view->table->insert_values; tbl->table->insert_values= view->table->insert_values;
view->table= tbl->table; view->table= tbl->table;
*map= tables; *map= tables;

View File

@ -1647,6 +1647,7 @@ void st_select_lex::init_select()
{ {
st_select_lex_node::init_select(); st_select_lex_node::init_select();
sj_nests.empty(); sj_nests.empty();
sj_subselects.empty();
group_list.empty(); group_list.empty();
type= db= 0; type= db= 0;
having= 0; having= 0;
@ -3235,12 +3236,6 @@ bool st_select_lex::get_free_table_map(table_map *map, uint *tablenr)
*map= 0; *map= 0;
*tablenr= 0; *tablenr= 0;
TABLE_LIST *tl; TABLE_LIST *tl;
if (!join)
{
(*map)= 1<<1;
(*tablenr)++;
return FALSE;
}
List_iterator<TABLE_LIST> ti(leaf_tables); List_iterator<TABLE_LIST> ti(leaf_tables);
while ((tl= ti++)) while ((tl= ti++))
{ {
@ -3397,7 +3392,8 @@ void st_select_lex::remap_tables(TABLE_LIST *derived, table_map map,
@return FALSE ok @return FALSE ok
*/ */
bool SELECT_LEX::merge_subquery(TABLE_LIST *derived, SELECT_LEX *subq_select, bool SELECT_LEX::merge_subquery(THD *thd, TABLE_LIST *derived,
SELECT_LEX *subq_select,
uint table_no, table_map map) uint table_no, table_map map)
{ {
derived->wrap_into_nested_join(subq_select->top_join_list); derived->wrap_into_nested_join(subq_select->top_join_list);
@ -3405,19 +3401,17 @@ bool SELECT_LEX::merge_subquery(TABLE_LIST *derived, SELECT_LEX *subq_select,
leaf_tables.concat(&subq_select->leaf_tables); leaf_tables.concat(&subq_select->leaf_tables);
ftfunc_list->concat(subq_select->ftfunc_list); ftfunc_list->concat(subq_select->ftfunc_list);
if (join) if (join ||
thd->lex->sql_command == SQLCOM_UPDATE_MULTI ||
thd->lex->sql_command == SQLCOM_DELETE_MULTI)
{ {
Item_in_subselect **in_subq; List_iterator_fast<Item_in_subselect> li(subq_select->sj_subselects);
Item_in_subselect **in_subq_end; Item_in_subselect *in_subq;
for (in_subq= subq_select->join->sj_subselects.front(), while ((in_subq= li++))
in_subq_end= subq_select->join->sj_subselects.back();
in_subq != in_subq_end;
in_subq++)
{ {
join->sj_subselects.append(join->thd->mem_root, *in_subq); sj_subselects.push_back(in_subq);
DBUG_ASSERT((*in_subq)->emb_on_expr_nest != NULL); if (in_subq->emb_on_expr_nest == NO_JOIN_NEST)
if ((*in_subq)->emb_on_expr_nest == NO_JOIN_NEST) in_subq->emb_on_expr_nest= derived;
(*in_subq)->emb_on_expr_nest= derived;
} }
} }
/* /*

View File

@ -637,6 +637,12 @@ public:
tables. Unlike 'next_local', this in this list views are *not* tables. Unlike 'next_local', this in this list views are *not*
leaves. Created in setup_tables() -> make_leaves_list(). leaves. Created in setup_tables() -> make_leaves_list().
*/ */
/*
Subqueries that will need to be converted to semi-join nests, including
those converted to jtbm nests. The list is emptied when conversion is done.
*/
List<Item_in_subselect> sj_subselects;
List<TABLE_LIST> leaf_tables; List<TABLE_LIST> leaf_tables;
List<TABLE_LIST> leaf_tables_exec; List<TABLE_LIST> leaf_tables_exec;
List<TABLE_LIST> leaf_tables_prep; List<TABLE_LIST> leaf_tables_prep;
@ -886,7 +892,7 @@ public:
void remove_table_from_list(TABLE_LIST *table); void remove_table_from_list(TABLE_LIST *table);
void remap_tables(TABLE_LIST *derived, table_map map, void remap_tables(TABLE_LIST *derived, table_map map,
uint tablenr, st_select_lex *parent_lex); uint tablenr, st_select_lex *parent_lex);
bool merge_subquery(TABLE_LIST *derived, st_select_lex *subq_lex, bool merge_subquery(THD *thd, TABLE_LIST *derived, st_select_lex *subq_lex,
uint tablenr, table_map map); uint tablenr, table_map map);
inline bool is_mergeable() inline bool is_mergeable()
{ {

View File

@ -13033,7 +13033,7 @@ void setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps)
*/ */
TABLE * TABLE *
create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
ORDER *group, bool distinct, bool save_sum_fields, ORDER *group, bool distinct, bool save_sum_fields,
ulonglong select_options, ha_rows rows_limit, ulonglong select_options, ha_rows rows_limit,
char *table_alias, bool do_not_open) char *table_alias, bool do_not_open)

View File

@ -964,11 +964,6 @@ public:
bool optimized; ///< flag to avoid double optimization in EXPLAIN bool optimized; ///< flag to avoid double optimization in EXPLAIN
bool initialized; ///< flag to avoid double init_execution calls bool initialized; ///< flag to avoid double init_execution calls
/*
Subqueries that will need to be converted to semi-join nests, including
those converted to jtbm nests. The list is emptied when conversion is done.
*/
Array<Item_in_subselect> sj_subselects;
/* /*
Additional WHERE and HAVING predicates to be considered for IN=>EXISTS Additional WHERE and HAVING predicates to be considered for IN=>EXISTS
subquery transformation of a JOIN object. subquery transformation of a JOIN object.
@ -998,7 +993,7 @@ public:
JOIN(THD *thd_arg, List<Item> &fields_arg, ulonglong select_options_arg, JOIN(THD *thd_arg, List<Item> &fields_arg, ulonglong select_options_arg,
select_result *result_arg) select_result *result_arg)
:fields_list(fields_arg), sj_subselects(thd_arg->mem_root, 4) :fields_list(fields_arg)
{ {
init(thd_arg, fields_arg, select_options_arg, result_arg); init(thd_arg, fields_arg, select_options_arg, result_arg);
} }

View File

@ -248,6 +248,7 @@ int mysql_update(THD *thd,
DBUG_RETURN(1); DBUG_RETURN(1);
close_tables_for_reopen(thd, &table_list); close_tables_for_reopen(thd, &table_list);
} }
if (table_list->handle_derived(thd->lex, DT_MERGE_FOR_INSERT)) if (table_list->handle_derived(thd->lex, DT_MERGE_FOR_INSERT))
DBUG_RETURN(1); DBUG_RETURN(1);
if (table_list->handle_derived(thd->lex, DT_PREPARE)) if (table_list->handle_derived(thd->lex, DT_PREPARE))
@ -1037,10 +1038,10 @@ reopen_tables:
second time, but this call will do nothing (there are check for second second time, but this call will do nothing (there are check for second
call in setup_tables()). call in setup_tables()).
*/ */
//We need to merge for insert prior to prepare. //We need to merge for insert prior to prepare.
if (mysql_handle_derived(lex, DT_MERGE_FOR_INSERT)) if (mysql_handle_derived(lex, DT_MERGE_FOR_INSERT))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
if (mysql_handle_derived(lex, DT_PREPARE)) if (mysql_handle_derived(lex, DT_PREPARE))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
@ -1048,7 +1049,10 @@ reopen_tables:
&lex->select_lex.top_join_list, &lex->select_lex.top_join_list,
table_list, table_list,
lex->select_lex.leaf_tables, FALSE, lex->select_lex.leaf_tables, FALSE,
UPDATE_ACL, SELECT_ACL, TRUE)) UPDATE_ACL, SELECT_ACL, FALSE))
DBUG_RETURN(TRUE);
if (lex->select_lex.handle_derived(thd->lex, DT_MERGE))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
if (setup_fields_with_no_wrap(thd, 0, *fields, MARK_COLUMNS_WRITE, 0, 0)) if (setup_fields_with_no_wrap(thd, 0, *fields, MARK_COLUMNS_WRITE, 0, 0))
@ -1334,13 +1338,6 @@ int multi_update::prepare(List<Item> &not_used_values,
thd->cuted_fields=0L; thd->cuted_fields=0L;
thd_proc_info(thd, "updating main table"); thd_proc_info(thd, "updating main table");
SELECT_LEX *select_lex= lex_unit->first_select();
if (select_lex->first_cond_optimization)
{
if (select_lex->handle_derived(thd->lex, DT_MERGE))
DBUG_RETURN(TRUE);
}
tables_to_update= get_table_map(fields); tables_to_update= get_table_map(fields);
if (!tables_to_update) if (!tables_to_update)