1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-07 00:04:31 +03:00

Merge with the latest 5.3 code.

This commit is contained in:
Igor Babaev
2011-07-17 00:52:07 -07:00
17 changed files with 323 additions and 184 deletions

View File

@@ -590,6 +590,31 @@ f1 f1
DROP VIEW v1; DROP VIEW v1;
DROP TABLE t1,t2; DROP TABLE t1,t2;
# #
# LP bug #794890: abort failure on multi-update with view
#
CREATE TABLE t1 (a int);
INSERT INTO t1 VALUES (20), (7);
CREATE TABLE t2 (a int);
INSERT INTO t2 VALUES (7), (9), (7);
CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT a FROM t1;
CREATE VIEW v2 AS SELECT t2.a FROM t2, v1 WHERE t2.a=t2.a;
UPDATE v2 SET a = 2;
SELECT * FROM t2;
a
2
2
2
UPDATE t1,v2 SET t1.a = 3;
SELECT * FROM t1;
a
3
3
DELETE t1 FROM t1,v2;
SELECT * FROM t1;
a
DROP VIEW v1,v2;
DROP TABLE t1,t2;
#
# LP bug #802023: MIN/MAX optimization # LP bug #802023: MIN/MAX optimization
# for mergeable derived tables and views # for mergeable derived tables and views
# #
@@ -1078,3 +1103,16 @@ Warnings:
Note 1003 select 6 AS `a`,5 AS `b` from `test`.`t1` join `test`.`t2` left join `test`.`t3` on((0 <> 0)) where (not(<in_optimizer>((6,5),<exists>(select 7,5 having (trigcond(((<cache>(6) = 7) or isnull(7))) and trigcond(((<cache>(5) = 5) or isnull(5))) and trigcond(<is_not_null_test>(7)) and trigcond(<is_not_null_test>(5))))))) Note 1003 select 6 AS `a`,5 AS `b` from `test`.`t1` join `test`.`t2` left join `test`.`t3` on((0 <> 0)) where (not(<in_optimizer>((6,5),<exists>(select 7,5 having (trigcond(((<cache>(6) = 7) or isnull(7))) and trigcond(((<cache>(5) = 5) or isnull(5))) and trigcond(<is_not_null_test>(7)) and trigcond(<is_not_null_test>(5)))))))
DROP VIEW v1; DROP VIEW v1;
DROP TABLE t1,t2,t3; DROP TABLE t1,t2,t3;
#
# 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

@@ -236,6 +236,30 @@ SELECT * FROM v1 JOIN t2 ON v1.f1 = t2.f1;
DROP VIEW v1; DROP VIEW v1;
DROP TABLE t1,t2; DROP TABLE t1,t2;
--echo #
--echo # LP bug #794890: abort failure on multi-update with view
--echo #
CREATE TABLE t1 (a int);
INSERT INTO t1 VALUES (20), (7);
CREATE TABLE t2 (a int);
INSERT INTO t2 VALUES (7), (9), (7);
CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT a FROM t1;
CREATE VIEW v2 AS SELECT t2.a FROM t2, v1 WHERE t2.a=t2.a;
UPDATE v2 SET a = 2;
SELECT * FROM t2;
UPDATE t1,v2 SET t1.a = 3;
SELECT * FROM t1;
DELETE t1 FROM t1,v2;
SELECT * FROM t1;
DROP VIEW v1,v2;
DROP TABLE t1,t2;
--echo # --echo #
--echo # LP bug #802023: MIN/MAX optimization --echo # LP bug #802023: MIN/MAX optimization
--echo # for mergeable derived tables and views --echo # for mergeable derived tables and views
@@ -626,3 +650,21 @@ SELECT t.a,t.b FROM t3 RIGHT JOIN (v1 AS t, t2) ON t2.b != 0
DROP VIEW v1; DROP VIEW v1;
DROP TABLE t1,t2,t3; DROP TABLE t1,t2,t3;
--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

@@ -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");

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

