summaryrefslogtreecommitdiff
path: root/sql/sql_select.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_select.cc')
-rw-r--r--sql/sql_select.cc539
1 files changed, 366 insertions, 173 deletions
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 07daaa2bd5c..f22510bb2b7 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -80,7 +80,7 @@ static bool sort_and_filter_keyuse(THD *thd, DYNAMIC_ARRAY *keyuse,
bool skip_unprefixed_keyparts);
static int sort_keyuse(KEYUSE *a,KEYUSE *b);
static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
- table_map used_tables);
+ bool allow_full_scan, table_map used_tables);
void best_access_path(JOIN *join, JOIN_TAB *s,
table_map remaining_tables, uint idx,
bool disable_jbuf, double record_count,
@@ -106,7 +106,7 @@ C_MODE_END
static bool find_best(JOIN *join,table_map rest_tables,uint index,
double record_count,double read_time);
static uint cache_record_length(JOIN *join,uint index);
-static bool get_best_combination(JOIN *join);
+bool get_best_combination(JOIN *join);
static store_key *get_store_key(THD *thd,
KEYUSE *keyuse, table_map used_tables,
KEY_PART_INFO *key_part, uchar *key_buff,
@@ -451,6 +451,73 @@ fix_inner_refs(THD *thd, List<Item> &all_fields, SELECT_LEX *select,
}
/**
+ The following clauses are redundant for subqueries:
+
+ DISTINCT
+ GROUP BY if there are no aggregate functions and no HAVING
+ clause
+
+ Because redundant clauses are removed both from JOIN and
+ select_lex, the removal is permanent. Thus, it only makes sense to
+ call this function for normal queries and on first execution of
+ SP/PS
+
+ @param subq_select_lex select_lex that is part of a subquery
+ predicate. This object and the associated
+ join is modified.
+*/
+
+static
+void remove_redundant_subquery_clauses(st_select_lex *subq_select_lex)
+{
+ Item_subselect *subq_predicate= subq_select_lex->master_unit()->item;
+ /*
+ The removal should happen for IN, ALL, ANY and EXISTS subqueries,
+ which means all but single row subqueries. Example single row
+ subqueries:
+ a) SELECT * FROM t1 WHERE t1.a = (<single row subquery>)
+ b) SELECT a, (<single row subquery) FROM t1
+ */
+ if (subq_predicate->substype() == Item_subselect::SINGLEROW_SUBS)
+ return;
+
+ /* A subquery that is not single row should be one of IN/ALL/ANY/EXISTS. */
+ DBUG_ASSERT (subq_predicate->substype() == Item_subselect::EXISTS_SUBS ||
+ subq_predicate->is_in_predicate());
+
+ if (subq_select_lex->options & SELECT_DISTINCT)
+ {
+ subq_select_lex->join->select_distinct= false;
+ subq_select_lex->options&= ~SELECT_DISTINCT;
+ }
+
+ /*
+ Remove GROUP BY if there are no aggregate functions and no HAVING
+ clause
+ */
+ if (subq_select_lex->group_list.elements &&
+ !subq_select_lex->with_sum_func && !subq_select_lex->join->having)
+ {
+ subq_select_lex->join->group_list= NULL;
+ subq_select_lex->group_list.empty();
+ }
+
+ /*
+ TODO: This would prevent processing quries with ORDER BY ... LIMIT
+ therefore we disable this optimization for now.
+ Remove GROUP BY if there are no aggregate functions and no HAVING
+ clause
+ if (subq_select_lex->group_list.elements &&
+ !subq_select_lex->with_sum_func && !subq_select_lex->join->having)
+ {
+ subq_select_lex->join->group_list= NULL;
+ subq_select_lex->group_list.empty();
+ }
+ */
+}
+
+
+/**
Function to setup clauses without sum functions.
*/
inline int setup_without_group(THD *thd, Item **ref_pointer_array,
@@ -547,6 +614,22 @@ JOIN::prepare(Item ***rref_pointer_array,
tables_list, select_lex->leaf_tables,
FALSE, SELECT_ACL, SELECT_ACL, FALSE))
DBUG_RETURN(-1);
+
+ /*
+ Permanently remove redundant parts from the query if
+ 1) This is a subquery
+ 2) This is the first time this query is optimized (since the
+ transformation is permanent
+ 3) Not normalizing a view. Removal should take place when a
+ query involving a view is optimized, not when the view
+ is created
+ */
+ if (select_lex->master_unit()->item && // 1)
+ select_lex->first_cond_optimization && // 2)
+ !(thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW)) // 3)
+ {
+ remove_redundant_subquery_clauses(select_lex);
+ }
/*
TRUE if the SELECT list mixes elements with and without grouping,
@@ -589,6 +672,9 @@ JOIN::prepare(Item ***rref_pointer_array,
aggregate functions and non-aggregate fields, any non-aggregated field
may produce a NULL value. Set all fields of each table as nullable before
semantic analysis to take into account this change of nullability.
+
+ Note: this loop doesn't touch tables inside merged semi-joins, because
+ subquery-to-semijoin conversion has not been done yet. This is intended.
*/
if (mixed_implicit_grouping)
tbl->table->maybe_null= 1;
@@ -824,58 +910,6 @@ err:
}
-void
-inject_jtbm_conds(JOIN *join, List<TABLE_LIST> *join_list, Item **join_where)
-{
- TABLE_LIST *table;
- NESTED_JOIN *nested_join;
- List_iterator<TABLE_LIST> li(*join_list);
- DBUG_ENTER("inject_jtbm_conds");
-
-
- while ((table= li++))
- {
- Item_in_subselect *item;
-
- if ((item= table->jtbm_subselect))
- {
- Item_in_subselect *subq_pred= item;
- double rows;
- double read_time;
-
- //DBUG_ASSERT(subq_pred->test_set_strategy(SUBS_MATERIALIZATION));
- subq_pred->optimize(&rows, &read_time);
-
- subq_pred->jtbm_read_time= read_time;
- subq_pred->jtbm_record_count=rows;
- subq_pred->is_jtbm_merged= TRUE;
-
- subselect_hash_sj_engine *hash_sj_engine=
- ((subselect_hash_sj_engine*)item->engine);
-
-
- //repeat of convert_subq_to_jtbm:
- table->table= hash_sj_engine->tmp_table;
- table->table->pos_in_table_list= table;
-
- setup_table_map(table->table, table, table->jtbm_table_no);
-
- Item *sj_conds= hash_sj_engine->semi_join_conds;
-
- (*join_where)= and_items(*join_where, sj_conds);
- if (!(*join_where)->fixed)
- (*join_where)->fix_fields(join->thd, join_where);
- //parent_join->select_lex->where= parent_join->conds;
- }
-
- if ((nested_join= table->nested_join))
- {
- inject_jtbm_conds(join, &nested_join->join_list, join_where);
- }
- }
- DBUG_VOID_RETURN;
-}
-
/**
global select optimisation.
@@ -947,9 +981,6 @@ JOIN::optimize()
select_limit= unit->select_limit_cnt;
if (having || (select_options & OPTION_FOUND_ROWS))
select_limit= HA_POS_ERROR;
- // Ignore errors of execution if option IGNORE present
- if (thd->lex->ignore)
- thd->lex->current_select->no_error= 1;
#ifdef HAVE_REF_TO_FIELDS // Not done yet
/* Add HAVING to WHERE if possible */
if (having && !group_list && !sum_func_count)
@@ -1003,7 +1034,8 @@ JOIN::optimize()
thd->restore_active_arena(arena, &backup);
}
- inject_jtbm_conds(this, join_list, &conds);
+ if (setup_jtbm_semi_joins(this, join_list, &conds))
+ DBUG_RETURN(1);
conds= optimize_cond(this, conds, join_list, &cond_value, &cond_equal);
@@ -1450,7 +1482,10 @@ JOIN::optimize()
DBUG_RETURN(1);
}
if (old_group_list && !group_list)
+ {
+ DBUG_ASSERT(group);
select_distinct= 0;
+ }
}
if (!group_list && group)
{
@@ -1458,6 +1493,7 @@ JOIN::optimize()
simple_order=1;
select_distinct= 0; // No need in distinct for 1 row
group_optimized_away= 1;
+ implicit_grouping= TRUE;
}
calc_group_buffer(this, group_list);
@@ -1484,7 +1520,7 @@ JOIN::optimize()
}
// Can't use sort on head table if using join buffering
- if (full_join)
+ if (full_join || hash_join)
{
TABLE *stable= (sort_by_table == (TABLE *) 1 ?
join_tab[const_tables].table : sort_by_table);
@@ -1501,22 +1537,7 @@ JOIN::optimize()
}
}
- /*
- Check if we need to create a temporary table.
- This has to be done if all tables are not already read (const tables)
- and one of the following conditions holds:
- - We are using DISTINCT (simple distinct's are already optimized away)
- - We are using an ORDER BY or GROUP BY on fields not in the first table
- - We are using different ORDER BY and GROUP BY orders
- - The user wants us to buffer the result.
- When the WITH ROLLUP modifier is present, we cannot skip temporary table
- creation for the DISTINCT clause just because there are only const tables.
- */
- need_tmp= ((const_tables != table_count &&
- ((select_distinct || !simple_order || !simple_group) ||
- (group_list && order) ||
- test(select_options & OPTION_BUFFER_RESULT))) ||
- (rollup.state != ROLLUP::STATE_NONE && select_distinct));
+ need_tmp= test_if_need_tmp_table();
/*
If the hint FORCE INDEX FOR ORDER BY/GROUP BY is used for the table
@@ -1655,6 +1676,7 @@ JOIN::optimize()
}
error= 0;
+
DBUG_RETURN(0);
setup_subq_exit:
@@ -2903,7 +2925,7 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
if (!(join= new JOIN(thd, fields, select_options, result)))
DBUG_RETURN(TRUE);
thd_proc_info(thd, "init");
- thd->lex->used_tables=0; // Updated by setup_fields
+ thd->lex->used_tables=0;
if ((err= join->prepare(rref_pointer_array, tables, wild_num,
conds, og_num, order, group, having, proc_param,
select_lex, unit)))
@@ -3048,6 +3070,14 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
table->pos_in_table_list= tables;
error= tables->fetch_number_of_rows();
+ DBUG_EXECUTE_IF("bug11747970_raise_error",
+ {
+ if (!error)
+ {
+ my_error(ER_UNKNOWN_ERROR, MYF(0));
+ goto error;
+ }
+ });
if (error)
{
table->file->print_error(error, MYF(0));
@@ -3132,6 +3162,14 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
set_position(join,const_count++,s,(KEYUSE*) 0);
no_rows_const_tables |= table->map;
}
+
+ /* SJ-Materialization handling: */
+ if (table->pos_in_table_list->jtbm_subselect &&
+ table->pos_in_table_list->jtbm_subselect->is_jtbm_const_tab)
+ {
+ set_position(join,const_count++,s,(KEYUSE*) 0);
+ no_rows_const_tables |= table->map;
+ }
}
stat_vector[i]=0;
@@ -3376,7 +3414,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list,
s->type= JT_CONST;
join->const_table_map|=table->map;
set_position(join,const_count++,s,start_keyuse);
- if (create_ref_for_key(join, s, start_keyuse,
+ if (create_ref_for_key(join, s, start_keyuse, FALSE,
found_const_table_map))
goto error;
if ((tmp=join_read_const_table(s,
@@ -4982,7 +5020,7 @@ void set_position(JOIN *join,uint idx,JOIN_TAB *table,KEYUSE *key)
join->positions[idx].records_read=1.0; /* This is a const table */
join->positions[idx].ref_depend_map= 0;
- join->positions[idx].loosescan_key= MAX_KEY; /* Not a LooseScan */
+// join->positions[idx].loosescan_key= MAX_KEY; /* Not a LooseScan */
join->positions[idx].sj_strategy= SJ_OPT_NONE;
join->positions[idx].use_join_buffer= FALSE;
@@ -5080,6 +5118,8 @@ best_access_path(JOIN *join,
MY_BITMAP *eq_join_set= &s->table->eq_join_set;
KEYUSE *hj_start_key= 0;
+ disable_jbuf= disable_jbuf || idx == join->const_tables;
+
Loose_scan_opt loose_scan_opt;
DBUG_ENTER("best_access_path");
@@ -5476,7 +5516,9 @@ best_access_path(JOIN *join,
(1) s is inner table of semi-join -> join cache is allowed for semijoins
(2) s is inner table of outer join -> join cache is allowed for outer joins
*/
- if (idx > join->const_tables && best_key == 0 &&
+ if (idx > join->const_tables && best_key == 0 &&
+ (join->allowed_join_cache_types & JOIN_CACHE_HASHED_BIT) &&
+ join->max_allowed_join_cache_level > 2 &&
!bitmap_is_clear_all(eq_join_set) && !disable_jbuf &&
(!s->emb_sj_nest ||
join->allowed_semijoin_with_cache) && // (1)
@@ -5632,7 +5674,7 @@ best_access_path(JOIN *join,
pos->key= best_key;
pos->table= s;
pos->ref_depend_map= best_ref_depends_map;
- pos->loosescan_key= MAX_KEY;
+ pos->loosescan_picker.loosescan_key= MAX_KEY;
pos->use_join_buffer= best_uses_jbuf;
loose_scan_opt.save_to_position(s, loose_scan_pos);
@@ -5938,22 +5980,22 @@ optimize_straight_join(JOIN *join, table_map join_tables)
/* compute the cost of the new plan extended with 's' */
record_count*= join->positions[idx].records_read;
- read_time+= join->positions[idx].read_time;
- advance_sj_state(join, join_tables, s, idx, &record_count, &read_time,
+ read_time+= join->positions[idx].read_time +
+ record_count / (double) TIME_FOR_COMPARE;
+ advance_sj_state(join, join_tables, idx, &record_count, &read_time,
&loose_scan_pos);
join_tables&= ~(s->table->map);
++idx;
}
- read_time+= record_count / (double) TIME_FOR_COMPARE;
if (join->sort_by_table &&
join->sort_by_table != join->positions[join->const_tables].table->table)
read_time+= record_count; // We have to make a temp table
memcpy((uchar*) join->best_positions, (uchar*) join->positions,
sizeof(POSITION)*idx);
join->record_count= record_count;
- join->best_read= read_time;
+ join->best_read= read_time - 0.001;
}
@@ -6121,7 +6163,8 @@ greedy_search(JOIN *join,
/* compute the cost of the new plan extended with 'best_table' */
record_count*= join->positions[idx].records_read;
- read_time+= join->positions[idx].read_time;
+ read_time+= join->positions[idx].read_time +
+ record_count / (double) TIME_FOR_COMPARE;
remaining_tables&= ~(best_table->table->map);
--size_remain;
@@ -6229,7 +6272,7 @@ void JOIN::get_partial_cost_and_fanout(int end_tab_idx,
if (tab->records_read && (cur_table_map & filter_map))
{
record_count *= tab->records_read;
- read_time += tab->read_time;
+ read_time += tab->read_time + record_count / (double) TIME_FOR_COMPARE;
if (tab->emb_sj_nest)
sj_inner_fanout *= tab->records_read;
}
@@ -6453,21 +6496,19 @@ best_extension_by_limited_search(JOIN *join,
/* Compute the cost of extending the plan with 's' */
current_record_count= record_count * position->records_read;
- current_read_time= read_time + position->read_time;
+ current_read_time=read_time + position->read_time +
+ current_record_count / (double) TIME_FOR_COMPARE;
- advance_sj_state(join, remaining_tables, s, idx, &current_record_count,
+ advance_sj_state(join, remaining_tables, idx, &current_record_count,
&current_read_time, &loose_scan_pos);
/* Expand only partial plans with lower cost than the best QEP so far */
- if ((current_read_time +
- current_record_count / (double) TIME_FOR_COMPARE) >= join->best_read)
+ if (current_read_time >= join->best_read)
{
DBUG_EXECUTE("opt", print_plan(join, idx+1,
current_record_count,
read_time,
- (current_read_time +
- current_record_count /
- (double) TIME_FOR_COMPARE),
+ current_read_time,
"prune_by_cost"););
restore_prev_nj_state(s);
restore_prev_sj_state(remaining_tables, s, idx);
@@ -6526,13 +6567,12 @@ best_extension_by_limited_search(JOIN *join,
'join' is either the best partial QEP with 'search_depth' relations,
or the best complete QEP so far, whichever is smaller.
*/
- current_read_time+= current_record_count / (double) TIME_FOR_COMPARE;
if (join->sort_by_table &&
join->sort_by_table !=
join->positions[join->const_tables].table->table)
/* We have to make a temp table */
current_read_time+= current_record_count;
- if ((search_depth == 1) || (current_read_time < join->best_read))
+ if (current_read_time < join->best_read)
{
memcpy((uchar*) join->best_positions, (uchar*) join->positions,
sizeof(POSITION) * (idx + 1));
@@ -6612,7 +6652,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
*/
double current_record_count=record_count*records;
double current_read_time=read_time+best;
- advance_sj_state(join, rest_tables, s, idx, &current_record_count,
+ advance_sj_state(join, rest_tables, idx, &current_record_count,
&current_read_time, &loose_scan_pos);
if (best_record_count > current_record_count ||
@@ -7112,7 +7152,7 @@ static Item * const null_ptr= NULL;
TRUE Out of memory
*/
-static bool
+bool
get_best_combination(JOIN *join)
{
uint tablenr;
@@ -7129,6 +7169,7 @@ get_best_combination(JOIN *join)
DBUG_RETURN(TRUE);
join->full_join=0;
+ join->hash_join= FALSE;
used_tables= OUTER_REF_TABLE_BIT; // Outer row is already read
@@ -7190,13 +7231,6 @@ get_best_combination(JOIN *join)
*j= *join->best_positions[tablenr].table;
-#if 0
-/* SJ-Materialization is represented with join tab ranges */
- if (j->sj_strategy == SJ_OPT_MATERIALIZE ||
- j->sj_strategy == SJ_OPT_MATERIALIZE)
- j->sj_strategy= SJ_OPT_NONE;
-#endif
-
j->bush_root_tab= sjm_nest_root;
form=join->table[tablenr]=j->table;
@@ -7215,16 +7249,27 @@ get_best_combination(JOIN *join)
if (j->type == JT_SYSTEM)
goto loop_end;
- if ( !(keyuse= join->best_positions[tablenr].key) ||
- (join->best_positions[tablenr].sj_strategy == SJ_OPT_LOOSE_SCAN))
+ if ( !(keyuse= join->best_positions[tablenr].key))
{
j->type=JT_ALL;
- j->index= join->best_positions[tablenr].loosescan_key;
if (tablenr != join->const_tables)
join->full_join=1;
}
- else if (create_ref_for_key(join, j, keyuse, used_tables))
+
+ /*if (join->best_positions[tablenr].sj_strategy == SJ_OPT_LOOSE_SCAN)
+ {
+ DBUG_ASSERT(!keyuse || keyuse->key ==
+ join->best_positions[tablenr].loosescan_picker.loosescan_key);
+ j->index= join->best_positions[tablenr].loosescan_picker.loosescan_key;
+ }*/
+
+ if (keyuse && create_ref_for_key(join, j, keyuse, TRUE, used_tables))
DBUG_RETURN(TRUE); // Something went wrong
+
+ if ((j->type == JT_REF || j->type == JT_EQ_REF) &&
+ is_hash_join_key_no(j->ref.key))
+ join->hash_join= TRUE;
+
loop_end:
/*
Save records_read in JOIN_TAB so that select_describe()/etc don't have
@@ -7285,10 +7330,26 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab,
do
{
- if (!(~used_tables & keyuse->used_tables) &&
- (first_keyuse || keyuse->keypart != (keyuse-1)->keypart))
- key_parts++;
- first_keyuse= FALSE;
+ if (!(~used_tables & keyuse->used_tables))
+ {
+ if (first_keyuse)
+ {
+ key_parts++;
+ first_keyuse= FALSE;
+ }
+ else
+ {
+ KEYUSE *curr= org_keyuse;
+ for( ; curr < keyuse; curr++)
+ {
+ if (curr->keypart == keyuse->keypart &&
+ !(~used_tables & curr->used_tables))
+ break;
+ }
+ if (curr == keyuse)
+ key_parts++;
+ }
+ }
keyuse++;
} while (keyuse->table == table && keyuse->is_for_hash_join());
if (!key_parts)
@@ -7313,15 +7374,31 @@ static bool create_hj_key_for_table(JOIN *join, JOIN_TAB *join_tab,
keyuse= org_keyuse;
do
{
- if (!(~used_tables & keyuse->used_tables) &&
- (first_keyuse || keyuse->keypart != (keyuse-1)->keypart))
- {
- Field *field= table->field[keyuse->keypart];
- uint fieldnr= keyuse->keypart+1;
- table->create_key_part_by_field(keyinfo, key_part_info, field, fieldnr);
- first_keyuse= FALSE;
- key_part_info++;
+ if (!(~used_tables & keyuse->used_tables))
+ {
+ bool add_key_part= TRUE;
+ if (!first_keyuse)
+ {
+ for(KEYUSE *curr= org_keyuse; curr < keyuse; curr++)
+ {
+ if (curr->keypart == keyuse->keypart &&
+ !(~used_tables & curr->used_tables))
+ {
+ keyuse->keypart= NO_KEYPART;
+ add_key_part= FALSE;
+ break;
+ }
+ }
+ }
+ if (add_key_part)
+ {
+ Field *field= table->field[keyuse->keypart];
+ uint fieldnr= keyuse->keypart+1;
+ table->create_key_part_by_field(keyinfo, key_part_info, field, fieldnr);
+ key_part_info++;
+ }
}
+ first_keyuse= FALSE;
keyuse++;
} while (keyuse->table == table && keyuse->is_for_hash_join());
@@ -7359,7 +7436,8 @@ static bool are_tables_local(JOIN_TAB *jtab, table_map used_tables)
}
static bool create_ref_for_key(JOIN *join, JOIN_TAB *j,
- KEYUSE *org_keyuse, table_map used_tables)
+ KEYUSE *org_keyuse, bool allow_full_scan,
+ table_map used_tables)
{
uint keyparts, length, key;
TABLE *table;
@@ -7404,8 +7482,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j,
{
if (are_tables_local(j, keyuse->val->used_tables()))
{
- if ((is_hash_join_key_no(key) &&
- (keyparts == 0 || keyuse->keypart != (keyuse-1)->keypart)) ||
+ if ((is_hash_join_key_no(key) && keyuse->keypart != NO_KEYPART) ||
(!is_hash_join_key_no(key) && keyparts == keyuse->keypart &&
!(found_part_ref_or_null & keyuse->optimize)))
{
@@ -7418,6 +7495,14 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j,
keyuse++;
} while (keyuse->table == table && keyuse->key == key);
} /* not ftkey */
+
+ if (!keyparts && allow_full_scan)
+ {
+ /* It's a LooseIndexScan strategy scanning whole index */
+ j->type= JT_ALL;
+ j->index= key;
+ DBUG_RETURN(FALSE);
+ }
/* set up fieldref */
j->ref.key_parts= keyparts;
@@ -7459,6 +7544,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j,
for (i=0 ; i < keyparts ; keyuse++,i++)
{
while (((~used_tables) & keyuse->used_tables) ||
+ keyuse->keypart == NO_KEYPART ||
(keyuse->keypart !=
(is_hash_join_key_no(key) ?
keyinfo->key_part[i].field->field_index : i)) ||
@@ -8042,14 +8128,33 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
DBUG_RETURN(1); // Impossible const condition
}
- COND *outer_ref_cond= make_cond_for_table(thd, cond,
- OUTER_REF_TABLE_BIT,
- OUTER_REF_TABLE_BIT,
- -1, FALSE, FALSE);
- if (outer_ref_cond)
- {
- add_cond_and_fix(thd, &outer_ref_cond, join->outer_ref_cond);
- join->outer_ref_cond= outer_ref_cond;
+ if (join->table_count != join->const_tables)
+ {
+ COND *outer_ref_cond= make_cond_for_table(thd, cond,
+ join->const_table_map |
+ OUTER_REF_TABLE_BIT,
+ OUTER_REF_TABLE_BIT,
+ -1, FALSE, FALSE);
+ if (outer_ref_cond)
+ {
+ add_cond_and_fix(thd, &outer_ref_cond, join->outer_ref_cond);
+ join->outer_ref_cond= outer_ref_cond;
+ }
+ }
+ else
+ {
+ COND *pseudo_bits_cond=
+ make_cond_for_table(thd, cond,
+ join->const_table_map |
+ PSEUDO_TABLE_BITS,
+ PSEUDO_TABLE_BITS,
+ -1, FALSE, FALSE);
+ if (pseudo_bits_cond)
+ {
+ add_cond_and_fix(thd, &pseudo_bits_cond,
+ join->pseudo_bits_cond);
+ join->pseudo_bits_cond= pseudo_bits_cond;
+ }
}
}
}
@@ -8441,9 +8546,39 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
COND *tmp_cond= make_cond_for_table(thd, on_expr, used_tables2,
current_map, /*(tab - first_tab)*/ -1,
FALSE, FALSE);
- if (tab == first_inner_tab && tab->on_precond)
+ bool is_sjm_lookup_tab= FALSE;
+ if (tab->bush_children)
+ {
+ /*
+ 'tab' is an SJ-Materialization tab, i.e. we have a join order
+ like this:
+
+ ot1 sjm_tab LEFT JOIN ot2 ot3
+ ^ ^
+ 'tab'-+ +--- left join we're adding triggers for
+
+ LEFT JOIN's ON expression may not have references to subquery
+ columns. The subquery was in the WHERE clause, so IN-equality
+ is in the WHERE clause, also.
+ However, equality propagation code may have propagated the
+ IN-equality into ON expression, and we may get things like
+
+ subquery_inner_table=const
+
+ in the ON expression. We must not check such conditions during
+ SJM-lookup, because 1) subquery_inner_table has no valid current
+ row (materialization temp.table has it instead), and 2) they
+ would be true anyway.
+ */
+ SJ_MATERIALIZATION_INFO *sjm=
+ tab->bush_children->start->emb_sj_nest->sj_mat_info;
+ if (sjm->is_used && !sjm->is_sj_scan)
+ is_sjm_lookup_tab= TRUE;
+ }
+
+ if (tab == first_inner_tab && tab->on_precond && !is_sjm_lookup_tab)
add_cond_and_fix(thd, &tmp_cond, tab->on_precond);
- if (tmp_cond)
+ if (tmp_cond && !is_sjm_lookup_tab)
{
JOIN_TAB *cond_tab= tab < first_inner_tab ? first_inner_tab : tab;
Item **sel_cond_ref= tab < first_inner_tab ?
@@ -8872,8 +9007,7 @@ void revise_cache_usage(JOIN_TAB *join_tab)
first_inner= join_tab->first_sj_inner_tab;
for (tab= join_tab-1; tab >= first_inner; tab--)
{
- if (tab->first_sj_inner_tab == first_inner)
- set_join_cache_denial(tab);
+ set_join_cache_denial(tab);
}
}
else set_join_cache_denial(join_tab);
@@ -9157,11 +9291,12 @@ uint check_join_cache_usage(JOIN_TAB *tab,
for (JOIN_TAB *first_inner= tab->first_inner; first_inner;
first_inner= first_inner->first_upper)
{
- if (first_inner != tab && !first_inner->use_join_cache)
+ if (first_inner != tab &&
+ (!first_inner->use_join_cache || !(tab-1)->use_join_cache))
goto no_join_cache;
}
if (tab->first_sj_inner_tab && tab->first_sj_inner_tab != tab &&
- !tab->first_sj_inner_tab->use_join_cache)
+ (!tab->first_sj_inner_tab->use_join_cache || !(tab-1)->use_join_cache))
goto no_join_cache;
if (!prev_tab->use_join_cache)
{
@@ -9692,8 +9827,6 @@ bool error_if_full_join(JOIN *join)
{
if (tab->type == JT_ALL && (!tab->select || !tab->select->quick))
{
- /* This error should not be ignored. */
- join->select_lex->no_error= FALSE;
my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0));
return(1);
@@ -9734,9 +9867,22 @@ void JOIN_TAB::cleanup()
if (table->pos_in_table_list &&
table->pos_in_table_list->jtbm_subselect)
{
- end_read_record(&read_record);
- table->pos_in_table_list->jtbm_subselect->cleanup();
- table= NULL;
+ if (table->pos_in_table_list->jtbm_subselect->is_jtbm_const_tab)
+ {
+ free_tmp_table(join->thd, table);
+ table= NULL;
+ }
+ else
+ {
+ end_read_record(&read_record);
+ table->pos_in_table_list->jtbm_subselect->cleanup();
+ /*
+ The above call freed the materializedd temptable. Set it to NULL so
+ that we don't attempt to touch it if JOIN_TAB::cleanup() is invoked
+ multiple times (it may be)
+ */
+ table=NULL;
+ }
DBUG_VOID_RETURN;
}
/*
@@ -12047,7 +12193,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top,
{
if (!table->prep_on_expr)
table->prep_on_expr= table->on_expr;
- used_tables= table->table->map;
+ used_tables= table->get_map();
if (conds)
not_null_tables= conds->not_null_tables();
}
@@ -12104,7 +12250,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top,
table->embedding->on_expr_dep_tables|= table->on_expr->used_tables();
}
else
- table->dep_tables&= ~table->table->map;
+ table->dep_tables&= ~table->get_map();
}
if (prev_table)
@@ -12117,7 +12263,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top,
prev_table->dep_tables|= table->on_expr_dep_tables;
table_map prev_used_tables= prev_table->nested_join ?
prev_table->nested_join->used_tables :
- prev_table->table->map;
+ prev_table->get_map();
/*
If on expression contains only references to inner tables
we still make the inner tables dependent on the outer tables.
@@ -14189,10 +14335,22 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
key_part_info->store_length= key_part_info->length;
if ((*reg_field)->real_maybe_null())
+ {
key_part_info->store_length+= HA_KEY_NULL_LENGTH;
- if ((*reg_field)->type() == MYSQL_TYPE_BLOB ||
- (*reg_field)->real_type() == MYSQL_TYPE_VARCHAR)
- key_part_info->store_length+= HA_KEY_BLOB_LENGTH;
+ key_part_info->key_part_flag |= HA_NULL_PART;
+ }
+ if ((*reg_field)->type() == MYSQL_TYPE_BLOB ||
+ (*reg_field)->real_type() == MYSQL_TYPE_VARCHAR ||
+ (*reg_field)->type() == MYSQL_TYPE_GEOMETRY)
+ {
+ if ((*reg_field)->type() == MYSQL_TYPE_BLOB ||
+ (*reg_field)->type() == MYSQL_TYPE_GEOMETRY)
+ key_part_info->key_part_flag|= HA_BLOB_PART;
+ else
+ key_part_info->key_part_flag|= HA_VAR_LENGTH_PART;
+
+ key_part_info->store_length+=HA_KEY_BLOB_LENGTH;
+ }
keyinfo->key_length+= key_part_info->store_length;
@@ -14224,6 +14382,9 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
goto err;
}
+ // Make empty record so random data is not written to disk
+ empty_record(table);
+
thd->mem_root= mem_root_save;
DBUG_RETURN(table);
@@ -14718,6 +14879,7 @@ bool create_internal_tmp_table(TABLE *table, KEY *keyinfo,
goto err;
}
status_var_increment(table->in_use->status_var.created_tmp_disk_tables);
+ table->in_use->query_plan_flags|= QPLAN_TMP_DISK;
share->db_record_offset= 1;
table->created= TRUE;
DBUG_RETURN(0);
@@ -15041,15 +15203,14 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
{
/*
HAVING will be checked after processing aggregate functions,
- But WHERE should checkd here (we alredy have read tables).
- If there is join->exec_const_cond, and all tables are constant, then it
- is equivalent to join->conds. exec_const_cond is already checked in the
- beginning of JOIN::exec. If it is false, JOIN::exec returns zero
- result already there, therefore execution reaches this point only if
- exec_const_cond is TRUE. Since it is equvalent to join->conds, then
- join->conds is also TRUE.
+ But WHERE should checked here (we alredy have read tables).
+ Notice that make_join_select() splits all conditions in this case
+ into two groups exec_const_cond and outer_ref_cond.
+ If join->table_count == join->const_tables then it is
+ sufficient to check only the condition pseudo_bits_cond.
*/
- if (!join->conds || join->exec_const_cond || join->conds->val_int())
+ DBUG_ASSERT(join->outer_ref_cond == NULL);
+ if (!join->pseudo_bits_cond || join->pseudo_bits_cond->val_int())
{
error= (*end_select)(join, 0, 0);
if (error == NESTED_LOOP_OK || error == NESTED_LOOP_QUERY_LIMIT)
@@ -15375,10 +15536,12 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
int error;
enum_nested_loop_state rc= NESTED_LOOP_OK;
READ_RECORD *info= &join_tab->read_record;
-
- if (join_tab->flush_weedout_table)
+
+ for (SJ_TMP_TABLE *flush_dups_table= join_tab->flush_weedout_table;
+ flush_dups_table;
+ flush_dups_table= flush_dups_table->next_flush_table)
{
- do_sj_reset(join_tab->flush_weedout_table);
+ flush_dups_table->sj_weedout_delete_rows();
}
if (!join_tab->preread_init_done && join_tab->preread_init())
@@ -15427,7 +15590,7 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
join_tab->loosescan_match_tab->found_match)
{
KEY *key= join_tab->table->key_info + join_tab->index;
- key_copy(join_tab->loosescan_buf, info->record, key,
+ key_copy(join_tab->loosescan_buf, join_tab->table->record[0], key,
join_tab->loosescan_key_len);
skip_over= TRUE;
}
@@ -15603,7 +15766,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
if (join_tab->check_weed_out_table && found)
{
- int res= do_sj_dups_weedout(join->thd, join_tab->check_weed_out_table);
+ int res= join_tab->check_weed_out_table->sj_weedout_check_row(join->thd);
if (res == -1)
DBUG_RETURN(NESTED_LOOP_ERROR);
else if (res == 1)
@@ -15730,7 +15893,7 @@ evaluate_null_complemented_join_record(JOIN *join, JOIN_TAB *join_tab)
*/
if (join_tab->check_weed_out_table)
{
- int res= do_sj_dups_weedout(join->thd, join_tab->check_weed_out_table);
+ int res= join_tab->check_weed_out_table->sj_weedout_check_row(join->thd);
if (res == -1)
return NESTED_LOOP_ERROR;
else if (res == 1)
@@ -15810,6 +15973,17 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos)
/* Skip materialized derived tables/views. */
DBUG_RETURN(0);
}
+ else if (tab->table->pos_in_table_list->jtbm_subselect &&
+ tab->table->pos_in_table_list->jtbm_subselect->is_jtbm_const_tab)
+ {
+ /* Row will not be found */
+ int res;
+ if (tab->table->pos_in_table_list->jtbm_subselect->jtbm_const_row_found)
+ res= 0;
+ else
+ res= -1;
+ DBUG_RETURN(res);
+ }
else if (tab->type == JT_SYSTEM)
{
if ((error=join_read_system(tab)))
@@ -17675,8 +17849,8 @@ find_field_in_item_list (Field *field, void *data)
while ((item= li++))
{
- if (item->type() == Item::FIELD_ITEM &&
- ((Item_field*) item)->field->eq(field))
+ if (item->real_item()->type() == Item::FIELD_ITEM &&
+ ((Item_field*) (item->real_item()))->field->eq(field))
{
part_found= 1;
break;
@@ -17810,7 +17984,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
while (keyuse->key != new_ref_key && keyuse->table == tab->table)
keyuse++;
- if (create_ref_for_key(tab->join, tab, keyuse,
+ if (create_ref_for_key(tab->join, tab, keyuse, FALSE,
tab->join->const_table_map))
goto use_filesort;
@@ -20665,7 +20839,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
/* id */
item_list.push_back(new Item_uint((uint32)select_id));
/* select_type */
- const char* stype= printing_materialize_nest? "SUBQUERY" :
+ const char* stype= printing_materialize_nest? "MATERIALIZED" :
join->select_lex->type;
item_list.push_back(new Item_string(stype, strlen(stype), cs));
@@ -21062,7 +21236,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
extra.append(STRING_WITH_LEN("; LooseScan"));
}
- if (tab->flush_weedout_table)
+ if (tab->first_weedout_table)
extra.append(STRING_WITH_LEN("; Start temporary"));
if (tab->check_weed_out_table)
extra.append(STRING_WITH_LEN("; End temporary"));
@@ -21370,11 +21544,29 @@ void TABLE_LIST::print(THD *thd, table_map eliminated_tables, String *str,
}
else if (jtbm_subselect)
{
- str->append(STRING_WITH_LEN(" <materialize> ("));
- subselect_hash_sj_engine *hash_engine;
- hash_engine= (subselect_hash_sj_engine*)jtbm_subselect->engine;
- hash_engine->materialize_engine->print(str, query_type);
- str->append(')');
+ if (jtbm_subselect->engine->engine_type() ==
+ subselect_engine::SINGLE_SELECT_ENGINE)
+ {
+ /*
+ We get here when conversion into materialization didn't finish (this
+ happens when
+ - The subquery is a degenerate case which produces 0 or 1 record
+ - subquery's optimization didn't finish because of @@max_join_size
+ limits
+ - ... maybe some other cases like this
+ */
+ str->append(STRING_WITH_LEN(" <materialize> ("));
+ jtbm_subselect->engine->print(str, query_type);
+ str->append(')');
+ }
+ else
+ {
+ str->append(STRING_WITH_LEN(" <materialize> ("));
+ subselect_hash_sj_engine *hash_engine;
+ hash_engine= (subselect_hash_sj_engine*)jtbm_subselect->engine;
+ hash_engine->materialize_engine->print(str, query_type);
+ str->append(')');
+ }
}
else
{
@@ -22015,7 +22207,8 @@ test_if_cheaper_ordering(const JOIN_TAB *tab, ORDER *order, TABLE *table,
uint used_pk_parts= 0;
if (used_key_parts > used_index_parts)
used_pk_parts= used_key_parts-used_index_parts;
- rec_per_key= keyinfo->rec_per_key[used_key_parts-1];
+ rec_per_key= used_key_parts ?
+ keyinfo->rec_per_key[used_key_parts-1] : 1;
/* Take into account the selectivity of the used pk prefix */
if (used_pk_parts)
{