diff options
-rw-r--r-- | sql/item.h | 15 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 28 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 6 | ||||
-rw-r--r-- | sql/item_subselect.cc | 53 | ||||
-rw-r--r-- | sql/item_subselect.h | 31 | ||||
-rw-r--r-- | sql/opt_subselect.cc | 107 | ||||
-rw-r--r-- | sql/sql_base.cc | 11 | ||||
-rw-r--r-- | sql/sql_lex.cc | 11 | ||||
-rw-r--r-- | sql/sql_select.cc | 11 |
9 files changed, 155 insertions, 118 deletions
diff --git a/sql/item.h b/sql/item.h index 8118b079ca1..ad746a4c3eb 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1841,6 +1841,18 @@ public: */ virtual void top_level_item() {} /* + Return TRUE if it is item of top WHERE level (AND/OR) and it is + important, return FALSE if it not important (we can not use to simplify + calculations) or not top level + */ + virtual bool is_top_level_item() const + { return FALSE; /* not important */} + /* + return IN/ALL/ANY subquery or NULL + */ + virtual Item_in_subselect* get_IN_subquery() + { return NULL; /* in is not IN/ALL/ANY */ } + /* set field of temporary table for Item which can be switched on temporary table during query processing (grouping and so on) */ @@ -2435,7 +2447,8 @@ public: } bool pushable_cond_checker_for_subquery(uchar *arg) { - return excl_dep_on_in_subq_left_part((Item_in_subselect *)arg); + DBUG_ASSERT(((Item*) arg)->get_IN_subquery()); + return excl_dep_on_in_subq_left_part(((Item*)arg)->get_IN_subquery()); } Item *build_pushable_cond(THD *thd, Pushdown_checker checker, diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 24914accc6f..8203af5c7dc 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1197,11 +1197,9 @@ longlong Item_func_truth::val_int() } -bool Item_in_optimizer::is_top_level_item() +bool Item_in_optimizer::is_top_level_item() const { - if (invisible_mode()) - return FALSE; - return ((Item_in_subselect *)args[1])->is_top_level_item(); + return args[1]->is_top_level_item(); } @@ -1265,10 +1263,9 @@ void Item_in_optimizer::print(String *str, enum_query_type query_type) void Item_in_optimizer::restore_first_argument() { - if (!invisible_mode()) - { - args[0]= ((Item_in_subselect *)args[1])->left_expr; - } + Item_in_subselect *in_subs= args[1]->get_IN_subquery(); + if (in_subs) + args[0]= in_subs->left_exp(); } @@ -1292,8 +1289,8 @@ bool Item_in_optimizer::fix_left(THD *thd) the pointer to the post-transformation item. Because of that, on the next execution we need to copy args[1]->left_expr again. */ - ref0= &(((Item_in_subselect *)args[1])->left_expr); - args[0]= ((Item_in_subselect *)args[1])->left_expr; + ref0= args[1]->get_IN_subquery()->left_exp_ptr(); + args[0]= (*ref0); } if ((*ref0)->fix_fields_if_needed(thd, ref0) || (!cache && !(cache= (*ref0)->get_cache(thd)))) @@ -1419,9 +1416,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, Item **ref) bool Item_in_optimizer::invisible_mode() { /* MAX/MIN transformed or EXISTS->IN prepared => do nothing */ - return (args[1]->type() != Item::SUBSELECT_ITEM || - ((Item_subselect *)args[1])->substype() == - Item_subselect::EXISTS_SUBS); + return (args[1]->get_IN_subquery() == NULL); } @@ -1583,7 +1578,7 @@ longlong Item_in_optimizer::val_int() "<outer_value_list> [NOT] IN (SELECT <inner_value_list>...)" where one or more of the outer values is NULL. */ - if (((Item_in_subselect*)args[1])->is_top_level_item()) + if (args[1]->is_top_level_item()) { /* We're evaluating a top level item, e.g. @@ -1606,7 +1601,7 @@ longlong Item_in_optimizer::val_int() SELECT evaluated over the non-NULL values produces at least one row, FALSE otherwise */ - Item_in_subselect *item_subs=(Item_in_subselect*)args[1]; + Item_in_subselect *item_subs= args[1]->get_IN_subquery(); bool all_left_cols_null= true; const uint ncols= cache->cols(); @@ -1752,8 +1747,7 @@ Item *Item_in_optimizer::transform(THD *thd, Item_transformer transformer, ((Item_subselect*)(args[1]))->substype() == Item_subselect::ANY_SUBS)); - Item_in_subselect *in_arg= (Item_in_subselect*)args[1]; - thd->change_item_tree(&in_arg->left_expr, args[0]); + thd->change_item_tree(args[1]->get_IN_subquery()->left_exp_ptr(), args[0]); } return (this->*transformer)(thd, argument); } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 6d02d6642e2..4b64ac82c72 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -384,7 +384,7 @@ public: void set_join_tab_idx(uint join_tab_idx_arg) { args[1]->set_join_tab_idx(join_tab_idx_arg); } virtual void get_cache_parameters(List<Item> ¶meters); - bool is_top_level_item(); + bool is_top_level_item() const override; bool eval_not_null_tables(void *opt_arg); bool find_not_null_fields(table_map allowed); void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); @@ -602,7 +602,7 @@ public: Item_func_not(THD *thd, Item *a): Item_bool_func(thd, a), abort_on_null(FALSE) {} virtual void top_level_item() { abort_on_null= 1; } - bool is_top_level_item() { return abort_on_null; } + bool is_top_level_item() const override { return abort_on_null; } longlong val_int(); enum Functype functype() const { return NOT_FUNC; } const char *func_name() const { return "not"; } @@ -890,7 +890,7 @@ public: Item_bool_func(thd, list), negated(0), pred_level(0) {} public: inline void top_level_item() { pred_level= 1; } - bool is_top_level_item() const { return pred_level; } + bool is_top_level_item() const override { return pred_level; } Item *neg_transformer(THD *thd) { negated= !negated; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 1690ec96e65..16fa06f4cda 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -4141,7 +4141,8 @@ int subselect_uniquesubquery_engine::exec() TABLE *table= tab->table; empty_result_set= TRUE; table->status= 0; - Item_in_subselect *in_subs= (Item_in_subselect *) item; + Item_in_subselect *in_subs= item->get_IN_subquery(); + DBUG_ASSERT(in_subs); if (!tab->preread_init_done && tab->preread_init()) DBUG_RETURN(1); @@ -4186,11 +4187,11 @@ int subselect_uniquesubquery_engine::exec() table->null_row= 0; if (!table->status && (!cond || cond->val_int())) { - ((Item_in_subselect *) item)->value= 1; + in_subs->value= 1; empty_result_set= FALSE; } else - ((Item_in_subselect *) item)->value= 0; + in_subs->value= 0; } DBUG_RETURN(error != 0); @@ -4229,9 +4230,9 @@ int subselect_uniquesubquery_engine::index_lookup() table->null_row= 0; if (!error && (!cond || cond->val_int())) - ((Item_in_subselect *) item)->value= 1; + item->get_IN_subquery()->value= 1; else - ((Item_in_subselect *) item)->value= 0; + item->get_IN_subquery()->value= 0; DBUG_RETURN(0); } @@ -4301,9 +4302,9 @@ int subselect_indexsubquery_engine::exec() int error; bool null_finding= 0; TABLE *table= tab->table; - Item_in_subselect *in_subs= (Item_in_subselect *) item; + Item_in_subselect *in_subs= item->get_IN_subquery(); - ((Item_in_subselect *) item)->value= 0; + in_subs->value= 0; empty_result_set= TRUE; table->status= 0; @@ -4311,7 +4312,7 @@ int subselect_indexsubquery_engine::exec() { /* We need to check for NULL if there wasn't a matching value */ *tab->ref.null_ref_key= 0; // Search first for not null - ((Item_in_subselect *) item)->was_null= 0; + in_subs->was_null= 0; } if (!tab->preread_init_done && tab->preread_init()) @@ -4363,9 +4364,9 @@ int subselect_indexsubquery_engine::exec() { empty_result_set= FALSE; if (null_finding) - ((Item_in_subselect *) item)->was_null= 1; + in_subs->was_null= 1; else - ((Item_in_subselect *) item)->value= 1; + in_subs->value= 1; break; } error= table->file->ha_index_next_same(table->record[0], @@ -4751,7 +4752,7 @@ bool subselect_uniquesubquery_engine::no_tables() subselect_hash_sj_engine::exec_strategy subselect_hash_sj_engine::get_strategy_using_schema() { - Item_in_subselect *item_in= (Item_in_subselect *) item; + Item_in_subselect *item_in= item->get_IN_subquery(); if (item_in->is_top_level_item()) return COMPLETE_MATCH; @@ -4798,7 +4799,7 @@ subselect_hash_sj_engine::get_strategy_using_schema() subselect_hash_sj_engine::exec_strategy subselect_hash_sj_engine::get_strategy_using_data() { - Item_in_subselect *item_in= (Item_in_subselect *) item; + Item_in_subselect *item_in= item->get_IN_subquery(); select_materialize_with_stats *result_sink= (select_materialize_with_stats *) result; Item *outer_col; @@ -5049,8 +5050,9 @@ bool subselect_hash_sj_engine::init(List<Item> *tmp_columns, uint subquery_id) DBUG_RETURN(TRUE); result_sink->get_tmp_table_param()->materialized_subquery= true; - if (item->substype() == Item_subselect::IN_SUBS && - ((Item_in_subselect*)item)->is_jtbm_merged) + + if (item->substype() == Item_subselect::IN_SUBS && + (item->get_IN_subquery()->is_jtbm_merged)) { result_sink->get_tmp_table_param()->force_not_null_cols= true; } @@ -5090,9 +5092,12 @@ bool subselect_hash_sj_engine::init(List<Item> *tmp_columns, uint subquery_id) /* Make sure there is only one index on the temp table, and it doesn't have the extra key part created when s->uniques > 0. + + NOTE: item have to be Item_in_subselect, because class constructor + accept Item_in_subselect as the parmeter. */ DBUG_ASSERT(tmp_table->s->keys == 1 && - ((Item_in_subselect *) item)->left_expr->cols() == + item->get_IN_subquery()->left_expr->cols() == tmp_table->key_info->user_defined_key_parts); if (make_semi_join_conds() || @@ -5141,7 +5146,7 @@ bool subselect_hash_sj_engine::make_semi_join_conds() TABLE_LIST *tmp_table_ref; /* Name resolution context for all tmp_table columns created below. */ Name_resolution_context *context; - Item_in_subselect *item_in= (Item_in_subselect *) item; + Item_in_subselect *item_in= item->get_IN_subquery(); LEX_CSTRING table_name; DBUG_ENTER("subselect_hash_sj_engine::make_semi_join_conds"); DBUG_ASSERT(semi_join_conds == NULL); @@ -5203,7 +5208,7 @@ bool subselect_hash_sj_engine::make_semi_join_conds() subselect_uniquesubquery_engine* subselect_hash_sj_engine::make_unique_engine() { - Item_in_subselect *item_in= (Item_in_subselect *) item; + Item_in_subselect *item_in= item->get_IN_subquery(); Item_iterator_row it(item_in->left_expr); /* The only index on the temporary table. */ KEY *tmp_key= tmp_table->key_info; @@ -5225,7 +5230,7 @@ subselect_hash_sj_engine::make_unique_engine() tab->preread_init_done= FALSE; tab->ref.tmp_table_index_lookup_init(thd, tmp_key, it, FALSE); - DBUG_RETURN(new subselect_uniquesubquery_engine(thd, tab, item, + DBUG_RETURN(new subselect_uniquesubquery_engine(thd, tab, item_in, semi_join_conds)); } @@ -5272,7 +5277,7 @@ void subselect_hash_sj_engine::cleanup() at parse time and stored across executions, while all other materialization related engines are created and chosen for each execution. */ - ((Item_in_subselect *) item)->engine= materialize_engine; + item->get_IN_subquery()->engine= materialize_engine; if (lookup_engine_type == TABLE_SCAN_ENGINE || lookup_engine_type == ROWID_MERGE_ENGINE) { @@ -5512,7 +5517,7 @@ double get_post_group_estimate(JOIN* join, double join_op_rows) int subselect_hash_sj_engine::exec() { - Item_in_subselect *item_in= (Item_in_subselect *) item; + Item_in_subselect *item_in= item->get_IN_subquery(); SELECT_LEX *save_select= thd->lex->current_select; subselect_partial_match_engine *pm_engine= NULL; int res= 0; @@ -6129,7 +6134,7 @@ subselect_partial_match_engine::subselect_partial_match_engine( int subselect_partial_match_engine::exec() { - Item_in_subselect *item_in= (Item_in_subselect *) item; + Item_in_subselect *item_in= item->get_IN_subquery(); int lookup_res; DBUG_ASSERT(!(item_in->left_expr_has_null() && @@ -6251,7 +6256,7 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts, select_materialize_with_stats *result_sink= (select_materialize_with_stats *) result; uint cur_keyid= 0; - Item_in_subselect *item_in= (Item_in_subselect*) item; + Item *left= item->get_IN_subquery()->left_exp(); int error; if (merge_keys_count == 0) @@ -6286,7 +6291,7 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts, /* Create the only non-NULL key if there is any. */ if (non_null_key_parts) { - non_null_key= new Ordered_key(cur_keyid, tmp_table, item_in->left_expr, + non_null_key= new Ordered_key(cur_keyid, tmp_table, left, 0, 0, 0, row_num_to_rowid); if (non_null_key->init(non_null_key_parts)) return TRUE; @@ -6318,7 +6323,7 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts, merge_keys[cur_keyid]= new Ordered_key( cur_keyid, tmp_table, - item_in->left_expr->element_index(i), + left->element_index(i), result_sink->get_null_count_of_col(i), result_sink->get_min_null_of_col(i), result_sink->get_max_null_of_col(i), diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 8f6e4836ac7..e2c82554b73 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -151,9 +151,7 @@ public: virtual subs_type substype() { return UNKNOWN_SUBS; } bool is_in_predicate() { - return (substype() == Item_subselect::IN_SUBS || - substype() == Item_subselect::ALL_SUBS || - substype() == Item_subselect::ANY_SUBS); + return get_IN_subquery() != NULL; } /* @@ -416,7 +414,7 @@ public: void print(String *str, enum_query_type query_type); bool select_transformer(JOIN *join); void top_level_item() { abort_on_null=1; } - inline bool is_top_level_item() { return abort_on_null; } + bool is_top_level_item() const override { return abort_on_null; } bool exists2in_processor(void *opt_arg); Item* expr_cache_insert_transformer(THD *thd, uchar *unused); @@ -507,7 +505,6 @@ protected: bool create_row_in_to_exists_cond(JOIN * join, Item **where_item, Item **having_item); -public: Item *left_expr; /* Important for PS/SP: left_expr_orig is the item that left_expr originally @@ -515,6 +512,7 @@ public: left_expr could later be changed to something on the execution arena. */ Item *left_expr_orig; +public: /* Priority of this predicate in the convert-to-semi-join-nest process. */ int sj_convert_priority; /* May be TRUE only for the candidates to semi-join conversion */ @@ -752,6 +750,15 @@ public: bool pushdown_cond_for_in_subquery(THD *thd, Item *cond); + Item_in_subselect *get_IN_subquery() override + { return this; } + inline Item** left_exp_ptr() + { return &left_expr; } + inline Item* left_exp() const + { return left_expr; } + inline Item* left_exp_orig() const + { return left_expr_orig; } + friend class Item_ref_null_helper; friend class Item_is_not_null_test; friend class Item_in_optimizer; @@ -964,9 +971,9 @@ public: // constructor can assign THD because it will be called after JOIN::prepare subselect_uniquesubquery_engine(THD *thd_arg, st_join_table *tab_arg, - Item_subselect *subs, Item *where) + Item_in_subselect *subs, Item *where) :subselect_engine(subs, 0), tab(tab_arg), cond(where) - {} + { DBUG_ASSERT(subs); } ~subselect_uniquesubquery_engine(); void cleanup(); int prepare(THD *); @@ -1027,12 +1034,12 @@ public: // constructor can assign THD because it will be called after JOIN::prepare subselect_indexsubquery_engine(THD *thd_arg, st_join_table *tab_arg, - Item_subselect *subs, Item *where, + Item_in_subselect *subs, Item *where, Item *having_arg, bool chk_null) :subselect_uniquesubquery_engine(thd_arg, tab_arg, subs, where), check_null(chk_null), having(having_arg) - {} + { DBUG_ASSERT(subs); } int exec(); void print (String *str, enum_query_type query_type); virtual enum_engine_type engine_type() { return INDEXSUBQUERY_ENGINE; } @@ -1095,14 +1102,14 @@ public: Name_resolution_context *semi_join_conds_context; - subselect_hash_sj_engine(THD *thd_arg, Item_subselect *in_predicate, + subselect_hash_sj_engine(THD *thd_arg, Item_in_subselect *in_predicate, subselect_single_select_engine *old_engine) : subselect_engine(in_predicate, NULL), tmp_table(NULL), is_materialized(FALSE), materialize_engine(old_engine), materialize_join(NULL), semi_join_conds(NULL), lookup_engine(NULL), count_partial_match_columns(0), count_null_only_columns(0), count_columns_with_nulls(0), strategy(UNDEFINED) - {} + { DBUG_ASSERT(in_predicate); } ~subselect_hash_sj_engine(); bool init(List<Item> *tmp_columns, uint subquery_id); @@ -1410,7 +1417,7 @@ public: from Item_in_optimizer::val_int() sets Item_in_optimizer::null_value correctly. */ - return !(((Item_in_subselect *) item)->null_value); + return !(item->get_IN_subquery()->null_value); } void print(String*, enum_query_type); diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 62f5964cd3c..343d12b0d60 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -592,10 +592,11 @@ int check_and_do_in_subquery_rewrites(JOIN *join) Item_subselect::subs_type substype= subselect->substype(); switch (substype) { case Item_subselect::IN_SUBS: - in_subs= (Item_in_subselect *)subselect; + in_subs= subselect->get_IN_subquery(); break; case Item_subselect::ALL_SUBS: case Item_subselect::ANY_SUBS: + DBUG_ASSERT(subselect->get_IN_subquery()); allany_subs= (Item_allany_subselect *)subselect; break; default: @@ -640,13 +641,15 @@ int check_and_do_in_subquery_rewrites(JOIN *join) char const *save_where= thd->where; thd->where= "IN/ALL/ANY subquery"; - bool failure= in_subs->left_expr->fix_fields_if_needed(thd, - &in_subs->left_expr); + Item **left= in_subs->left_exp_ptr(); + bool failure= (*left)->fix_fields_if_needed(thd, left); thd->lex->current_select= current; thd->where= save_where; if (failure) DBUG_RETURN(-1); /* purecov: deadcode */ + // fix_field above can rewrite left expression + uint ncols= (*left)->cols(); /* Check if the left and right expressions have the same # of columns, i.e. we don't have a case like @@ -655,9 +658,9 @@ int check_and_do_in_subquery_rewrites(JOIN *join) TODO why do we have this duplicated in IN->EXISTS transformers? psergey-todo: fix these: grep for duplicated_subselect_card_check */ - if (select_lex->item_list.elements != in_subs->left_expr->cols()) + if (select_lex->item_list.elements != ncols) { - my_error(ER_OPERAND_COLUMNS, MYF(0), in_subs->left_expr->cols()); + my_error(ER_OPERAND_COLUMNS, MYF(0), ncols); DBUG_RETURN(-1); } } @@ -847,9 +850,10 @@ int check_and_do_in_subquery_rewrites(JOIN *join) static bool subquery_types_allow_materialization(THD* thd, Item_in_subselect *in_subs) { + Item *left_exp= in_subs->left_exp(); DBUG_ENTER("subquery_types_allow_materialization"); - DBUG_ASSERT(in_subs->left_expr->is_fixed()); + DBUG_ASSERT(left_exp->is_fixed()); List_iterator<Item> it(in_subs->unit->first_select()->item_list); uint elements= in_subs->unit->first_select()->item_list.elements; @@ -871,7 +875,7 @@ bool subquery_types_allow_materialization(THD* thd, Item_in_subselect *in_subs) uint32 total_key_length = 0; for (uint i= 0; i < elements; i++) { - Item *outer= in_subs->left_expr->element_index(i); + Item *outer= left_exp->element_index(i); Item *inner= it++; all_are_fields &= (outer->real_item()->type() == Item::FIELD_ITEM && inner->real_item()->type() == Item::FIELD_ITEM); @@ -1706,7 +1710,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) sj_nest->alias= sj_nest_name; sj_nest->sj_subq_pred= subq_pred; sj_nest->original_subq_pred_used_tables= subq_pred->used_tables() | - subq_pred->left_expr->used_tables(); + subq_pred->left_exp()->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, thd->mem_root); @@ -1794,14 +1798,17 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) */ SELECT_LEX *save_lex= thd->lex->current_select; thd->lex->current_select=subq_lex; - if (subq_pred->left_expr->fix_fields_if_needed(thd, &subq_pred->left_expr)) + Item **left= subq_pred->left_exp_ptr(); + if ((*left)->fix_fields_if_needed(thd, left)) DBUG_RETURN(TRUE); + Item *left_exp= *left; + Item *left_exp_orig= subq_pred->left_exp_orig(); thd->lex->current_select=save_lex; 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(); + left_exp->used_tables(); sj_nest->sj_on_expr= subq_lex->join->conds; /* @@ -1819,14 +1826,14 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) Item_direct_view_refs doesn't substitute itself with anything in Item_direct_view_ref::fix_fields. */ - sj_nest->sj_in_exprs= subq_pred->left_expr->cols(); + uint ncols= sj_nest->sj_in_exprs= left_exp->cols(); sj_nest->nested_join->sj_outer_expr_list.empty(); reset_equality_number_for_subq_conds(sj_nest->sj_on_expr); - if (subq_pred->left_expr->cols() == 1) + if (ncols == 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(left, thd->mem_root); /* Create Item_func_eq. Note that @@ -1838,36 +1845,36 @@ 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 (thd->mem_root) Item_func_eq(thd, subq_pred->left_expr_orig, + new (thd->mem_root) Item_func_eq(thd, left_exp_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); + if (left_exp_orig != left_exp) + thd->change_item_tree(item_eq->arguments(), left_exp); item_eq->in_equality_no= 0; 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) + else if (left_exp->type() == Item::ROW_ITEM) { /* disassemple left expression and add left1 = select_list_element1 and left2 = select_list_element2 ... */ - for (uint i= 0; i < subq_pred->left_expr->cols(); i++) + for (uint i= 0; i < ncols; i++) { - nested_join->sj_outer_expr_list.push_back(subq_pred->left_expr->addr(i), + nested_join->sj_outer_expr_list.push_back(left_exp->addr(i), thd->mem_root); Item_func_eq *item_eq= new (thd->mem_root) - Item_func_eq(thd, subq_pred->left_expr_orig->element_index(i), + Item_func_eq(thd, left_exp_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)->is_fixed()); - if (subq_pred->left_expr_orig->element_index(i) != - subq_pred->left_expr->element_index(i)) + DBUG_ASSERT(left_exp->element_index(i)->is_fixed()); + if (left_exp_orig->element_index(i) != + left_exp->element_index(i)) thd->change_item_tree(item_eq->arguments(), - subq_pred->left_expr->element_index(i)); + left_exp->element_index(i)); item_eq->in_equality_no= i; sj_nest->sj_on_expr= and_items(thd, sj_nest->sj_on_expr, item_eq); } @@ -1882,10 +1889,10 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) /* fix fields on subquery was call so they should be the same */ if (!row) DBUG_RETURN(TRUE); - DBUG_ASSERT(subq_pred->left_expr->cols() == row->cols()); - nested_join->sj_outer_expr_list.push_back(&subq_pred->left_expr); + DBUG_ASSERT(ncols == row->cols()); + nested_join->sj_outer_expr_list.push_back(left); Item_func_eq *item_eq= - new (thd->mem_root) Item_func_eq(thd, subq_pred->left_expr_orig, row); + new (thd->mem_root) Item_func_eq(thd, left_exp_orig, row); if (!item_eq) DBUG_RETURN(TRUE); for (uint i= 0; i < row->cols(); i++) @@ -4140,7 +4147,8 @@ 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); + tab_ref->items[i]= + emb_sj_nest->sj_subq_pred->left_exp()->element_index(i); int null_count= MY_TEST(cur_key_part->field->real_maybe_null()); *ref_key= new store_key_item(thd, cur_key_part->field, /* TODO: @@ -4325,18 +4333,20 @@ static Item *create_subq_in_equalities(THD *thd, SJ_MATERIALIZATION_INFO *sjm, Item_in_subselect *subq_pred) { Item *res= NULL; - if (subq_pred->left_expr->cols() == 1) + Item *left_exp= subq_pred->left_exp(); + uint ncols= left_exp->cols(); + if (ncols == 1) { - if (!(res= new (thd->mem_root) Item_func_eq(thd, subq_pred->left_expr, + if (!(res= new (thd->mem_root) Item_func_eq(thd, left_exp, new (thd->mem_root) Item_field(thd, sjm->table->field[0])))) return NULL; /* purecov: inspected */ } else { Item *conj; - for (uint i= 0; i < subq_pred->left_expr->cols(); i++) + for (uint i= 0; i < ncols; i++) { - if (!(conj= new (thd->mem_root) Item_func_eq(thd, subq_pred->left_expr->element_index(i), + if (!(conj= new (thd->mem_root) Item_func_eq(thd, left_exp->element_index(i), new (thd->mem_root) Item_field(thd, sjm->table->field[i]))) || !(res= and_items(thd, res, conj))) return NULL; /* purecov: inspected */ @@ -5404,7 +5414,7 @@ int rewrite_to_index_subquery_engine(JOIN *join) change_engine(new subselect_uniquesubquery_engine(thd, join_tab, - unit->item, + unit->item->get_IN_subquery(), where))); } else if (join_tab[0].type == JT_REF && @@ -5418,7 +5428,7 @@ int rewrite_to_index_subquery_engine(JOIN *join) change_engine(new subselect_indexsubquery_engine(thd, join_tab, - unit->item, + unit->item->get_IN_subquery(), where, NULL, 0))); @@ -5434,7 +5444,7 @@ int rewrite_to_index_subquery_engine(JOIN *join) DBUG_RETURN(unit->item-> change_engine(new subselect_indexsubquery_engine(thd, join_tab, - unit->item, + unit->item->get_IN_subquery(), join->conds, join->having, 1))); @@ -6109,11 +6119,13 @@ bool execute_degenerate_jtbm_semi_join(THD *thd, subq_pred->jtbm_const_row_found= TRUE; Item *eq_cond; - for (uint i= 0; i < subq_pred->left_expr->cols(); i++) + Item *left_exp= subq_pred->left_exp(); + uint ncols= left_exp->cols(); + for (uint i= 0; i < ncols; i++) { eq_cond= new (thd->mem_root) Item_func_eq(thd, - subq_pred->left_expr->element_index(i), + left_exp->element_index(i), new_sink->row[i]); if (!eq_cond || eq_cond->fix_fields(thd, NULL) || eq_list.push_back(eq_cond, thd->mem_root)) @@ -6408,7 +6420,7 @@ bool JOIN::choose_subquery_plan(table_map join_tables) if (is_in_subquery()) { - in_subs= (Item_in_subselect*) unit->item; + in_subs= unit->item->get_IN_subquery(); if (in_subs->create_in_to_exists_cond(this)) return true; } @@ -6692,12 +6704,12 @@ bool JOIN::choose_tableless_subquery_plan() everything as-is, setup_jtbm_semi_joins() has special handling for cases like this. */ - if (subs_predicate->is_in_predicate() && - !(subs_predicate->substype() == Item_subselect::IN_SUBS && - ((Item_in_subselect*)subs_predicate)->is_jtbm_merged)) + Item_in_subselect *in_subs; + in_subs= subs_predicate->get_IN_subquery(); + if (in_subs && + !(subs_predicate->substype() == Item_subselect::IN_SUBS && + in_subs->is_jtbm_merged)) { - Item_in_subselect *in_subs; - in_subs= (Item_in_subselect*) subs_predicate; in_subs->set_strategy(SUBS_IN_TO_EXISTS); if (in_subs->create_in_to_exists_cond(this) || in_subs->inject_in_to_exists_cond(this)) @@ -6714,7 +6726,8 @@ bool Item::pushable_equality_checker_for_subquery(uchar *arg) { return get_corresponding_field_pair(this, - ((Item_in_subselect *)arg)->corresponding_fields); + ((Item *)arg)->get_IN_subquery()-> + corresponding_fields); } @@ -6853,7 +6866,7 @@ Item *get_corresponding_item(THD *thd, Item *item, Item *Item_field::in_subq_field_transformer_for_where(THD *thd, uchar *arg) { - Item_in_subselect *subq_pred= (Item_in_subselect *)arg; + Item_in_subselect *subq_pred= ((Item *)arg)->get_IN_subquery(); Item *producing_item= get_corresponding_item(thd, this, subq_pred); if (producing_item) return producing_item->build_clone(thd); @@ -6866,7 +6879,7 @@ Item *Item_direct_view_ref::in_subq_field_transformer_for_where(THD *thd, { if (item_equal) { - Item_in_subselect *subq_pred= (Item_in_subselect *)arg; + Item_in_subselect *subq_pred= ((Item *)arg)->get_IN_subquery(); Item *producing_item= get_corresponding_item(thd, this, subq_pred); DBUG_ASSERT (producing_item != NULL); return producing_item->build_clone(thd); @@ -6916,6 +6929,7 @@ get_corresponding_item_for_in_subq_having(THD *thd, Item *in_item, Item *Item_field::in_subq_field_transformer_for_having(THD *thd, uchar *arg) { + DBUG_ASSERT(((Item *)arg)->get_IN_subquery()); return get_corresponding_item_for_in_subq_having(thd, this, (Item_in_subselect *)arg); } @@ -6928,6 +6942,7 @@ Item *Item_direct_view_ref::in_subq_field_transformer_for_having(THD *thd, return this; else { + DBUG_ASSERT(((Item *)arg)->get_IN_subquery()); Item *new_item= get_corresponding_item_for_in_subq_having(thd, this, (Item_in_subselect *)arg); if (!new_item) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 6d53a8ee6e3..c85c2b6449a 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -6328,10 +6328,11 @@ find_field_in_tables(THD *thd, Item_ident *item, for (SELECT_LEX *sl= current_sel; sl && sl!=last_select; sl=sl->outer_select()) { - Item *subs= sl->master_unit()->item; - if (subs->type() == Item::SUBSELECT_ITEM && - ((Item_subselect*)subs)->substype() == Item_subselect::IN_SUBS && - ((Item_in_subselect*)subs)->test_strategy(SUBS_SEMI_JOIN)) + Item_in_subselect *in_subs= + sl->master_unit()->item->get_IN_subquery(); + if (in_subs && + in_subs->substype() == Item_subselect::IN_SUBS && + in_subs->test_strategy(SUBS_SEMI_JOIN)) { continue; } @@ -8230,7 +8231,7 @@ bool setup_on_expr(THD *thd, TABLE_LIST *table, bool is_update) */ if (embedded->sj_subq_pred) { - Item **left_expr= &embedded->sj_subq_pred->left_expr; + Item **left_expr= embedded->sj_subq_pred->left_exp_ptr(); if ((*left_expr)->fix_fields_if_needed(thd, left_expr)) return TRUE; } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index f39f88fe843..4cc93c31b38 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -4740,7 +4740,7 @@ bool st_select_lex::optimize_unflattened_subqueries(bool const_only) } if (subquery_predicate->substype() == Item_subselect::IN_SUBS) { - Item_in_subselect *in_subs= (Item_in_subselect*) subquery_predicate; + Item_in_subselect *in_subs= subquery_predicate->get_IN_subquery(); if (in_subs->is_jtbm_merged) continue; } @@ -5167,7 +5167,7 @@ void SELECT_LEX::update_used_tables() */ if (tl->jtbm_subselect) { - Item *left_expr= tl->jtbm_subselect->left_expr; + Item *left_expr= tl->jtbm_subselect->left_exp(); left_expr->walk(&Item::update_table_bitmaps_processor, FALSE, NULL); } @@ -5324,7 +5324,7 @@ void st_select_lex::set_explain_type(bool on_the_fly) if ((parent_item= master_unit()->item) && parent_item->substype() == Item_subselect::IN_SUBS) { - Item_in_subselect *in_subs= (Item_in_subselect*)parent_item; + Item_in_subselect *in_subs= parent_item->get_IN_subquery(); /* Surprisingly, in_subs->is_set_strategy() can return FALSE here, even for the last invocation of this function for the select. @@ -5613,9 +5613,10 @@ bool st_select_lex::is_merged_child_of(st_select_lex *ancestor) sl=sl->outer_select()) { Item *subs= sl->master_unit()->item; - if (subs && subs->type() == Item::SUBSELECT_ITEM && + Item_in_subselect *in_subs= (subs ? subs->get_IN_subquery() : NULL); + if (in_subs && ((Item_subselect*)subs)->substype() == Item_subselect::IN_SUBS && - ((Item_in_subselect*)subs)->test_strategy(SUBS_SEMI_JOIN)) + in_subs->test_strategy(SUBS_SEMI_JOIN)) { continue; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index fc9fea42a99..36bf0dd5840 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1425,7 +1425,7 @@ JOIN::prepare(TABLE_LIST *tables_init, COND *conds_init, uint og_num, if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY && !group_list && !(select_lex->master_unit()->item && select_lex->master_unit()->item->is_in_predicate() && - ((Item_in_subselect*)select_lex->master_unit()->item)-> + select_lex->master_unit()->item->get_IN_subquery()-> test_set_strategy(SUBS_MAXMIN_INJECTED)) && select_lex->non_agg_field_used() && select_lex->agg_func_used()) @@ -5046,7 +5046,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list, */ bool skip_unprefixed_keyparts= !(join->is_in_subquery() && - ((Item_in_subselect*)join->unit->item)->test_strategy(SUBS_IN_TO_EXISTS)); + join->unit->item->get_IN_subquery()->test_strategy(SUBS_IN_TO_EXISTS)); if (keyuse_array->elements && sort_and_filter_keyuse(thd, keyuse_array, @@ -5799,7 +5799,8 @@ static uint get_semi_join_select_list_index(Field *field) { Item_in_subselect *subq_pred= emb_sj_nest->sj_subq_pred; st_select_lex *subq_lex= subq_pred->unit->first_select(); - if (subq_pred->left_expr->cols() == 1) + uint ncols= subq_pred->left_exp()->cols(); + if (ncols == 1) { Item *sel_item= subq_lex->ref_pointer_array[0]; if (sel_item->type() == Item::FIELD_ITEM && @@ -5810,7 +5811,7 @@ static uint get_semi_join_select_list_index(Field *field) } else { - for (uint i= 0; i < subq_pred->left_expr->cols(); i++) + for (uint i= 0; i < ncols; i++) { Item *sel_item= subq_lex->ref_pointer_array[i]; if (sel_item->type() == Item::FIELD_ITEM && @@ -21290,7 +21291,7 @@ int join_read_key2(THD *thd, JOIN_TAB *tab, TABLE *table, TABLE_REF *table_ref) if (tab && tab->bush_children) { TABLE_LIST *emb_sj_nest= tab->bush_children->start->emb_sj_nest; - emb_sj_nest->sj_subq_pred->left_expr->bring_value(); + emb_sj_nest->sj_subq_pred->left_exp()->bring_value(); } /* TODO: Why don't we do "Late NULLs Filtering" here? */ |