diff options
Diffstat (limited to 'sql/opt_subselect.cc')
-rw-r--r-- | sql/opt_subselect.cc | 55 |
1 files changed, 39 insertions, 16 deletions
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 167194df785..c0d0fa3c7f3 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 @@ -1611,9 +1611,20 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) sj_nest->sj_on_expr= and_items(sj_nest->sj_on_expr, item_eq); } } - /* Fix the created equality and AND */ - if (!sj_nest->sj_on_expr->fixed) - sj_nest->sj_on_expr->fix_fields(parent_join->thd, &sj_nest->sj_on_expr); + /* + Fix the created equality and AND + + Note that fix_fields() can actually fail in a meaningful way here. One + example is when the IN-equality is not valid, because it compares columns + with incompatible collations. (One can argue it would be more appropriate + to check for this at name resolution stage, but as a legacy of IN->EXISTS + 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)) + { + DBUG_RETURN(TRUE); + } /* Walk through sj nest's WHERE and ON expressions and call @@ -1632,12 +1643,15 @@ 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(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); + if (!emb_tbl_nest->on_expr->fixed && + emb_tbl_nest->on_expr->fix_fields(parent_join->thd, + &emb_tbl_nest->on_expr)) + { + DBUG_RETURN(TRUE); + } } else { @@ -1650,8 +1664,12 @@ 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); + if (!parent_join->conds->fixed && + parent_join->conds->fix_fields(parent_join->thd, + &parent_join->conds)) + { + DBUG_RETURN(1); + } thd->lex->current_select=save_lex; parent_join->select_lex->where= parent_join->conds; } @@ -2508,10 +2526,16 @@ 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; - pos->prefix_dups_producing_tables= join->cur_dups_producing_tables; + table_map dups_producing_tables; + + if (idx == join->const_tables) + dups_producing_tables= 0; + else + dups_producing_tables= pos[-1].dups_producing_tables; + TABLE_LIST *emb_sj_nest; if ((emb_sj_nest= new_join_tab->emb_sj_nest)) - join->cur_dups_producing_tables |= emb_sj_nest->sj_inner_tables; + dups_producing_tables |= emb_sj_nest->sj_inner_tables; Semi_join_strategy_picker **strategy; if (idx == join->const_tables) @@ -2564,7 +2588,7 @@ void advance_sj_state(JOIN *join, table_map remaining_tables, uint idx, fanout from semijoin X. 3. We have no clue what to do about fanount of semi-join Y. */ - if ((join->cur_dups_producing_tables & handled_fanout) || + if ((dups_producing_tables & handled_fanout) || (read_time < *current_read_time && !(handled_fanout & pos->inner_tables_handled_with_other_sjs))) { @@ -2577,7 +2601,7 @@ void advance_sj_state(JOIN *join, table_map remaining_tables, uint idx, join->sjm_lookup_tables &= ~handled_fanout; *current_read_time= read_time; *current_record_count= rec_count; - join->cur_dups_producing_tables &= ~handled_fanout; + dups_producing_tables &= ~handled_fanout; //TODO: update bitmap of semi-joins that were handled together with // others. if (is_multiple_semi_joins(join, join->positions, idx, handled_fanout)) @@ -2604,6 +2628,7 @@ void advance_sj_state(JOIN *join, table_map remaining_tables, uint idx, pos->prefix_cost.convert_from_cost(*current_read_time); pos->prefix_record_count= *current_record_count; + pos->dups_producing_tables= dups_producing_tables; } @@ -3115,8 +3140,6 @@ void restore_prev_sj_state(const table_map remaining_tables, tab->join->cur_sj_inner_tables &= ~emb_sj_nest->sj_inner_tables; } } - POSITION *pos= tab->join->positions + idx; - tab->join->cur_dups_producing_tables= pos->prefix_dups_producing_tables; } |