summaryrefslogtreecommitdiff
path: root/sql/opt_subselect.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/opt_subselect.cc')
-rw-r--r--sql/opt_subselect.cc127
1 files changed, 69 insertions, 58 deletions
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index bd07bb63ceb..5d97d016499 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -177,8 +177,8 @@ bool subquery_types_allow_materialization(Item_in_subselect *in_subs);
static bool replace_where_subcondition(JOIN *join, Item **expr,
Item *old_cond, Item *new_cond,
bool do_fix_fields);
-static int subq_sj_candidate_cmp(Item_in_subselect* const *el1,
- Item_in_subselect* const *el2);
+static int subq_sj_candidate_cmp(Item_in_subselect* el1, Item_in_subselect* el2,
+ void *arg);
static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred);
static bool convert_subq_to_jtbm(JOIN *parent_join,
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;
/* Register the subquery for further processing in flatten_subqueries() */
- select_lex->
- outer_select()->join->sj_subselects.append(thd->mem_root, in_subs);
+ if (!in_subs->is_registered_semijoin)
+ {
+ 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
{
@@ -405,7 +412,7 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
condition also excludes multi-table update statements.
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
- 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
@@ -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->is_flattenable_semijoin= FALSE;
- select_lex->outer_select()->
- join->sj_subselects.append(thd->mem_root, in_subs);
+ if (!in_subs->is_registered_semijoin)
+ {
+ 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)
{
Query_arena *arena, backup;
- Item_in_subselect **in_subq;
- Item_in_subselect **in_subq_end;
+ Item_in_subselect *in_subq;
THD *thd= join->thd;
List_iterator<TABLE_LIST> ti(join->select_lex->leaf_tables);
DBUG_ENTER("convert_join_subqueries_to_semijoins");
- if (join->sj_subselects.elements() == 0)
+ if (join->select_lex->sj_subselects.is_empty())
DBUG_RETURN(FALSE);
- for (in_subq= join->sj_subselects.front(),
- in_subq_end= join->sj_subselects.back();
- in_subq != in_subq_end;
- in_subq++)
+ List_iterator_fast<Item_in_subselect> li(join->select_lex->sj_subselects);
+
+ while ((in_subq= li++))
{
- 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))
DBUG_RETURN(1);
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();
}
+ li.rewind();
/* First, convert child join's subqueries. We proceed bottom-up here */
- for (in_subq= join->sj_subselects.front(),
- in_subq_end= join->sj_subselects.back();
- in_subq != in_subq_end;
- in_subq++)
+ while ((in_subq= li++))
{
- 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;
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))
DBUG_RETURN(TRUE);
- (*in_subq)->sj_convert_priority=
- 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->sj_convert_priority=
+ test(in_subq->emb_on_expr_nest != NO_JOIN_NEST) * MAX_TABLES * 2 +
+ in_subq->is_correlated * MAX_TABLES + child_join->outer_tables;
}
// 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 (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);
goto skip_conversion;
}
@@ -795,41 +805,41 @@ bool convert_join_subqueries_to_semijoins(JOIN *join)
- prefer correlated subqueries over uncorrelated;
- 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
/* Replace all subqueries to be flattened with Item_int(1) */
arena= thd->activate_stmt_arena_if_needed(&backup);
- for (in_subq= join->sj_subselects.front();
- in_subq != in_subq_end;
- in_subq++)
+ li.rewind();
+ while ((in_subq= li++))
{
bool remove_item= TRUE;
/* 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;
- if ((*in_subq)->is_flattenable_semijoin)
+ if (in_subq->is_flattenable_semijoin)
{
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;
- if (convert_subq_to_sj(join, *in_subq))
+ if (convert_subq_to_sj(join, in_subq))
DBUG_RETURN(TRUE);
}
else
{
if (join->table_count + 1 >= MAX_TABLES)
break;
- if (convert_subq_to_jtbm(join, *in_subq, &remove_item))
+ if (convert_subq_to_jtbm(join, in_subq, &remove_item))
DBUG_RETURN(TRUE);
}
if (remove_item)
{
- Item **tree= ((*in_subq)->emb_on_expr_nest == NO_JOIN_NEST)?
- &join->conds : &((*in_subq)->emb_on_expr_nest->on_expr);
- Item *replace_me= (*in_subq)->original_item();
+ Item **tree= (in_subq->emb_on_expr_nest == NO_JOIN_NEST)?
+ &join->conds : &(in_subq->emb_on_expr_nest->on_expr);
+ Item *replace_me= in_subq->original_item();
if (replace_where_subcondition(join, tree, replace_me, new Item_int(1),
FALSE))
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
convert:
*/
- for (; in_subq!= in_subq_end; in_subq++)
+ while (in_subq)
{
- JOIN *child_join= (*in_subq)->unit->first_select()->join;
- (*in_subq)->changed= 0;
- (*in_subq)->fixed= 0;
+ JOIN *child_join= in_subq->unit->first_select()->join;
+ in_subq->changed= 0;
+ in_subq->fixed= 0;
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;
if (res)
DBUG_RETURN(TRUE);
- (*in_subq)->changed= 1;
- (*in_subq)->fixed= 1;
+ in_subq->changed= 1;
+ in_subq->fixed= 1;
- Item *substitute= (*in_subq)->substitution;
- bool do_fix_fields= !(*in_subq)->substitution->fixed;
- Item **tree= ((*in_subq)->emb_on_expr_nest == NO_JOIN_NEST)?
- &join->conds : &((*in_subq)->emb_on_expr_nest->on_expr);
- Item *replace_me= (*in_subq)->original_item();
+ Item *substitute= in_subq->substitution;
+ bool do_fix_fields= !in_subq->substitution->fixed;
+ Item **tree= (in_subq->emb_on_expr_nest == NO_JOIN_NEST)?
+ &join->conds : &(in_subq->emb_on_expr_nest->on_expr);
+ Item *replace_me= in_subq->original_item();
if (replace_where_subcondition(join, tree, replace_me, substitute,
do_fix_fields))
DBUG_RETURN(TRUE);
- (*in_subq)->substitution= NULL;
+ in_subq->substitution= NULL;
#if 0
/*
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())
{
- 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 :
- &((*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,
FALSE))
@@ -898,12 +908,13 @@ bool convert_join_subqueries_to_semijoins(JOIN *join)
re-run the test for materialization that was done in
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)
thd->restore_active_arena(arena, &backup);
- join->sj_subselects.clear();
+ join->select_lex->sj_subselects.empty();
DBUG_RETURN(FALSE);
}
@@ -1004,11 +1015,11 @@ static bool replace_where_subcondition(JOIN *join, Item **expr,
return TRUE;
}
-static int subq_sj_candidate_cmp(Item_in_subselect* const *el1,
- Item_in_subselect* const *el2)
+static int subq_sj_candidate_cmp(Item_in_subselect* el1, Item_in_subselect* el2,
+ void *arg)
{
- return ((*el1)->sj_convert_priority < (*el2)->sj_convert_priority) ? 1 :
- ( ((*el1)->sj_convert_priority == (*el2)->sj_convert_priority)? 0 : -1);
+ return (el1->sj_convert_priority > el2->sj_convert_priority) ? 1 :
+ ( (el1->sj_convert_priority == el2->sj_convert_priority)? 0 : -1);
}