@@ -7794,8 +7794,17 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
if (select_lex->first_cond_optimization) if (select_lex->first_cond_optimization)
{ {
leaves.empty(); leaves.empty();
select_lex->leaf_tables_exec.empty(); if (!select_lex->is_prep_leaf_list_saved)
{
make_leaves_list(leaves, tables, full_table_list, first_select_table); make_leaves_list(leaves, tables, full_table_list, first_select_table);
select_lex->leaf_tables_exec.empty();
}
else
{
List_iterator_fast <TABLE_LIST> ti(select_lex->leaf_tables_prep);
while ((table_list= ti++))
leaves.push_back(table_list);
}
while ((table_list= ti++)) while ((table_list= ti++))
{ {

View File

@@ -817,6 +817,7 @@ THD::THD()
memset(&invoker_host, 0, sizeof(invoker_host)); memset(&invoker_host, 0, sizeof(invoker_host));
prepare_derived_at_open= FALSE; prepare_derived_at_open= FALSE;
create_tmp_table_for_derived= FALSE; create_tmp_table_for_derived= FALSE;
save_prep_leaf_list= FALSE;
} }

View File

@@ -1601,6 +1601,8 @@ public:
*/ */
bool create_tmp_table_for_derived; bool create_tmp_table_for_derived;
bool save_prep_leaf_list;
#ifndef MYSQL_CLIENT #ifndef MYSQL_CLIENT
int binlog_setup_trx_data(); int binlog_setup_trx_data();

View File

@@ -61,8 +61,9 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (open_and_lock_tables(thd, table_list)) if (open_and_lock_tables(thd, table_list))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
if (mysql_handle_list_of_derived(thd->lex, table_list, DT_MERGE_FOR_INSERT) || if (mysql_handle_list_of_derived(thd->lex, table_list, DT_MERGE_FOR_INSERT))
mysql_handle_list_of_derived(thd->lex, table_list, DT_PREPARE)) DBUG_RETURN(TRUE);
if (mysql_handle_list_of_derived(thd->lex, table_list, DT_PREPARE))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
if (!table_list->updatable) if (!table_list->updatable)
@@ -586,10 +587,11 @@ int mysql_multi_delete_prepare(THD *thd)
TABLE_LIST *target_tbl; TABLE_LIST *target_tbl;
DBUG_ENTER("mysql_multi_delete_prepare"); DBUG_ENTER("mysql_multi_delete_prepare");
TABLE_LIST *tables= lex->query_tables; if (mysql_handle_derived(lex, DT_INIT))
if (mysql_handle_derived(lex, DT_INIT) || DBUG_RETURN(TRUE);
mysql_handle_list_of_derived(lex, tables, DT_MERGE_FOR_INSERT) || if (mysql_handle_derived(lex, DT_MERGE_FOR_INSERT))
mysql_handle_list_of_derived(lex, tables, DT_PREPARE)) DBUG_RETURN(TRUE);
if (mysql_handle_derived(lex, DT_PREPARE))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
/* /*
setup_tables() need for VIEWs. JOIN::prepare() will not do it second setup_tables() need for VIEWs. JOIN::prepare() will not do it second
@@ -601,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
@@ -616,7 +620,8 @@ int mysql_multi_delete_prepare(THD *thd)
target_tbl= target_tbl->next_local) target_tbl= target_tbl->next_local)
{ {
if (!(target_tbl->table= target_tbl->correspondent_table->table)) target_tbl->table= target_tbl->correspondent_table->table;
if (target_tbl->correspondent_table->is_multitable())
{ {
my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
target_tbl->correspondent_table->view_db.str, target_tbl->correspondent_table->view_db.str,
@@ -651,6 +656,10 @@ int mysql_multi_delete_prepare(THD *thd)
with further calls to unique_table with further calls to unique_table
*/ */
lex->select_lex.exclude_from_table_unique_test= FALSE; lex->select_lex.exclude_from_table_unique_test= FALSE;
if (lex->select_lex.save_prep_leaf_tables(thd))
DBUG_RETURN(TRUE);
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }

View File

@@ -85,15 +85,18 @@ mysql_handle_derived(LEX *lex, uint phases)
cursor && !res; cursor && !res;
cursor= cursor->next_local) cursor= cursor->next_local)
{ {
if (!cursor->is_view_or_derived() && phases == DT_MERGE_FOR_INSERT)
continue;
uint8 allowed_phases= (cursor->is_merged_derived() ? DT_PHASES_MERGE : uint8 allowed_phases= (cursor->is_merged_derived() ? DT_PHASES_MERGE :
DT_PHASES_MATERIALIZE); DT_PHASES_MATERIALIZE | DT_MERGE_FOR_INSERT);
/* /*
Skip derived tables to which the phase isn't applicable. Skip derived tables to which the phase isn't applicable.
TODO: mark derived at the parse time, later set it's type TODO: mark derived at the parse time, later set it's type
(merged or materialized) (merged or materialized)
*/ */
if ((phase_flag != DT_PREPARE && !(allowed_phases & phase_flag)) || if ((phase_flag != DT_PREPARE && !(allowed_phases & phase_flag)) ||
(cursor->merged_for_insert && phase_flag != DT_REINIT)) (cursor->merged_for_insert && phase_flag != DT_REINIT &&
phase_flag != DT_PREPARE))
continue; continue;
res= (*processors[phase])(lex->thd, lex, cursor); res= (*processors[phase])(lex->thd, lex, cursor);
} }
@@ -343,8 +346,18 @@ 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 ||
(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.
If not - materialize it. This check isn't cached so when there is a big If not - materialize it. This check isn't cached so when there is a big
@@ -378,8 +391,7 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived)
make_leaves_list(dt_select->leaf_tables, derived, TRUE, 0); make_leaves_list(dt_select->leaf_tables, derived, TRUE, 0);
} }
if (!derived->merged_for_insert) derived->nested_join= (NESTED_JOIN*) thd->calloc(sizeof(NESTED_JOIN));
{ derived->nested_join= (NESTED_JOIN*) thd->calloc(sizeof(NESTED_JOIN));
if (!derived->nested_join) if (!derived->nested_join)
{ {
res= TRUE; res= TRUE;
@@ -387,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;
@@ -463,52 +475,25 @@ 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;
/* It's a target view for an INSERT, create field translation only. */ if (derived->is_materialized_derived())
if (!derived->updatable || derived->is_materialized_derived())
{ {
bool res= derived->create_field_translation(thd); bool res= mysql_derived_prepare(thd, lex, derived);
derived->select_lex->leaf_tables.push_back(derived);
return res; return res;
} }
if (!derived->is_multitable()) if (!derived->is_multitable())
{ {
TABLE_LIST *tl=((TABLE_LIST*)dt_select->table_list.first); if (!derived->updatable)
TABLE *table= tl->table; return derived->create_field_translation(thd);
/* preserve old map & tablenr. */ if (derived->merge_underlying_list)
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->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 (!derived->merged_for_insert && mysql_derived_merge(thd, lex, derived))
return TRUE;
}
derived->merged_for_insert= TRUE; derived->merged_for_insert= TRUE;
}
}
return FALSE; return FALSE;
} }
@@ -609,7 +594,11 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
bool res= FALSE; bool res= FALSE;
// Skip already prepared views/DT // Skip already prepared views/DT
if (!unit || unit->prepared || derived->merged_for_insert) if (!unit || unit->prepared ||
(derived->merged_for_insert &&
!(derived->is_multitable() &&
(thd->lex->sql_command == SQLCOM_UPDATE_MULTI ||
thd->lex->sql_command == SQLCOM_DELETE_MULTI))))
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
Query_arena *arena= thd->stmt_arena, backup; Query_arena *arena= thd->stmt_arena, backup;

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

