Commit d37465a9 authored by Igor Babaev's avatar Igor Babaev

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.
parent 6e541385
...@@ -1003,3 +1003,16 @@ Warnings: ...@@ -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;
...@@ -582,3 +582,21 @@ SELECT * FROM t2 RIGHT JOIN v1 AS t ON t.a != 0 ...@@ -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;
...@@ -1147,6 +1147,7 @@ Item_in_subselect::Item_in_subselect(Item * left_exp, ...@@ -1147,6 +1147,7 @@ Item_in_subselect::Item_in_subselect(Item * left_exp,
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");
......
...@@ -458,6 +458,11 @@ public: ...@@ -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.
......
...@@ -177,8 +177,8 @@ bool subquery_types_allow_materialization(Item_in_subselect *in_subs); ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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);
} }
......
...@@ -603,9 +603,11 @@ int mysql_multi_delete_prepare(THD *thd) ...@@ -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
......
...@@ -346,10 +346,17 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived) ...@@ -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) ...@@ -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: ...@@ -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) ...@@ -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;
} }
......
...@@ -135,7 +135,7 @@ bool check_view_single_update(List<Item> &fields, List<Item> *values, ...@@ -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;
......
...@@ -1647,6 +1647,7 @@ void st_select_lex::init_select() ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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 ||
Item_in_subselect **in_subq; thd->lex->sql_command == SQLCOM_DELETE_MULTI)
Item_in_subselect **in_subq_end; {
for (in_subq= subq_select->join->sj_subselects.front(), List_iterator_fast<Item_in_subselect> li(subq_select->sj_subselects);
in_subq_end= subq_select->join->sj_subselects.back(); Item_in_subselect *in_subq;
in_subq != in_subq_end; while ((in_subq= li++))
in_subq++) {
{ sj_subselects.push_back(in_subq);
join->sj_subselects.append(join->thd->mem_root, *in_subq); if (in_subq->emb_on_expr_nest == NO_JOIN_NEST)
DBUG_ASSERT((*in_subq)->emb_on_expr_nest != NULL); in_subq->emb_on_expr_nest= derived;
if ((*in_subq)->emb_on_expr_nest == NO_JOIN_NEST)
(*in_subq)->emb_on_expr_nest= derived;
} }
} }
/* /*
......
...@@ -637,6 +637,12 @@ public: ...@@ -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: ...@@ -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()
{ {
......
...@@ -13033,7 +13033,7 @@ void setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps) ...@@ -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)
......
...@@ -964,11 +964,6 @@ public: ...@@ -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: ...@@ -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);
} }
......
...@@ -248,6 +248,7 @@ int mysql_update(THD *thd, ...@@ -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: ...@@ -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: ...@@ -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, ...@@ -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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment