From c020d362b68d0cfad03cabdeef508ca22e26d485 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Tue, 17 Mar 2015 13:26:33 +0300 Subject: MDEV-7474: Semi-Join's DuplicateWeedout strategy skipped ... JOIN::cur_dups_producing_tables was not maintained correctly in the cases of greedy optimization (search_depth < n_tables). Moved it to POSITION structure where it will be maintained automatically. Removed POSITION::prefix_dups_producing_tables since its value can now be calculated. --- sql/opt_subselect.cc | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'sql/opt_subselect.cc') diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 794b4f9b750..ca880e8fdaa 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -2504,10 +2504,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) @@ -2560,7 +2566,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))) { @@ -2573,7 +2579,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)) @@ -2600,6 +2606,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; } @@ -3111,8 +3118,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; } -- cgit v1.2.1 From e428c809d7e2176834ed9889483643e4ef2c2c2b Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Tue, 21 Apr 2015 15:41:01 +0300 Subject: MDEV-7911: crash in Item_cond::eval_not_null_tables convert_subq_to_sj() must check the results of in_equality->fix_fields() call. It can fail in a meaningful way when e.g. we're trying to compare columns with incompatible collations. --- sql/opt_subselect.cc | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) (limited to 'sql/opt_subselect.cc') diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index ca880e8fdaa..ebf640c2987 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -1610,9 +1610,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 @@ -1631,12 +1642,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 { @@ -1649,8 +1663,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; } -- cgit v1.2.1