@@ -1604,6 +1604,7 @@ void st_select_lex::init_query()
top_join_list.empty(); top_join_list.empty();
join_list= &top_join_list; join_list= &top_join_list;
embedding= 0; embedding= 0;
leaf_tables_prep.empty();
leaf_tables.empty(); leaf_tables.empty();
item_list.empty(); item_list.empty();
join= 0; join= 0;
@@ -1646,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;
@@ -1672,6 +1674,7 @@ void st_select_lex::init_select()
cond_value= having_value= Item::COND_UNDEF; cond_value= having_value= Item::COND_UNDEF;
inner_refs_list.empty(); inner_refs_list.empty();
full_group_by_flag= 0; full_group_by_flag= 0;
is_prep_leaf_list_saved= FALSE;
insert_tables= 0; insert_tables= 0;
merged_into= 0; merged_into= 0;
} }
@@ -3233,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++))
{ {
@@ -3395,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);
@@ -3403,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;
} }
} }
/* /*
@@ -3628,6 +3624,7 @@ void SELECT_LEX::mark_const_derived(bool empty)
} }
} }
bool st_select_lex::save_leaf_tables(THD *thd) bool st_select_lex::save_leaf_tables(THD *thd)
{ {
Query_arena *arena= thd->stmt_arena, backup; Query_arena *arena= thd->stmt_arena, backup;
@@ -3652,6 +3649,33 @@ bool st_select_lex::save_leaf_tables(THD *thd)
} }
bool st_select_lex::save_prep_leaf_tables(THD *thd)
{
if (!thd->save_prep_leaf_list)
return 0;
Query_arena *arena= thd->stmt_arena, backup;
if (arena->is_conventional())
arena= 0;
else
thd->set_n_backup_active_arena(arena, &backup);
List_iterator_fast<TABLE_LIST> li(leaf_tables);
TABLE_LIST *table;
while ((table= li++))
{
if (leaf_tables_prep.push_back(table))
return 1;
}
thd->lex->select_lex.is_prep_leaf_list_saved= TRUE;
thd->save_prep_leaf_list= FALSE;
if (arena)
thd->restore_active_arena(arena, &backup);
return 0;
}
/** /**
A routine used by the parser to decide whether we are specifying a full A routine used by the parser to decide whether we are specifying a full
partitioning or if only partitions to add or to split. partitioning or if only partitions to add or to split.

View File

@@ -637,8 +637,16 @@ 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;
bool is_prep_leaf_list_saved;
uint insert_tables; uint insert_tables;
st_select_lex *merged_into; /* select which this select is merged into */ st_select_lex *merged_into; /* select which this select is merged into */
/* (not 0 only for views/derived tables) */ /* (not 0 only for views/derived tables) */
@@ -884,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()
{ {
@@ -899,6 +907,7 @@ public:
void mark_const_derived(bool empty); void mark_const_derived(bool empty);
bool save_leaf_tables(THD *thd); bool save_leaf_tables(THD *thd);
bool save_prep_leaf_tables(THD *thd);
private: private:
/* current index hint kind. used in filling up index_hints */ /* current index hint kind. used in filling up index_hints */

View File

@@ -1269,8 +1269,9 @@ static int mysql_test_update(Prepared_statement *stmt,
thd->fill_derived_tables() is false here for sure (because it is thd->fill_derived_tables() is false here for sure (because it is
preparation of PS, so we even do not check it). preparation of PS, so we even do not check it).
*/ */
if (table_list->handle_derived(thd->lex, DT_MERGE_FOR_INSERT) || if (table_list->handle_derived(thd->lex, DT_MERGE_FOR_INSERT))
table_list->handle_derived(thd->lex, DT_PREPARE)) goto error;
if (table_list->handle_derived(thd->lex, DT_PREPARE))
goto error; goto error;
if (!table_list->updatable) if (!table_list->updatable)
@@ -1340,9 +1341,11 @@ static bool mysql_test_delete(Prepared_statement *stmt,
open_tables(thd, &table_list, &table_count, 0)) open_tables(thd, &table_list, &table_count, 0))
goto error; goto error;
if (mysql_handle_derived(thd->lex, DT_INIT) || if (mysql_handle_derived(thd->lex, DT_INIT))
mysql_handle_list_of_derived(thd->lex, table_list, DT_MERGE_FOR_INSERT) || goto error;
mysql_handle_list_of_derived(thd->lex, table_list, DT_PREPARE)) if (mysql_handle_derived(thd->lex, DT_MERGE_FOR_INSERT))
goto error;
if (mysql_handle_derived(thd->lex, DT_PREPARE))
goto error; goto error;
if (!table_list->updatable) if (!table_list->updatable)

View File

@@ -966,11 +966,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.
@@ -1000,7 +995,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,9 +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_list_of_derived(lex, table_list, DT_MERGE_FOR_INSERT)) if (mysql_handle_derived(lex, DT_MERGE_FOR_INSERT))
DBUG_RETURN(1); DBUG_RETURN(TRUE);
if (mysql_handle_derived(lex, DT_PREPARE)) if (mysql_handle_derived(lex, DT_PREPARE))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
@@ -1047,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))
@@ -1238,6 +1243,9 @@ reopen_tables:
*/ */
lex->select_lex.exclude_from_table_unique_test= FALSE; lex->select_lex.exclude_from_table_unique_test= FALSE;
if (lex->select_lex.save_prep_leaf_tables(thd))
DBUG_RETURN(TRUE);
DBUG_RETURN (FALSE); DBUG_RETURN (FALSE);
} }
@@ -1330,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)