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:
@ -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
|
|||||||
|
|
||||||
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;
|
||||||
|
@ -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");
|
||||||
|
@ -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);
|
|||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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)
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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()
|
|||||||
{
|
{
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
@ -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()
|
||||||
{
|
{
|
||||||
|
@ -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:
|
|||||||
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);
|
||||||
}
|
}
|
||||||
|
@ -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> ¬_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)
|
||||||
|
Reference in New Issue
Block a user