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.cc355
1 files changed, 215 insertions, 140 deletions
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index f82d55f8309..852f91efc00 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2010, 2012, Monty Program Ab
+ Copyright (c) 2010, 2015, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -12,7 +12,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
/**
@file
@@ -26,6 +26,7 @@
#pragma implementation // gcc: Class implementation
#endif
+#include <my_global.h>
#include "sql_base.h"
#include "sql_select.h"
#include "filesort.h"
@@ -461,7 +462,7 @@ void best_access_path(JOIN *join, JOIN_TAB *s,
static Item *create_subq_in_equalities(THD *thd, SJ_MATERIALIZATION_INFO *sjm,
Item_in_subselect *subq_pred);
-static void remove_sj_conds(Item **tree);
+static void remove_sj_conds(THD *thd, Item **tree);
static bool is_cond_sj_in_equality(Item *item);
static bool sj_table_is_included(JOIN *join, JOIN_TAB *join_tab);
static Item *remove_additional_cond(Item* conds);
@@ -513,8 +514,6 @@ bool is_materialization_applicable(THD *thd, Item_in_subselect *in_subs,
Subquery !contains {GROUP BY, ORDER BY [LIMIT],
aggregate functions}) && subquery predicate is not under "NOT IN"))
- (*) The subquery must be part of a SELECT or CREATE TABLE ... SELECT statement.
- The current 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
select_lex->sj_subselects list to be populated for every EXECUTE.
@@ -523,9 +522,7 @@ bool is_materialization_applicable(THD *thd, Item_in_subselect *in_subs,
if (optimizer_flag(thd, OPTIMIZER_SWITCH_MATERIALIZATION) && // 0
!child_select->is_part_of_union() && // 1
parent_unit->first_select()->leaf_tables.elements && // 2
- (thd->lex->sql_command == SQLCOM_SELECT || // *
- thd->lex->sql_command == SQLCOM_CREATE_TABLE) && // *
- child_select->outer_select()->leaf_tables.elements && // 2A
+ child_select->outer_select()->leaf_tables.elements && // 2A
subquery_types_allow_materialization(in_subs) &&
(in_subs->is_top_level_item() || //3
optimizer_flag(thd,
@@ -665,6 +662,9 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
8. No execution method was already chosen (by a prepared statement)
9. Parent select is not a table-less select
10. Neither parent nor child select have STRAIGHT_JOIN option.
+ 11. It is first optimisation (the subquery could be moved from ON
+ clause during first optimisation and then be considered for SJ
+ on the second when it is too late)
*/
if (optimizer_flag(thd, OPTIMIZER_SWITCH_SEMIJOIN) &&
in_subs && // 1
@@ -678,8 +678,8 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
select_lex->outer_select()->table_list.first && // 9
!((join->select_options | // 10
select_lex->outer_select()->join->select_options) // 10
- & SELECT_STRAIGHT_JOIN)) // 10
-
+ & SELECT_STRAIGHT_JOIN) && // 10
+ select_lex->first_cond_optimization) // 11
{
DBUG_PRINT("info", ("Subquery is semi-join conversion candidate"));
@@ -692,7 +692,8 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
{
Query_arena *arena, backup;
arena= thd->activate_stmt_arena_if_needed(&backup);
- select_lex->outer_select()->sj_subselects.push_back(in_subs);
+ select_lex->outer_select()->sj_subselects.push_back(in_subs,
+ thd->mem_root);
if (arena)
thd->restore_active_arena(arena, &backup);
in_subs->is_registered_semijoin= TRUE;
@@ -735,7 +736,8 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
{
Query_arena *arena, backup;
arena= thd->activate_stmt_arena_if_needed(&backup);
- select_lex->outer_select()->sj_subselects.push_back(in_subs);
+ select_lex->outer_select()->sj_subselects.push_back(in_subs,
+ thd->mem_root);
if (arena)
thd->restore_active_arena(arena, &backup);
in_subs->is_registered_semijoin= TRUE;
@@ -1203,7 +1205,7 @@ bool convert_join_subqueries_to_semijoins(JOIN *join)
in_subq->sj_convert_priority=
- test(in_subq->do_not_convert_to_sj) * MAX_TABLES * 2 +
+ MY_TEST(in_subq->do_not_convert_to_sj) * MAX_TABLES * 2 +
in_subq->is_correlated * MAX_TABLES + child_join->outer_tables;
}
@@ -1259,7 +1261,8 @@ bool convert_join_subqueries_to_semijoins(JOIN *join)
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),
+ if (replace_where_subcondition(join, tree, replace_me,
+ new (thd->mem_root) Item_int(thd, 1),
FALSE))
goto restore_arena_and_fail;
}
@@ -1609,7 +1612,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
A3: changes in the TABLE_LIST::outer_join will make everything work
automatically.
*/
- if (!(wrap_nest= alloc_join_nest(parent_join->thd)))
+ if (!(wrap_nest= alloc_join_nest(thd)))
{
DBUG_RETURN(TRUE);
}
@@ -1618,7 +1621,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
wrap_nest->alias= (char*) "(sj-wrap)";
wrap_nest->nested_join->join_list.empty();
- wrap_nest->nested_join->join_list.push_back(outer_tbl);
+ wrap_nest->nested_join->join_list.push_back(outer_tbl, thd->mem_root);
outer_tbl->embedding= wrap_nest;
outer_tbl->join_list= &wrap_nest->nested_join->join_list;
@@ -1654,7 +1657,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
TABLE_LIST *sj_nest;
NESTED_JOIN *nested_join;
- if (!(sj_nest= alloc_join_nest(parent_join->thd)))
+ if (!(sj_nest= alloc_join_nest(thd)))
{
DBUG_RETURN(TRUE);
}
@@ -1668,7 +1671,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
subq_pred->left_expr->used_tables();
/* Nests do not participate in those 'chains', so: */
/* sj_nest->next_leaf= sj_nest->next_local= sj_nest->next_global == NULL*/
- emb_join_list->push_back(sj_nest);
+ emb_join_list->push_back(sj_nest, thd->mem_root);
/*
nested_join->used_tables and nested_join->not_null_tables are
@@ -1688,7 +1691,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
{
tl->embedding= sj_nest;
tl->join_list= &nested_join->join_list;
- nested_join->join_list.push_back(tl);
+ nested_join->join_list.push_back(tl, thd->mem_root);
}
/*
@@ -1698,7 +1701,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
NOTE: We actually insert them at the front! That's because the order is
reversed in this list.
*/
- parent_lex->leaf_tables.concat(&subq_lex->leaf_tables);
+ parent_lex->leaf_tables.append(&subq_lex->leaf_tables);
if (subq_lex->options & OPTION_SCHEMA_TABLE)
parent_lex->options |= OPTION_SCHEMA_TABLE;
@@ -1730,7 +1733,12 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
{
tl->set_tablenr(table_no);
if (tl->is_jtbm())
+ {
tl->jtbm_table_no= table_no;
+ Item *dummy= tl->jtbm_subselect;
+ tl->jtbm_subselect->fix_after_pullout(parent_lex, &dummy, true);
+ DBUG_ASSERT(dummy == tl->jtbm_subselect);
+ }
SELECT_LEX *old_sl= tl->select_lex;
tl->select_lex= parent_join->select_lex;
for (TABLE_LIST *emb= tl->embedding;
@@ -1753,8 +1761,9 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
DBUG_RETURN(TRUE);
thd->lex->current_select=save_lex;
- sj_nest->nested_join->sj_corr_tables= subq_pred->used_tables();
- sj_nest->nested_join->sj_depends_on= subq_pred->used_tables() |
+ table_map subq_pred_used_tables= subq_pred->used_tables();
+ sj_nest->nested_join->sj_corr_tables= subq_pred_used_tables;
+ sj_nest->nested_join->sj_depends_on= subq_pred_used_tables |
subq_pred->left_expr->used_tables();
sj_nest->sj_on_expr= subq_lex->join->conds;
@@ -1780,7 +1789,8 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
if (subq_pred->left_expr->cols() == 1)
{
/* add left = select_list_element */
- nested_join->sj_outer_expr_list.push_back(&subq_pred->left_expr);
+ nested_join->sj_outer_expr_list.push_back(&subq_pred->left_expr,
+ thd->mem_root);
/*
Create Item_func_eq. Note that
1. this is done on the statement, not execution, arena
@@ -1791,13 +1801,14 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
with thd->change_item_tree
*/
Item_func_eq *item_eq=
- new Item_func_eq(subq_pred->left_expr_orig, subq_lex->ref_pointer_array[0]);
+ new (thd->mem_root) Item_func_eq(thd, subq_pred->left_expr_orig,
+ subq_lex->ref_pointer_array[0]);
if (!item_eq)
DBUG_RETURN(TRUE);
if (subq_pred->left_expr_orig != subq_pred->left_expr)
thd->change_item_tree(item_eq->arguments(), subq_pred->left_expr);
item_eq->in_equality_no= 0;
- sj_nest->sj_on_expr= and_items(sj_nest->sj_on_expr, item_eq);
+ sj_nest->sj_on_expr= and_items(thd, sj_nest->sj_on_expr, item_eq);
}
else if (subq_pred->left_expr->type() == Item::ROW_ITEM)
{
@@ -1807,11 +1818,12 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
*/
for (uint i= 0; i < subq_pred->left_expr->cols(); i++)
{
- nested_join->sj_outer_expr_list.push_back(subq_pred->left_expr->
- addr(i));
+ nested_join->sj_outer_expr_list.push_back(subq_pred->left_expr->addr(i),
+ thd->mem_root);
Item_func_eq *item_eq=
- new Item_func_eq(subq_pred->left_expr_orig->element_index(i),
- subq_lex->ref_pointer_array[i]);
+ new (thd->mem_root)
+ Item_func_eq(thd, subq_pred->left_expr_orig->element_index(i),
+ subq_lex->ref_pointer_array[i]);
if (!item_eq)
DBUG_RETURN(TRUE);
DBUG_ASSERT(subq_pred->left_expr->element_index(i)->fixed);
@@ -1820,7 +1832,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
thd->change_item_tree(item_eq->arguments(),
subq_pred->left_expr->element_index(i));
item_eq->in_equality_no= i;
- sj_nest->sj_on_expr= and_items(sj_nest->sj_on_expr, item_eq);
+ sj_nest->sj_on_expr= and_items(thd, sj_nest->sj_on_expr, item_eq);
}
}
else
@@ -1829,14 +1841,14 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
add row operation
left = (select_list_element1, select_list_element2, ...)
*/
- Item_row *row= new Item_row(subq_lex->pre_fix);
+ Item_row *row= new (thd->mem_root) Item_row(thd, subq_lex->pre_fix);
/* fix fields on subquery was call so they should be the same */
DBUG_ASSERT(subq_pred->left_expr->cols() == row->cols());
if (!row)
DBUG_RETURN(TRUE);
nested_join->sj_outer_expr_list.push_back(&subq_pred->left_expr);
Item_func_eq *item_eq=
- new Item_func_eq(subq_pred->left_expr_orig, row);
+ new (thd->mem_root) Item_func_eq(thd, subq_pred->left_expr_orig, row);
if (!item_eq)
DBUG_RETURN(TRUE);
for (uint i= 0; i < row->cols(); i++)
@@ -1845,7 +1857,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
thd->change_item_tree(row->addr(i), subq_lex->ref_pointer_array[i]);
}
item_eq->in_equality_no= 0;
- sj_nest->sj_on_expr= and_items(sj_nest->sj_on_expr, item_eq);
+ sj_nest->sj_on_expr= and_items(thd, sj_nest->sj_on_expr, item_eq);
}
/*
Fix the created equality and AND
@@ -1857,7 +1869,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
we have in here).
*/
if (!sj_nest->sj_on_expr->fixed &&
- sj_nest->sj_on_expr->fix_fields(parent_join->thd, &sj_nest->sj_on_expr))
+ sj_nest->sj_on_expr->fix_fields(thd, &sj_nest->sj_on_expr))
{
DBUG_RETURN(TRUE);
}
@@ -1866,7 +1878,8 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
Walk through sj nest's WHERE and ON expressions and call
item->fix_table_changes() for all items.
*/
- sj_nest->sj_on_expr->fix_after_pullout(parent_lex, &sj_nest->sj_on_expr);
+ sj_nest->sj_on_expr->fix_after_pullout(parent_lex, &sj_nest->sj_on_expr,
+ TRUE);
fix_list_after_tbl_changes(parent_lex, &sj_nest->nested_join->join_list);
@@ -1879,11 +1892,11 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
/* Inject sj_on_expr into the parent's WHERE or ON */
if (emb_tbl_nest)
{
- emb_tbl_nest->on_expr= and_items(emb_tbl_nest->on_expr,
+ emb_tbl_nest->on_expr= and_items(thd, emb_tbl_nest->on_expr,
sj_nest->sj_on_expr);
emb_tbl_nest->on_expr->top_level_item();
if (!emb_tbl_nest->on_expr->fixed &&
- emb_tbl_nest->on_expr->fix_fields(parent_join->thd,
+ emb_tbl_nest->on_expr->fix_fields(thd,
&emb_tbl_nest->on_expr))
{
DBUG_RETURN(TRUE);
@@ -1892,7 +1905,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
else
{
/* Inject into the WHERE */
- parent_join->conds= and_items(parent_join->conds, sj_nest->sj_on_expr);
+ parent_join->conds= and_items(thd, parent_join->conds, sj_nest->sj_on_expr);
parent_join->conds->top_level_item();
/*
fix_fields must update the properties (e.g. st_select_lex::cond_count of
@@ -1901,7 +1914,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
save_lex= thd->lex->current_select;
thd->lex->current_select=parent_join->select_lex;
if (!parent_join->conds->fixed &&
- parent_join->conds->fix_fields(parent_join->thd,
+ parent_join->conds->fix_fields(thd,
&parent_join->conds))
{
DBUG_RETURN(1);
@@ -1915,9 +1928,10 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred)
Item_func_match *ifm;
List_iterator_fast<Item_func_match> li(*(subq_lex->ftfunc_list));
while ((ifm= li++))
- parent_lex->ftfunc_list->push_front(ifm);
+ parent_lex->ftfunc_list->push_front(ifm, thd->mem_root);
}
+ parent_lex->have_merged_subqueries= TRUE;
DBUG_RETURN(FALSE);
}
@@ -1956,16 +1970,16 @@ static bool convert_subq_to_jtbm(JOIN *parent_join,
List<TABLE_LIST> *emb_join_list= &parent_lex->top_join_list;
TABLE_LIST *emb_tbl_nest= NULL; // will change when we learn to handle outer joins
TABLE_LIST *tl;
- DBUG_ENTER("convert_subq_to_jtbm");
bool optimization_delayed= TRUE;
- subq_pred->set_strategy(SUBS_MATERIALIZATION);
+ TABLE_LIST *jtbm;
+ char *tbl_alias;
+ DBUG_ENTER("convert_subq_to_jtbm");
+ subq_pred->set_strategy(SUBS_MATERIALIZATION);
subq_pred->is_jtbm_merged= TRUE;
*remove_item= TRUE;
- TABLE_LIST *jtbm;
- char *tbl_alias;
if (!(tbl_alias= (char*)parent_join->thd->calloc(SUBQERY_TEMPTABLE_NAME_MAX_LEN)) ||
!(jtbm= alloc_join_nest(parent_join->thd))) //todo: this is not a join nest!
{
@@ -1979,13 +1993,13 @@ static bool convert_subq_to_jtbm(JOIN *parent_join,
/* Nests do not participate in those 'chains', so: */
/* jtbm->next_leaf= jtbm->next_local= jtbm->next_global == NULL*/
- emb_join_list->push_back(jtbm);
+ emb_join_list->push_back(jtbm, parent_join->thd->mem_root);
/*
Inject the jtbm table into TABLE_LIST::next_leaf list, so that
make_join_statistics() and co. can find it.
*/
- parent_lex->leaf_tables.push_back(jtbm);
+ parent_lex->leaf_tables.push_back(jtbm, parent_join->thd->mem_root);
if (subq_pred->unit->first_select()->options & OPTION_SCHEMA_TABLE)
parent_lex->options |= OPTION_SCHEMA_TABLE;
@@ -2024,13 +2038,15 @@ static bool convert_subq_to_jtbm(JOIN *parent_join,
DBUG_ASSERT(parent_join->table_count < MAX_TABLES);
Item *conds= hash_sj_engine->semi_join_conds;
- conds->fix_after_pullout(parent_lex, &conds);
+ conds->fix_after_pullout(parent_lex, &conds, TRUE);
DBUG_EXECUTE("where", print_where(conds,"SJ-EXPR", QT_ORDINARY););
create_subquery_temptable_name(tbl_alias, hash_sj_engine->materialize_join->
select_lex->select_number);
jtbm->alias= tbl_alias;
+
+ parent_lex->have_merged_subqueries= TRUE;
#if 0
/* Inject sj_on_expr into the parent's WHERE or ON */
if (emb_tbl_nest)
@@ -2074,7 +2090,7 @@ void fix_list_after_tbl_changes(SELECT_LEX *new_parent, List<TABLE_LIST> *tlist)
while ((table= it++))
{
if (table->on_expr)
- table->on_expr->fix_after_pullout(new_parent, &table->on_expr);
+ table->on_expr->fix_after_pullout(new_parent, &table->on_expr, TRUE);
if (table->nested_join)
fix_list_after_tbl_changes(new_parent, &table->nested_join->join_list);
}
@@ -2304,7 +2320,7 @@ int pull_out_semijoin_tables(JOIN *join)
*/
child_li.remove();
sj_nest->nested_join->used_tables &= ~tbl->table->map;
- upper_join_list->push_back(tbl);
+ upper_join_list->push_back(tbl, join->thd->mem_root);
tbl->join_list= upper_join_list;
tbl->embedding= sj_nest->embedding;
}
@@ -2452,9 +2468,10 @@ bool optimize_semijoin_nests(JOIN *join, table_map all_table_map)
double rows= 1.0;
while ((tableno = tm_it.next_bit()) != Table_map_iterator::BITMAP_END)
rows *= join->map2table[tableno]->table->quick_condition_rows;
- sjm->rows= min(sjm->rows, rows);
+ sjm->rows= MY_MIN(sjm->rows, rows);
}
- memcpy(sjm->positions, join->best_positions + join->const_tables,
+ memcpy((uchar*) sjm->positions,
+ (uchar*) (join->best_positions + join->const_tables),
sizeof(POSITION) * n_tables);
/*
@@ -2477,7 +2494,7 @@ bool optimize_semijoin_nests(JOIN *join, table_map all_table_map)
Set the cost to do a full scan of the temptable (will need this to
consider doing sjm-scan):
*/
- sjm->scan_cost.zero();
+ sjm->scan_cost.reset();
sjm->scan_cost.add_io(sjm->rows, lookup_cost);
sjm->lookup_cost.convert_from_cost(lookup_cost);
@@ -2632,7 +2649,7 @@ bool find_eq_ref_candidate(TABLE *table, table_map sj_inner_tables)
if (!is_excluded_key)
{
keyinfo= table->key_info + key;
- is_excluded_key= !test(keyinfo->flags & HA_NOSAME);
+ is_excluded_key= !MY_TEST(keyinfo->flags & HA_NOSAME);
}
if (!is_excluded_key)
{
@@ -2647,7 +2664,7 @@ bool find_eq_ref_candidate(TABLE *table, table_map sj_inner_tables)
keyuse++;
} while (keyuse->key == key && keyuse->table == table);
- if (bound_parts == PREV_BITS(uint, keyinfo->key_parts))
+ if (bound_parts == PREV_BITS(uint, keyinfo->user_defined_key_parts))
return TRUE;
}
else
@@ -2719,8 +2736,8 @@ bool is_multiple_semi_joins(JOIN *join, POSITION *prefix, uint idx, table_map in
if ((emb_sj_nest= prefix[i].table->emb_sj_nest))
{
if (inner_tables & emb_sj_nest->sj_inner_tables)
- return !test(inner_tables == (emb_sj_nest->sj_inner_tables &
- ~join->const_table_map));
+ return !MY_TEST(inner_tables == (emb_sj_nest->sj_inner_tables &
+ ~join->const_table_map));
}
}
return FALSE;
@@ -2759,8 +2776,8 @@ void advance_sj_state(JOIN *join, table_map remaining_tables, uint idx,
LooseScan detector in best_access_path)
*/
remaining_tables &= ~new_join_tab->table->map;
- table_map dups_producing_tables, prev_dups_producing_tables,
- prev_sjm_lookup_tables;
+ table_map dups_producing_tables, prev_dups_producing_tables= 0,
+ prev_sjm_lookup_tables= 0;
if (idx == join->const_tables)
dups_producing_tables= 0;
@@ -2771,7 +2788,7 @@ void advance_sj_state(JOIN *join, table_map remaining_tables, uint idx,
if ((emb_sj_nest= new_join_tab->emb_sj_nest))
dups_producing_tables |= emb_sj_nest->sj_inner_tables;
- Semi_join_strategy_picker **strategy, **prev_strategy;
+ Semi_join_strategy_picker **strategy, **prev_strategy= NULL;
if (idx == join->const_tables)
{
/* First table, initialize pickers */
@@ -2955,12 +2972,12 @@ bool Sj_materialization_picker::check_qep(JOIN *join,
else
{
/* This is SJ-Materialization with lookups */
- COST_VECT prefix_cost;
+ Cost_estimate prefix_cost;
signed int first_tab= (int)idx - mat_info->tables;
double prefix_rec_count;
if (first_tab < (int)join->const_tables)
{
- prefix_cost.zero();
+ prefix_cost.reset();
prefix_rec_count= 1.0;
}
else
@@ -3491,9 +3508,9 @@ at_sjmat_pos(const JOIN *join, table_map remaining_tables, const JOIN_TAB *tab,
if (join->positions[idx - i].table->emb_sj_nest != tab->emb_sj_nest)
return NULL;
}
- *loose_scan= test(remaining_tables & ~tab->table->map &
- (emb_sj_nest->sj_inner_tables |
- emb_sj_nest->nested_join->sj_depends_on));
+ *loose_scan= MY_TEST(remaining_tables & ~tab->table->map &
+ (emb_sj_nest->sj_inner_tables |
+ emb_sj_nest->nested_join->sj_depends_on));
if (*loose_scan && !emb_sj_nest->sj_subq_pred->sjm_scan_allowed)
return NULL;
else
@@ -3577,8 +3594,7 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
{
POSITION *pos= join->best_positions + tablenr;
JOIN_TAB *s= pos->table;
- uint first;
- LINT_INIT(first); // Set by every branch except SJ_OPT_NONE which doesn't use it
+ uint UNINIT_VAR(first); // Set by every branch except SJ_OPT_NONE which doesn't use it
if ((handled_tabs & s->table->map) || pos->sj_strategy == SJ_OPT_NONE)
{
@@ -3591,7 +3607,7 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
SJ_MATERIALIZATION_INFO *sjm= s->emb_sj_nest->sj_mat_info;
sjm->is_used= TRUE;
sjm->is_sj_scan= FALSE;
- memcpy(pos - sjm->tables + 1, sjm->positions,
+ memcpy((uchar*) (pos - sjm->tables + 1), (uchar*) sjm->positions,
sizeof(POSITION) * sjm->tables);
recalculate_prefix_record_count(join, tablenr - sjm->tables + 1,
tablenr);
@@ -3608,8 +3624,8 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
sjm->is_used= TRUE;
sjm->is_sj_scan= TRUE;
first= pos->sjmat_picker.sjm_scan_last_inner - sjm->tables + 1;
- memcpy(join->best_positions + first,
- sjm->positions, sizeof(POSITION) * sjm->tables);
+ memcpy((uchar*) (join->best_positions + first),
+ (uchar*) sjm->positions, sizeof(POSITION) * sjm->tables);
recalculate_prefix_record_count(join, first, first + sjm->tables);
join->best_positions[first].sj_strategy= SJ_OPT_MATERIALIZE_SCAN;
join->best_positions[first].n_sj_tables= sjm->tables;
@@ -3781,16 +3797,19 @@ void fix_semijoin_strategies_for_picked_join_order(JOIN *join)
bool setup_sj_materialization_part1(JOIN_TAB *sjm_tab)
{
- DBUG_ENTER("setup_sj_materialization");
JOIN_TAB *tab= sjm_tab->bush_children->start;
TABLE_LIST *emb_sj_nest= tab->table->pos_in_table_list->embedding;
+ SJ_MATERIALIZATION_INFO *sjm;
+ THD *thd;
+
+ DBUG_ENTER("setup_sj_materialization");
/* Walk out of outer join nests until we reach the semi-join nest we're in */
while (!emb_sj_nest->sj_mat_info)
emb_sj_nest= emb_sj_nest->embedding;
- SJ_MATERIALIZATION_INFO *sjm= emb_sj_nest->sj_mat_info;
- THD *thd= tab->join->thd;
+ sjm= emb_sj_nest->sj_mat_info;
+ thd= tab->join->thd;
/* First the calls come to the materialization function */
DBUG_ASSERT(sjm->is_used);
@@ -3831,8 +3850,8 @@ bool setup_sj_materialization_part1(JOIN_TAB *sjm_tab)
sjm->table->file->extra(HA_EXTRA_WRITE_CACHE);
sjm->table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
- tab->join->sj_tmp_tables.push_back(sjm->table);
- tab->join->sjm_info_list.push_back(sjm);
+ tab->join->sj_tmp_tables.push_back(sjm->table, thd->mem_root);
+ tab->join->sjm_info_list.push_back(sjm, thd->mem_root);
sjm->materialized= FALSE;
sjm_tab->table= sjm->table;
@@ -3861,7 +3880,7 @@ bool setup_sj_materialization_part2(JOIN_TAB *sjm_tab)
KEY *tmp_key; /* The only index on the temporary table. */
uint tmp_key_parts; /* Number of keyparts in tmp_key. */
tmp_key= sjm->table->key_info;
- tmp_key_parts= tmp_key->key_parts;
+ tmp_key_parts= tmp_key->user_defined_key_parts;
/*
Create/initialize everything we will need to index lookups into the
@@ -3892,12 +3911,12 @@ bool setup_sj_materialization_part2(JOIN_TAB *sjm_tab)
for (i= 0; i < tmp_key_parts; i++, cur_key_part++, ref_key++)
{
tab_ref->items[i]= emb_sj_nest->sj_subq_pred->left_expr->element_index(i);
- int null_count= test(cur_key_part->field->real_maybe_null());
+ int null_count= MY_TEST(cur_key_part->field->real_maybe_null());
*ref_key= new store_key_item(thd, cur_key_part->field,
/* TODO:
the NULL byte is taken into account in
cur_key_part->store_length, so instead of
- cur_ref_buff + test(maybe_null), we could
+ cur_ref_buff + MY_TEST(maybe_null), we could
use that information instead.
*/
cur_ref_buff + null_count,
@@ -3929,9 +3948,9 @@ bool setup_sj_materialization_part2(JOIN_TAB *sjm_tab)
*/
for (i= 0; i < sjm->tables; i++)
{
- remove_sj_conds(&tab[i].select_cond);
+ remove_sj_conds(thd, &tab[i].select_cond);
if (tab[i].select)
- remove_sj_conds(&tab[i].select->cond);
+ remove_sj_conds(thd, &tab[i].select->cond);
}
if (!(sjm->in_equality= create_subq_in_equalities(thd, sjm,
emb_sj_nest->sj_subq_pred)))
@@ -4074,8 +4093,8 @@ static Item *create_subq_in_equalities(THD *thd, SJ_MATERIALIZATION_INFO *sjm,
Item *res= NULL;
if (subq_pred->left_expr->cols() == 1)
{
- if (!(res= new Item_func_eq(subq_pred->left_expr,
- new Item_field(sjm->table->field[0]))))
+ if (!(res= new (thd->mem_root) Item_func_eq(thd, subq_pred->left_expr,
+ new (thd->mem_root) Item_field(thd, sjm->table->field[0]))))
return NULL; /* purecov: inspected */
}
else
@@ -4083,9 +4102,9 @@ static Item *create_subq_in_equalities(THD *thd, SJ_MATERIALIZATION_INFO *sjm,
Item *conj;
for (uint i= 0; i < subq_pred->left_expr->cols(); i++)
{
- if (!(conj= new Item_func_eq(subq_pred->left_expr->element_index(i),
- new Item_field(sjm->table->field[i]))) ||
- !(res= and_items(res, conj)))
+ if (!(conj= new (thd->mem_root) Item_func_eq(thd, subq_pred->left_expr->element_index(i),
+ new (thd->mem_root) Item_field(thd, sjm->table->field[i]))) ||
+ !(res= and_items(thd, res, conj)))
return NULL; /* purecov: inspected */
}
}
@@ -4097,7 +4116,7 @@ static Item *create_subq_in_equalities(THD *thd, SJ_MATERIALIZATION_INFO *sjm,
-static void remove_sj_conds(Item **tree)
+static void remove_sj_conds(THD *thd, Item **tree)
{
if (*tree)
{
@@ -4113,7 +4132,7 @@ static void remove_sj_conds(Item **tree)
while ((item= li++))
{
if (is_cond_sj_in_equality(item))
- li.replace(new Item_int(1));
+ li.replace(new (thd->mem_root) Item_int(thd, 1));
}
}
}
@@ -4126,7 +4145,7 @@ static bool is_cond_sj_in_equality(Item *item)
((Item_func*)item)->functype()== Item_func::EQ_FUNC)
{
Item_func_eq *item_eq= (Item_func_eq*)item;
- return test(item_eq->in_equality_no != UINT_MAX);
+ return MY_TEST(item_eq->in_equality_no != UINT_MAX);
}
return FALSE;
}
@@ -4191,7 +4210,6 @@ SJ_TMP_TABLE::create_sj_weedout_tmp_table(THD *thd)
/*
STEP 1: Get temporary table name
*/
- statistic_increment(thd->status_var.created_tmp_tables, &LOCK_status);
if (use_temp_pool && !(test_flags & TEST_KEEP_TMP_TABLES))
temp_pool_slot = bitmap_lock_set_next(&temp_pool);
@@ -4212,7 +4230,7 @@ SJ_TMP_TABLE::create_sj_weedout_tmp_table(THD *thd)
using_unique_constraint= TRUE;
/* STEP 3: Allocate memory for temptable description */
- init_sql_alloc(&own_root, TABLE_ALLOC_BLOCK_SIZE, 0);
+ init_sql_alloc(&own_root, TABLE_ALLOC_BLOCK_SIZE, 0, MYF(MY_THREAD_SPECIFIC));
if (!multi_alloc_root(&own_root,
&table, sizeof(*table),
&share, sizeof(*share),
@@ -4225,7 +4243,7 @@ SJ_TMP_TABLE::create_sj_weedout_tmp_table(THD *thd)
&tmpname, (uint) strlen(path)+1,
&group_buff, (!using_unique_constraint ?
uniq_tuple_length_arg : 0),
- &bitmaps, bitmap_buffer_size(1)*3,
+ &bitmaps, bitmap_buffer_size(1)*5,
NullS))
{
if (temp_pool_slot != MY_BIT_NONE)
@@ -4259,7 +4277,6 @@ SJ_TMP_TABLE::create_sj_weedout_tmp_table(THD *thd)
table->s= share;
init_tmp_table_share(thd, share, "", 0, tmpname, tmpname);
share->blob_field= blob_field;
- share->blob_ptr_size= portable_sizeof_char_ptr;
share->table_charset= NULL;
share->primary_key= MAX_KEY; // Indicate no primary key
share->keys_for_keyread.init();
@@ -4301,17 +4318,23 @@ SJ_TMP_TABLE::create_sj_weedout_tmp_table(THD *thd)
share->db_plugin= ha_lock_engine(0, TMP_ENGINE_HTON);
table->file= get_new_handler(share, &table->mem_root,
share->db_type());
- DBUG_ASSERT(uniq_tuple_length_arg <= table->file->max_key_length());
}
else
{
share->db_plugin= ha_lock_engine(0, heap_hton);
table->file= get_new_handler(share, &table->mem_root,
share->db_type());
+ DBUG_ASSERT(uniq_tuple_length_arg <= table->file->max_key_length());
}
if (!table->file)
goto err;
+ if (table->file->set_ha_share_ref(&share->ha_share))
+ {
+ delete table->file;
+ goto err;
+ }
+
null_count=1;
null_pack_length= 1;
@@ -4381,7 +4404,7 @@ SJ_TMP_TABLE::create_sj_weedout_tmp_table(THD *thd)
share->max_rows= ~(ha_rows) 0;
else
share->max_rows= (ha_rows) (((share->db_type() == heap_hton) ?
- min(thd->variables.tmp_table_size,
+ MY_MIN(thd->variables.tmp_table_size,
thd->variables.max_heap_table_size) :
thd->variables.tmp_table_size) /
share->reclength);
@@ -4393,11 +4416,11 @@ SJ_TMP_TABLE::create_sj_weedout_tmp_table(THD *thd)
{
DBUG_PRINT("info",("Creating group key in temporary table"));
share->keys=1;
- share->uniques= test(using_unique_constraint);
+ share->uniques= MY_TEST(using_unique_constraint);
table->key_info=keyinfo;
keyinfo->key_part=key_part_info;
keyinfo->flags=HA_NOSAME;
- keyinfo->usable_key_parts= keyinfo->key_parts= 1;
+ keyinfo->usable_key_parts= keyinfo->user_defined_key_parts= 1;
keyinfo->key_length=0;
keyinfo->rec_per_key=0;
keyinfo->algorithm= HA_KEY_ALG_UNDEF;
@@ -4413,6 +4436,7 @@ SJ_TMP_TABLE::create_sj_weedout_tmp_table(THD *thd)
{
if (!(key_field= field->new_key_field(thd->mem_root, table,
group_buff,
+ key_part_info->length,
field->null_ptr,
field->null_bit)))
goto err;
@@ -4610,7 +4634,7 @@ int init_dups_weedout(JOIN *join, uint first_table, int first_fanout_table, uint
sjtbl->null_bytes= (jt_null_bits + 7)/8;
if (sjtbl->create_sj_weedout_tmp_table(thd))
DBUG_RETURN(TRUE);
- join->sj_tmp_tables.push_back(sjtbl->tmp_table);
+ join->sj_tmp_tables.push_back(sjtbl->tmp_table, thd->mem_root);
}
else
{
@@ -4635,6 +4659,74 @@ int init_dups_weedout(JOIN *join, uint first_table, int first_fanout_table, uint
/*
+ @brief
+ Set up semi-join Loose Scan strategy for execution
+
+ @detail
+ Other strategies are done in setup_semijoin_dups_elimination(),
+ however, we need to set up Loose Scan earlier, before make_join_select is
+ called. This is to prevent make_join_select() from switching full index
+ scans into quick selects (which will break Loose Scan access).
+
+ @return
+ 0 OK
+ 1 Error
+*/
+
+int setup_semijoin_loosescan(JOIN *join)
+{
+ uint i;
+ DBUG_ENTER("setup_semijoin_loosescan");
+
+ POSITION *pos= join->best_positions + join->const_tables;
+ for (i= join->const_tables ; i < join->top_join_tab_count; )
+ {
+ JOIN_TAB *tab=join->join_tab + i;
+ switch (pos->sj_strategy) {
+ case SJ_OPT_MATERIALIZE:
+ case SJ_OPT_MATERIALIZE_SCAN:
+ i+= 1; /* join tabs are embedded in the nest */
+ pos += pos->n_sj_tables;
+ break;
+ case SJ_OPT_LOOSE_SCAN:
+ {
+ /* We jump from the last table to the first one */
+ tab->loosescan_match_tab= tab + pos->n_sj_tables - 1;
+
+ /* LooseScan requires records to be produced in order */
+ if (tab->select && tab->select->quick)
+ tab->select->quick->need_sorted_output();
+
+ for (uint j= i; j < i + pos->n_sj_tables; j++)
+ join->join_tab[j].inside_loosescan_range= TRUE;
+
+ /* Calculate key length */
+ uint keylen= 0;
+ uint keyno= pos->loosescan_picker.loosescan_key;
+ for (uint kp=0; kp < pos->loosescan_picker.loosescan_parts; kp++)
+ keylen += tab->table->key_info[keyno].key_part[kp].store_length;
+
+ tab->loosescan_key= keyno;
+ tab->loosescan_key_len= keylen;
+ if (pos->n_sj_tables > 1)
+ tab[pos->n_sj_tables - 1].do_firstmatch= tab;
+ i+= pos->n_sj_tables;
+ pos+= pos->n_sj_tables;
+ break;
+ }
+ default:
+ {
+ i++;
+ pos++;
+ break;
+ }
+ }
+ }
+ DBUG_RETURN(FALSE);
+}
+
+
+/*
Setup the strategies to eliminate semi-join duplicates.
SYNOPSIS
@@ -4742,8 +4834,6 @@ int setup_semijoin_dups_elimination(JOIN *join, ulonglong options,
for (i= join->const_tables ; i < join->top_join_tab_count; )
{
JOIN_TAB *tab=join->join_tab + i;
- //POSITION *pos= join->best_positions + i;
- uint keylen, keyno;
switch (pos->sj_strategy) {
case SJ_OPT_MATERIALIZE:
case SJ_OPT_MATERIALIZE_SCAN:
@@ -4753,26 +4843,7 @@ int setup_semijoin_dups_elimination(JOIN *join, ulonglong options,
break;
case SJ_OPT_LOOSE_SCAN:
{
- /* We jump from the last table to the first one */
- tab->loosescan_match_tab= tab + pos->n_sj_tables - 1;
-
- /* LooseScan requires records to be produced in order */
- if (tab->select && tab->select->quick)
- tab->select->quick->need_sorted_output();
-
- for (uint j= i; j < i + pos->n_sj_tables; j++)
- join->join_tab[j].inside_loosescan_range= TRUE;
-
- /* Calculate key length */
- keylen= 0;
- keyno= pos->loosescan_picker.loosescan_key;
- for (uint kp=0; kp < pos->loosescan_picker.loosescan_parts; kp++)
- keylen += tab->table->key_info[keyno].key_part[kp].store_length;
-
- tab->loosescan_key= keyno;
- tab->loosescan_key_len= keylen;
- if (pos->n_sj_tables > 1)
- tab[pos->n_sj_tables - 1].do_firstmatch= tab;
+ /* Setup already handled by setup_semijoin_loosescan */
i+= pos->n_sj_tables;
pos+= pos->n_sj_tables;
break;
@@ -5374,13 +5445,14 @@ TABLE *create_dummy_tmp_table(THD *thd)
sjm_table_param.init();
sjm_table_param.field_count= 1;
List<Item> sjm_table_cols;
- Item *column_item= new Item_int(1);
- sjm_table_cols.push_back(column_item);
+ Item *column_item= new (thd->mem_root) Item_int(thd, 1);
+ sjm_table_cols.push_back(column_item, thd->mem_root);
if (!(table= create_tmp_table(thd, &sjm_table_param,
sjm_table_cols, (ORDER*) 0,
TRUE /* distinct */,
1, /*save_sum_fields*/
- thd->variables.option_bits | TMP_TABLE_ALL_COLUMNS,
+ thd->variables.option_bits |
+ TMP_TABLE_ALL_COLUMNS,
HA_POS_ERROR /*rows_limit */,
(char*)"dummy", TRUE /* Do not open */)))
{
@@ -5401,8 +5473,8 @@ TABLE *create_dummy_tmp_table(THD *thd)
class select_value_catcher :public select_subselect
{
public:
- select_value_catcher(Item_subselect *item_arg)
- :select_subselect(item_arg)
+ select_value_catcher(THD *thd_arg, Item_subselect *item_arg):
+ select_subselect(thd_arg, item_arg)
{}
int send_data(List<Item> &items);
int setup(List<Item> *items);
@@ -5417,16 +5489,16 @@ int select_value_catcher::setup(List<Item> *items)
assigned= FALSE;
n_elements= items->elements;
- if (!(row= (Item_cache**) sql_alloc(sizeof(Item_cache*)*n_elements)))
+ if (!(row= (Item_cache**) thd->alloc(sizeof(Item_cache*) * n_elements)))
return TRUE;
Item *sel_item;
List_iterator<Item> li(*items);
for (uint i= 0; (sel_item= li++); i++)
{
- if (!(row[i]= Item_cache::get_cache(sel_item)))
+ if (!(row[i]= Item_cache::get_cache(thd, sel_item)))
return TRUE;
- row[i]->setup(sel_item);
+ row[i]->setup(thd, sel_item);
}
return FALSE;
}
@@ -5466,6 +5538,7 @@ bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list,
TABLE_LIST *table;
NESTED_JOIN *nested_join;
List_iterator<TABLE_LIST> li(*join_list);
+ THD *thd= join->thd;
DBUG_ENTER("setup_jtbm_semi_joins");
while ((table= li++))
@@ -5497,7 +5570,7 @@ bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list,
0 or 1 record. Examples of both cases:
select * from ot where col in (select ... from it where 2>3)
- select * from ot where col in (select min(it.key) from it)
+ select * from ot where col in (select MY_MIN(it.key) from it)
in this case, the subquery predicate has not been setup for
materialization. In particular, there is no materialized temp.table.
@@ -5513,10 +5586,11 @@ bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list,
subselect_single_select_engine *engine=
(subselect_single_select_engine*)subq_pred->engine;
select_value_catcher *new_sink;
- if (!(new_sink= new select_value_catcher(subq_pred)))
+ if (!(new_sink=
+ new (thd->mem_root) select_value_catcher(thd, subq_pred)))
DBUG_RETURN(TRUE);
if (new_sink->setup(&engine->select_lex->join->fields_list) ||
- engine->select_lex->join->change_result(new_sink) ||
+ engine->select_lex->join->change_result(new_sink, NULL) ||
engine->exec())
{
DBUG_RETURN(TRUE);
@@ -5533,13 +5607,14 @@ bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list,
Item *eq_cond;
for (uint i= 0; i < subq_pred->left_expr->cols(); i++)
{
- eq_cond= new Item_func_eq(subq_pred->left_expr->element_index(i),
- new_sink->row[i]);
+ eq_cond= new (thd->mem_root)
+ Item_func_eq(thd, subq_pred->left_expr->element_index(i),
+ new_sink->row[i]);
if (!eq_cond)
DBUG_RETURN(1);
- if (!((*join_where)= and_items(*join_where, eq_cond)) ||
- (*join_where)->fix_fields(join->thd, join_where))
+ if (!((*join_where)= and_items(thd, *join_where, eq_cond)) ||
+ (*join_where)->fix_fields(thd, join_where))
DBUG_RETURN(1);
}
}
@@ -5551,7 +5626,7 @@ bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list,
/* Set up a dummy TABLE*, optimizer code needs JOIN_TABs to have TABLE */
TABLE *dummy_table;
- if (!(dummy_table= create_dummy_tmp_table(join->thd)))
+ if (!(dummy_table= create_dummy_tmp_table(thd)))
DBUG_RETURN(1);
table->table= dummy_table;
table->table->pos_in_table_list= table;
@@ -5577,11 +5652,11 @@ bool setup_jtbm_semi_joins(JOIN *join, List<TABLE_LIST> *join_list,
Item *sj_conds= hash_sj_engine->semi_join_conds;
- (*join_where)= and_items(*join_where, sj_conds);
+ (*join_where)= and_items(thd, *join_where, sj_conds);
if (!(*join_where)->fixed)
- (*join_where)->fix_fields(join->thd, join_where);
+ (*join_where)->fix_fields(thd, join_where);
}
- table->table->maybe_null= test(join->mixed_implicit_grouping);
+ table->table->maybe_null= MY_TEST(join->mixed_implicit_grouping);
}
if ((nested_join= table->nested_join))
@@ -5768,7 +5843,7 @@ bool JOIN::choose_subquery_plan(table_map join_tables)
unmodified, and with injected IN->EXISTS predicates.
*/
inner_read_time_1= inner_join->best_read;
- inner_record_count_1= inner_join->record_count;
+ inner_record_count_1= inner_join->join_record_count;
if (in_to_exists_where && const_tables != table_count)
{
@@ -5869,8 +5944,8 @@ bool JOIN::choose_subquery_plan(table_map join_tables)
Item_in_subselect::test_limit). However, once we allow this, here
we should set the correct limit if given in the query.
*/
- in_subs->unit->global_parameters->select_limit= NULL;
- in_subs->unit->set_limit(unit->global_parameters);
+ in_subs->unit->global_parameters()->select_limit= NULL;
+ in_subs->unit->set_limit(unit->global_parameters());
/*
Set the limit of this JOIN object as well, because normally its being
set in the beginning of JOIN::optimize, which was already done.