Commit aa195b25 authored by unknown's avatar unknown

MWL#89: Cost-based choice between Materialization and IN->EXISTS transformation

  
Step2 in the separation of the creation of IN->EXISTS equi-join conditions from
their injection. The goal of this separation is to make it possible that the
IN->EXISTS conditions can be used for cost estimation without actually modifying
the subquery.
  
This patch separates row_value_in_to_exists_transformer() into two methods:
- create_row_value_in_to_exists_cond(), and
- inject_row_value_in_to_exists_cond()
The patch performs minimal refactoring of the code so that it is easier to solve
problems resulting from the separation. There is a lot to be simplified in this
code, but this will be done separately.
parent 78ddd9ff
...@@ -1524,16 +1524,16 @@ Item_subselect::trans_res ...@@ -1524,16 +1524,16 @@ Item_subselect::trans_res
Item_in_subselect::single_value_in_to_exists_transformer(JOIN * join, Item_in_subselect::single_value_in_to_exists_transformer(JOIN * join,
Comp_creator *func) Comp_creator *func)
{ {
Item *where_term; Item *where_item;
Item *having_term; Item *having_item;
Item_subselect::trans_res res; Item_subselect::trans_res res;
res= create_single_value_in_to_exists_cond(join, func, res= create_single_value_in_to_exists_cond(join, func,
&where_term, &having_term); &where_item, &having_item);
if (res != RES_OK) if (res != RES_OK)
return res; return res;
res= inject_single_value_in_to_exists_cond(join, func, res= inject_single_value_in_to_exists_cond(join, func,
where_term, having_term); where_item, having_item);
return res; return res;
} }
...@@ -1541,8 +1541,8 @@ Item_in_subselect::single_value_in_to_exists_transformer(JOIN * join, ...@@ -1541,8 +1541,8 @@ Item_in_subselect::single_value_in_to_exists_transformer(JOIN * join,
Item_subselect::trans_res Item_subselect::trans_res
Item_in_subselect::create_single_value_in_to_exists_cond(JOIN * join, Item_in_subselect::create_single_value_in_to_exists_cond(JOIN * join,
Comp_creator *func, Comp_creator *func,
Item **where_term, Item **where_item,
Item **having_term) Item **having_item)
{ {
SELECT_LEX *select_lex= join->select_lex; SELECT_LEX *select_lex= join->select_lex;
DBUG_ENTER("Item_in_subselect::create_single_value_in_to_exists_cond"); DBUG_ENTER("Item_in_subselect::create_single_value_in_to_exists_cond");
...@@ -1569,8 +1569,8 @@ Item_in_subselect::create_single_value_in_to_exists_cond(JOIN * join, ...@@ -1569,8 +1569,8 @@ Item_in_subselect::create_single_value_in_to_exists_cond(JOIN * join,
if (item->fix_fields(thd, 0)) if (item->fix_fields(thd, 0))
DBUG_RETURN(RES_ERROR); DBUG_RETURN(RES_ERROR);
*having_term= item; *having_item= item;
*where_term= NULL; *where_item= NULL;
} }
else else
{ {
...@@ -1595,7 +1595,7 @@ Item_in_subselect::create_single_value_in_to_exists_cond(JOIN * join, ...@@ -1595,7 +1595,7 @@ Item_in_subselect::create_single_value_in_to_exists_cond(JOIN * join,
if (having->fix_fields(thd, 0)) if (having->fix_fields(thd, 0))
DBUG_RETURN(RES_ERROR); DBUG_RETURN(RES_ERROR);
*having_term= having; *having_item= having;
item= new Item_cond_or(item, item= new Item_cond_or(item,
new Item_func_isnull(orig_item)); new Item_func_isnull(orig_item));
...@@ -1613,7 +1613,7 @@ Item_in_subselect::create_single_value_in_to_exists_cond(JOIN * join, ...@@ -1613,7 +1613,7 @@ Item_in_subselect::create_single_value_in_to_exists_cond(JOIN * join,
if (item->fix_fields(thd, 0)) if (item->fix_fields(thd, 0))
DBUG_RETURN(RES_ERROR); DBUG_RETURN(RES_ERROR);
*where_term= item; *where_item= item;
} }
else else
{ {
...@@ -1640,13 +1640,13 @@ Item_in_subselect::create_single_value_in_to_exists_cond(JOIN * join, ...@@ -1640,13 +1640,13 @@ Item_in_subselect::create_single_value_in_to_exists_cond(JOIN * join,
if (new_having->fix_fields(thd, 0)) if (new_having->fix_fields(thd, 0))
DBUG_RETURN(RES_ERROR); DBUG_RETURN(RES_ERROR);
*having_term= new_having; *having_item= new_having;
*where_term= NULL; *where_item= NULL;
} }
else else
{ {
*having_term= NULL; *having_item= NULL;
*where_term= (Item*) select_lex->item_list.head(); *where_item= (Item*) select_lex->item_list.head();
} }
} }
} }
...@@ -1659,8 +1659,8 @@ Item_in_subselect::create_single_value_in_to_exists_cond(JOIN * join, ...@@ -1659,8 +1659,8 @@ Item_in_subselect::create_single_value_in_to_exists_cond(JOIN * join,
Item_subselect::trans_res Item_subselect::trans_res
Item_in_subselect::inject_single_value_in_to_exists_cond(JOIN * join, Item_in_subselect::inject_single_value_in_to_exists_cond(JOIN * join,
Comp_creator *func, Comp_creator *func,
Item *where_term, Item *where_item,
Item *having_term) Item *having_item)
{ {
SELECT_LEX *select_lex= join->select_lex; SELECT_LEX *select_lex= join->select_lex;
bool fix_res; bool fix_res;
...@@ -1675,9 +1675,9 @@ Item_in_subselect::inject_single_value_in_to_exists_cond(JOIN * join, ...@@ -1675,9 +1675,9 @@ Item_in_subselect::inject_single_value_in_to_exists_cond(JOIN * join,
we can assign select_lex->having here, and pass 0 as last we can assign select_lex->having here, and pass 0 as last
argument (reference) to fix_fields() argument (reference) to fix_fields()
*/ */
select_lex->having= join->having= and_items(join->having, having_term); select_lex->having= join->having= and_items(join->having, having_item);
if (join->having == having_term) if (join->having == having_item)
having_term->name= (char*)in_having_cond; having_item->name= (char*)in_having_cond;
select_lex->having_fix_field= 1; select_lex->having_fix_field= 1;
/* /*
we do not check join->having->fixed, because Item_and (from and_items) we do not check join->having->fixed, because Item_and (from and_items)
...@@ -1707,8 +1707,8 @@ Item_in_subselect::inject_single_value_in_to_exists_cond(JOIN * join, ...@@ -1707,8 +1707,8 @@ Item_in_subselect::inject_single_value_in_to_exists_cond(JOIN * join,
we can assign select_lex->having here, and pass 0 as last we can assign select_lex->having here, and pass 0 as last
argument (reference) to fix_fields() argument (reference) to fix_fields()
*/ */
having_term->name= (char*)in_having_cond; having_item->name= (char*)in_having_cond;
select_lex->having= join->having= having_term; select_lex->having= join->having= having_item;
select_lex->having_fix_field= 1; select_lex->having_fix_field= 1;
/* /*
we do not check join->having->fixed, because Item_and (from we do not check join->having->fixed, because Item_and (from
...@@ -1726,14 +1726,14 @@ Item_in_subselect::inject_single_value_in_to_exists_cond(JOIN * join, ...@@ -1726,14 +1726,14 @@ Item_in_subselect::inject_single_value_in_to_exists_cond(JOIN * join,
single_value_transformer but there is no corresponding action in single_value_transformer but there is no corresponding action in
row_value_transformer? row_value_transformer?
*/ */
where_term->name= (char *)in_additional_cond; where_item->name= (char *)in_additional_cond;
/* /*
AND can't be changed during fix_fields() AND can't be changed during fix_fields()
we can assign select_lex->having here, and pass 0 as last we can assign select_lex->having here, and pass 0 as last
argument (reference) to fix_fields() argument (reference) to fix_fields()
*/ */
select_lex->where= join->conds= and_items(join->conds, where_term); select_lex->where= join->conds= and_items(join->conds, where_item);
select_lex->where->top_level_item(); select_lex->where->top_level_item();
/* /*
we do not check join->conds->fixed, because Item_and can't be fixed we do not check join->conds->fixed, because Item_and can't be fixed
...@@ -1746,8 +1746,8 @@ Item_in_subselect::inject_single_value_in_to_exists_cond(JOIN * join, ...@@ -1746,8 +1746,8 @@ Item_in_subselect::inject_single_value_in_to_exists_cond(JOIN * join,
{ {
if (select_lex->master_unit()->is_union()) if (select_lex->master_unit()->is_union())
{ {
having_term->name= (char*)in_having_cond; having_item->name= (char*)in_having_cond;
select_lex->having= join->having= having_term; select_lex->having= join->having= having_item;
select_lex->having_fix_field= 1; select_lex->having_fix_field= 1;
/* /*
...@@ -1765,11 +1765,11 @@ Item_in_subselect::inject_single_value_in_to_exists_cond(JOIN * join, ...@@ -1765,11 +1765,11 @@ Item_in_subselect::inject_single_value_in_to_exists_cond(JOIN * join,
// it is single select without tables => possible optimization // it is single select without tables => possible optimization
// remove the dependence mark since the item is moved to upper // remove the dependence mark since the item is moved to upper
// select and is not outer anymore. // select and is not outer anymore.
where_term->walk(&Item::remove_dependence_processor, 0, where_item->walk(&Item::remove_dependence_processor, 0,
(uchar *) select_lex->outer_select()); (uchar *) select_lex->outer_select());
where_term= func->create(left_expr, where_term); where_item= func->create(left_expr, where_item);
// fix_field of item will be done in time of substituting // fix_field of item will be done in time of substituting
substitution= where_term; substitution= where_item;
have_to_be_excluded= 1; have_to_be_excluded= 1;
if (thd->lex->describe) if (thd->lex->describe)
{ {
...@@ -1866,20 +1866,37 @@ Item_in_subselect::row_value_transformer(JOIN *join) ...@@ -1866,20 +1866,37 @@ Item_in_subselect::row_value_transformer(JOIN *join)
add the equi-join and the "is null" to WHERE add the equi-join and the "is null" to WHERE
add the is_not_null_test to HAVING add the is_not_null_test to HAVING
*/ */
Item_subselect::trans_res Item_subselect::trans_res
Item_in_subselect::row_value_in_to_exists_transformer(JOIN * join) Item_in_subselect::row_value_in_to_exists_transformer(JOIN * join)
{
Item *where_item;
Item *having_item;
Item_subselect::trans_res res;
res= create_row_value_in_to_exists_cond(join, &where_item, &having_item);
if (res != RES_OK)
return res;
res= inject_row_value_in_to_exists_cond(join, where_item, having_item);
return res;
}
Item_subselect::trans_res
Item_in_subselect::create_row_value_in_to_exists_cond(JOIN * join,
Item **where_item,
Item **having_item)
{ {
SELECT_LEX *select_lex= join->select_lex; SELECT_LEX *select_lex= join->select_lex;
Item *having_item= 0;
uint cols_num= left_expr->cols(); uint cols_num= left_expr->cols();
bool is_having_used= (join->having || select_lex->with_sum_func || bool is_having_used= (join->having || select_lex->with_sum_func ||
select_lex->group_list.first || select_lex->group_list.first ||
!select_lex->table_list.elements); !select_lex->table_list.elements);
DBUG_ENTER("Item_in_subselect::row_value_in_to_exists_transformer"); DBUG_ENTER("Item_in_subselect::create_row_value_in_to_exists_cond");
*where_item= NULL;
*having_item= NULL;
select_lex->uncacheable|= UNCACHEABLE_DEPENDENT;
if (is_having_used) if (is_having_used)
{ {
/* /*
...@@ -1899,6 +1916,7 @@ Item_in_subselect::row_value_in_to_exists_transformer(JOIN * join) ...@@ -1899,6 +1916,7 @@ Item_in_subselect::row_value_in_to_exists_transformer(JOIN * join)
for (uint i= 0; i < cols_num; i++) for (uint i= 0; i < cols_num; i++)
{ {
DBUG_ASSERT((left_expr->fixed && DBUG_ASSERT((left_expr->fixed &&
select_lex->ref_pointer_array[i]->fixed) || select_lex->ref_pointer_array[i]->fixed) ||
(select_lex->ref_pointer_array[i]->type() == REF_ITEM && (select_lex->ref_pointer_array[i]->type() == REF_ITEM &&
((Item_ref*)(select_lex->ref_pointer_array[i]))->ref_type() == ((Item_ref*)(select_lex->ref_pointer_array[i]))->ref_type() ==
...@@ -1932,8 +1950,8 @@ Item_in_subselect::row_value_in_to_exists_transformer(JOIN * join) ...@@ -1932,8 +1950,8 @@ Item_in_subselect::row_value_in_to_exists_transformer(JOIN * join)
if (!(col_item= new Item_func_trig_cond(col_item, get_cond_guard(i)))) if (!(col_item= new Item_func_trig_cond(col_item, get_cond_guard(i))))
DBUG_RETURN(RES_ERROR); DBUG_RETURN(RES_ERROR);
} }
having_item= and_items(having_item, col_item); *having_item= and_items(*having_item, col_item);
Item *item_nnull_test= Item *item_nnull_test=
new Item_is_not_null_test(this, new Item_is_not_null_test(this,
new Item_ref(&select_lex->context, new Item_ref(&select_lex->context,
...@@ -1950,8 +1968,8 @@ Item_in_subselect::row_value_in_to_exists_transformer(JOIN * join) ...@@ -1950,8 +1968,8 @@ Item_in_subselect::row_value_in_to_exists_transformer(JOIN * join)
item_having_part2= and_items(item_having_part2, item_nnull_test); item_having_part2= and_items(item_having_part2, item_nnull_test);
item_having_part2->top_level_item(); item_having_part2->top_level_item();
} }
having_item= and_items(having_item, item_having_part2); *having_item= and_items(*having_item, item_having_part2);
having_item->top_level_item(); (*having_item)->top_level_item();
} }
else else
{ {
...@@ -1972,7 +1990,6 @@ Item_in_subselect::row_value_in_to_exists_transformer(JOIN * join) ...@@ -1972,7 +1990,6 @@ Item_in_subselect::row_value_in_to_exists_transformer(JOIN * join)
(l2 = v2) and (l2 = v2) and
(l3 = v3) (l3 = v3)
*/ */
Item *where_item= 0;
for (uint i= 0; i < cols_num; i++) for (uint i= 0; i < cols_num; i++)
{ {
Item *item, *item_isnull; Item *item, *item_isnull;
...@@ -2030,10 +2047,33 @@ Item_in_subselect::row_value_in_to_exists_transformer(JOIN * join) ...@@ -2030,10 +2047,33 @@ Item_in_subselect::row_value_in_to_exists_transformer(JOIN * join)
new Item_func_trig_cond(having_col_item, get_cond_guard(i)))) new Item_func_trig_cond(having_col_item, get_cond_guard(i))))
DBUG_RETURN(RES_ERROR); DBUG_RETURN(RES_ERROR);
} }
having_item= and_items(having_item, having_col_item); *having_item= and_items(*having_item, having_col_item);
} }
where_item= and_items(where_item, item); *where_item= and_items(*where_item, item);
} }
(*where_item)->fix_fields(thd, 0);
}
DBUG_RETURN(RES_OK);
}
Item_subselect::trans_res
Item_in_subselect::inject_row_value_in_to_exists_cond(JOIN * join,
Item *where_item,
Item *having_item)
{
SELECT_LEX *select_lex= join->select_lex;
bool is_having_used= (join->having || select_lex->with_sum_func ||
select_lex->group_list.first ||
!select_lex->table_list.elements);
DBUG_ENTER("Item_in_subselect::inject_row_value_in_to_exists_cond");
select_lex->uncacheable|= UNCACHEABLE_DEPENDENT;
if (!is_having_used)
{
/* /*
AND can't be changed during fix_fields() AND can't be changed during fix_fields()
we can assign select_lex->where here, and pass 0 as last we can assign select_lex->where here, and pass 0 as last
...@@ -2041,9 +2081,10 @@ Item_in_subselect::row_value_in_to_exists_transformer(JOIN * join) ...@@ -2041,9 +2081,10 @@ Item_in_subselect::row_value_in_to_exists_transformer(JOIN * join)
*/ */
select_lex->where= join->conds= and_items(join->conds, where_item); select_lex->where= join->conds= and_items(join->conds, where_item);
select_lex->where->top_level_item(); select_lex->where->top_level_item();
if (join->conds->fix_fields(thd, 0)) if (!join->conds->fixed && join->conds->fix_fields(thd, 0))
DBUG_RETURN(RES_ERROR); DBUG_RETURN(RES_ERROR);
} }
if (having_item) if (having_item)
{ {
bool res; bool res;
...@@ -2057,12 +2098,11 @@ Item_in_subselect::row_value_in_to_exists_transformer(JOIN * join) ...@@ -2057,12 +2098,11 @@ Item_in_subselect::row_value_in_to_exists_transformer(JOIN * join)
argument (reference) to fix_fields() argument (reference) to fix_fields()
*/ */
select_lex->having_fix_field= 1; select_lex->having_fix_field= 1;
res= join->having->fix_fields(thd, 0); if (!join->having->fixed)
res= join->having->fix_fields(thd, 0);
select_lex->having_fix_field= 0; select_lex->having_fix_field= 0;
if (res) if (res)
{
DBUG_RETURN(RES_ERROR); DBUG_RETURN(RES_ERROR);
}
} }
DBUG_RETURN(RES_OK); DBUG_RETURN(RES_OK);
......
...@@ -438,6 +438,13 @@ public: ...@@ -438,6 +438,13 @@ public:
Item *having_term); Item *having_term);
trans_res row_value_in_to_exists_transformer(JOIN * join); trans_res row_value_in_to_exists_transformer(JOIN * join);
trans_res create_row_value_in_to_exists_cond(JOIN * join,
Item **where_term,
Item **having_term);
trans_res inject_row_value_in_to_exists_cond(JOIN * join,
Item *where_term,
Item *having_term);
virtual bool exec(); virtual bool exec();
longlong val_int(); longlong val_int();
double val_real(); double val_real();
......
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