diff options
Diffstat (limited to 'sql/item_subselect.cc')
-rw-r--r-- | sql/item_subselect.cc | 344 |
1 files changed, 237 insertions, 107 deletions
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 2e4c70ecd5f..29c52e73159 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -53,7 +53,7 @@ void Item_subselect::init(st_select_lex *select_lex, { DBUG_ENTER("Item_subselect::init"); - DBUG_PRINT("subs", ("select_lex 0x%xl", (ulong) select_lex)); + DBUG_PRINT("enter", ("select_lex: 0x%x", (ulong) select_lex)); unit= select_lex->master_unit(); if (unit->item) @@ -66,7 +66,7 @@ void Item_subselect::init(st_select_lex *select_lex, parsing_place= unit->item->parsing_place; unit->item->engine= 0; unit->item= this; - engine->change_item(this, result); + engine->change_result(this, result); } else { @@ -132,18 +132,18 @@ Item_subselect::select_transformer(JOIN *join) bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref) { + char const *save_where= thd_param->where; + bool res; + DBUG_ASSERT(fixed == 0); engine->set_thd((thd= thd_param)); - char const *save_where= thd->where; - int res; - if (check_stack_overrun(thd, (gptr)&res)) - return 1; + return TRUE; res= engine->prepare(); - // all transformetion is done (used by prepared statements) + // all transformation is done (used by prepared statements) changed= 1; if (!res) @@ -173,7 +173,7 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref) if (engine->cols() > max_columns) { my_error(ER_OPERAND_COLUMNS, MYF(0), 1); - return 1; + return TRUE; } fix_length_and_dec(); } @@ -246,7 +246,7 @@ void Item_subselect::update_used_tables() { if (!engine->uncacheable()) { - // did all used tables become ststic? + // did all used tables become static? if (!(used_tables_cache & ~engine->upper_select_const_tables())) const_item_cache= 1; } @@ -271,7 +271,8 @@ Item_singlerow_subselect::Item_singlerow_subselect(st_select_lex *select_lex) DBUG_VOID_RETURN; } -Item_maxmin_subselect::Item_maxmin_subselect(Item_subselect *parent, +Item_maxmin_subselect::Item_maxmin_subselect(THD *thd_param, + Item_subselect *parent, st_select_lex *select_lex, bool max_arg) :Item_singlerow_subselect(), was_values(TRUE) @@ -290,6 +291,12 @@ Item_maxmin_subselect::Item_maxmin_subselect(Item_subselect *parent, used_tables_cache= parent->get_used_tables_cache(); const_item_cache= parent->get_const_item_cache(); + /* + this subquery always creates during preparation, so we can assign + thd here + */ + thd= thd_param; + DBUG_VOID_RETURN; } @@ -333,10 +340,8 @@ Item_singlerow_subselect::select_transformer(JOIN *join) return RES_OK; SELECT_LEX *select_lex= join->select_lex; - - /* Juggle with current arena only if we're in prepared statement prepare */ - Item_arena *arena= join->thd->current_arena; - + Item_arena *arena= thd->current_arena; + if (!select_lex->master_unit()->first_select()->next_select() && !select_lex->table_list.elements && select_lex->item_list.elements == 1 && @@ -351,7 +356,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join) !(select_lex->item_list.head()->type() == FIELD_ITEM || select_lex->item_list.head()->type() == REF_ITEM) && /* - switch off this optimisation for prepare statement, + switch off this optimization for prepare statement, because we do not rollback this changes TODO: make rollback for it, or special name resolving mode in 5.0. */ @@ -360,11 +365,11 @@ Item_singlerow_subselect::select_transformer(JOIN *join) { have_to_be_excluded= 1; - if (join->thd->lex->describe) + if (thd->lex->describe) { char warn_buff[MYSQL_ERRMSG_SIZE]; sprintf(warn_buff, ER(ER_SELECT_REDUCED), select_lex->select_number); - push_warning(join->thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_SELECT_REDUCED, warn_buff); } substitution= select_lex->item_list.head(); @@ -384,6 +389,7 @@ err: return RES_ERROR; } + void Item_singlerow_subselect::store(uint i, Item *item) { row[i]->store(item); @@ -446,13 +452,13 @@ void Item_singlerow_subselect::bring_value() exec(); } -double Item_singlerow_subselect::val() +double Item_singlerow_subselect::val_real() { DBUG_ASSERT(fixed == 1); if (!exec() && !value->null_value) { null_value= 0; - return value->val(); + return value->val_real(); } else { @@ -476,7 +482,7 @@ longlong Item_singlerow_subselect::val_int() } } -String *Item_singlerow_subselect::val_str (String *str) +String *Item_singlerow_subselect::val_str(String *str) { if (!exec() && !value->null_value) { @@ -491,10 +497,41 @@ String *Item_singlerow_subselect::val_str (String *str) } +my_decimal *Item_singlerow_subselect::val_decimal(my_decimal *decimal_value) +{ + if (!exec() && !value->null_value) + { + null_value= 0; + return value->val_decimal(decimal_value); + } + else + { + reset(); + return 0; + } +} + + +bool Item_singlerow_subselect::val_bool() +{ + if (!exec() && !value->null_value) + { + null_value= 0; + return value->val_bool(); + } + else + { + reset(); + return 0; + } +} + + Item_exists_subselect::Item_exists_subselect(st_select_lex *select_lex): Item_subselect() { DBUG_ENTER("Item_exists_subselect::Item_exists_subselect"); + bool val_bool(); init(select_lex, new select_exists_subselect(this)); max_columns= UINT_MAX; null_value= 0; //can't be NULL @@ -570,7 +607,7 @@ void Item_exists_subselect::fix_length_and_dec() max_columns= engine->cols(); } -double Item_exists_subselect::val() +double Item_exists_subselect::val_real() { DBUG_ASSERT(fixed == 1); if (exec()) @@ -600,12 +637,37 @@ String *Item_exists_subselect::val_str(String *str) reset(); return 0; } - str->set(value,&my_charset_bin); + str->set((ulonglong)value,&my_charset_bin); return str; } -double Item_in_subselect::val() +my_decimal *Item_exists_subselect::val_decimal(my_decimal *decimal_value) +{ + DBUG_ASSERT(fixed == 1); + if (exec()) + { + reset(); + return 0; + } + int2my_decimal(E_DEC_FATAL_ERROR, value, 0, decimal_value); + return decimal_value; +} + + +bool Item_exists_subselect::val_bool() +{ + DBUG_ASSERT(fixed == 1); + if (exec()) + { + reset(); + return 0; + } + return value != 0; +} + + +double Item_in_subselect::val_real() { /* As far as Item_in_subselect called only from Item_in_optimizer this @@ -627,6 +689,11 @@ double Item_in_subselect::val() longlong Item_in_subselect::val_int() { + /* + As far as Item_in_subselect called only from Item_in_optimizer this + method should not be used + */ + DBUG_ASSERT(0); DBUG_ASSERT(fixed == 1); if (exec()) { @@ -659,17 +726,53 @@ String *Item_in_subselect::val_str(String *str) null_value= 1; return 0; } - str->set(value, &my_charset_bin); + str->set((ulonglong)value, &my_charset_bin); return str; } +bool Item_in_subselect::val_bool() +{ + DBUG_ASSERT(fixed == 1); + if (exec()) + { + reset(); + null_value= 1; + return 0; + } + if (was_null && !value) + null_value= 1; + return value; +} + +my_decimal *Item_in_subselect::val_decimal(my_decimal *decimal_value) +{ + /* + As far as Item_in_subselect called only from Item_in_optimizer this + method should not be used + */ + DBUG_ASSERT(0); + DBUG_ASSERT(fixed == 1); + if (exec()) + { + reset(); + null_value= 1; + return 0; + } + if (was_null && !value) + null_value= 1; + int2my_decimal(E_DEC_FATAL_ERROR, value, 0, decimal_value); + return decimal_value; +} + + /* Rewrite a single-column IN/ALL/ANY subselect. */ Item_subselect::trans_res Item_in_subselect::single_value_transformer(JOIN *join, Comp_creator *func) { + Item_subselect::trans_res result= RES_ERROR; DBUG_ENTER("Item_in_subselect::single_value_transformer"); SELECT_LEX *select_lex= join->select_lex; @@ -738,7 +841,8 @@ Item_in_subselect::single_value_transformer(JOIN *join, /* Item_sum_(max|min) can't substitute other item => we can use 0 as - reference + reference, also Item_sum_(max|min) can't be fixed after creation, so + we do not check item->fixed */ if (item->fix_fields(thd, join->tables_list, 0)) DBUG_RETURN(RES_ERROR); @@ -753,7 +857,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, // remove LIMIT placed by ALL/ANY subquery select_lex->master_unit()->global_parameters->select_limit= HA_POS_ERROR; - subs= item= new Item_maxmin_subselect(this, select_lex, func->l_op()); + subs= item= new Item_maxmin_subselect(thd, this, select_lex, func->l_op()); if (upper_item) upper_item->set_sub_test(item); } @@ -780,7 +884,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, thd->lex->current_select= current; /* - As far as Item_ref_in_optimizer do not substitude itself on fix_fields + As far as Item_ref_in_optimizer do not substitute itself on fix_fields we can use same item for all selects. */ expr= new Item_direct_ref((Item**)optimizer->get_cache(), @@ -791,9 +895,6 @@ Item_in_subselect::single_value_transformer(JOIN *join, } select_lex->uncacheable|= UNCACHEABLE_DEPENDENT; - Item *item; - - item= (Item*) select_lex->item_list.head(); /* Add the left part of a subselect to a WHERE or HAVING clause of the right part, e.g. SELECT 1 IN (SELECT a FROM t1) => @@ -804,11 +905,17 @@ Item_in_subselect::single_value_transformer(JOIN *join, if (join->having || select_lex->with_sum_func || select_lex->group_list.elements) { - item= func->create(expr, - new Item_ref_null_helper(this, - select_lex->ref_pointer_array, - (char *)"<ref>", - this->full_name())); + bool tmp; + Item *item= func->create(expr, + new Item_ref_null_helper(this, + select_lex-> + ref_pointer_array, + (char *)"<ref>", + this->full_name())); +#ifdef CORRECT_BUT_TOO_SLOW_TO_BE_USABLE + if (!abort_on_null && left_expr->maybe_null) + item= new Item_cond_or(new Item_func_isnull(left_expr), item); +#endif /* AND and comparison functions can't be changed during fix_fields() we can assign select_lex->having here, and pass 0 as last @@ -816,21 +923,26 @@ Item_in_subselect::single_value_transformer(JOIN *join, */ select_lex->having= join->having= and_items(join->having, item); select_lex->having_fix_field= 1; - if (join->having->fix_fields(thd, join->tables_list, 0)) - { - select_lex->having_fix_field= 0; - DBUG_RETURN(RES_ERROR); - } + /* + we do not check join->having->fixed, because Item_and (from and_items) + or comparison function (from func->create) can't be fixed after creation + */ + tmp= join->having->fix_fields(thd, join->tables_list, 0); select_lex->having_fix_field= 0; + if (tmp) + DBUG_RETURN(RES_ERROR); } else { + Item *item= (Item*) select_lex->item_list.head(); + select_lex->item_list.empty(); select_lex->item_list.push_back(new Item_int("Not_used", (longlong) 1, 21)); select_lex->ref_pointer_array[0]= select_lex->item_list.head(); if (select_lex->table_list.elements) { + bool tmp; Item *having= item, *orig_item= item; item= func->create(expr, item); if (!abort_on_null && orig_item->maybe_null) @@ -846,14 +958,21 @@ Item_in_subselect::single_value_transformer(JOIN *join, new Item_cond_and(having, join->having) : having); select_lex->having_fix_field= 1; - if (join->having->fix_fields(thd, join->tables_list, 0)) - { - select_lex->having_fix_field= 0; + /* + we do not check join->having->fixed, because Item_and (from + and_items) or comparison function (from func->create) can't be + fixed after creation + */ + tmp= join->having->fix_fields(thd, join->tables_list, 0); + select_lex->having_fix_field= 0; + if (tmp) DBUG_RETURN(RES_ERROR); - } - select_lex->having_fix_field= 0; item= new Item_cond_or(item, new Item_func_isnull(orig_item)); +#ifdef CORRECT_BUT_TOO_SLOW_TO_BE_USABLE + if (left_expr->maybe_null) + item= new Item_cond_or(new Item_func_isnull(left_expr), item); +#endif } item->name= (char *)in_additional_cond; /* @@ -862,11 +981,16 @@ Item_in_subselect::single_value_transformer(JOIN *join, argument (reference) to fix_fields() */ select_lex->where= join->conds= and_items(join->conds, item); + /* + we do not check join->conds->fixed, because Item_and can't be fixed + after creation + */ if (join->conds->fix_fields(thd, join->tables_list, 0)) DBUG_RETURN(RES_ERROR); } else { + bool tmp; if (select_lex->master_unit()->first_select()->next_select()) { /* @@ -874,26 +998,30 @@ Item_in_subselect::single_value_transformer(JOIN *join, we can assign select_lex->having here, and pass 0 as last argument (reference) to fix_fields() */ - select_lex->having= - join->having= - func->create(expr, + item= func->create(expr, new Item_null_helper(this, item, (char *)"<no matter>", (char *)"<result>")); +#ifdef CORRECT_BUT_TOO_SLOW_TO_BE_USABLE + if (!abort_on_null && left_expr->maybe_null) + item= new Item_cond_or(new Item_func_isnull(left_expr), item); +#endif + select_lex->having= join->having= item; select_lex->having_fix_field= 1; - if (join->having->fix_fields(thd, join->tables_list, - 0)) - { - select_lex->having_fix_field= 0; + /* + we do not check join->having->fixed, because comparison function + (from func->create) can't be fixed after creation + */ + tmp= join->having->fix_fields(thd, join->tables_list, 0); + select_lex->having_fix_field= 0; + if (tmp) DBUG_RETURN(RES_ERROR); - } - select_lex->having_fix_field= 0; } else { // it is single select without tables => possible optimization item= func->create(left_expr, item); - // fix_field of item will be done in time of substituting + // fix_field of item will be done in time of substituting substitution= item; have_to_be_excluded= 1; if (thd->lex->describe) @@ -915,10 +1043,9 @@ Item_in_subselect::single_value_transformer(JOIN *join, Item_subselect::trans_res Item_in_subselect::row_value_transformer(JOIN *join) { - DBUG_ENTER("Item_in_subselect::row_value_transformer"); - Item *item= 0; SELECT_LEX *select_lex= join->select_lex; + DBUG_ENTER("Item_in_subselect::row_value_transformer"); if (select_lex->item_list.elements != left_expr->cols()) { @@ -941,7 +1068,7 @@ Item_in_subselect::row_value_transformer(JOIN *join) DBUG_RETURN(RES_ERROR); } - // we will refer to apper level cache array => we have to save it in PS + // we will refer to upper level cache array => we have to save it in PS optimizer->keep_top_level_cache(); thd->lex->current_select= current; @@ -959,9 +1086,9 @@ Item_in_subselect::row_value_transformer(JOIN *join) check_cols(left_expr->el(i)->cols())) DBUG_RETURN(RES_ERROR); Item *func= new Item_ref_null_helper(this, - select_lex->ref_pointer_array+i, - (char *) "<no matter>", - (char *) "<list ref>"); + select_lex->ref_pointer_array+i, + (char *) "<no matter>", + (char *) "<list ref>"); func= eq_creator.create(new Item_direct_ref((*optimizer->get_cache())-> addr(i), @@ -982,6 +1109,10 @@ Item_in_subselect::row_value_transformer(JOIN *join) */ select_lex->having= join->having= and_items(join->having, item); select_lex->having_fix_field= 1; + /* + join->having can't be fixed after creation, so we do not check + join->having->fixed + */ if (join->having->fix_fields(thd, join->tables_list, 0)) { select_lex->having_fix_field= 0; @@ -997,9 +1128,14 @@ Item_in_subselect::row_value_transformer(JOIN *join) argument (reference) to fix_fields() */ select_lex->where= join->conds= and_items(join->conds, item); + /* + join->conds can't be fixed after creation, so we do not check + join->conds->fixed + */ if (join->conds->fix_fields(thd, join->tables_list, 0)) DBUG_RETURN(RES_ERROR); } + DBUG_RETURN(RES_OK); } @@ -1154,13 +1290,7 @@ subselect_single_select_engine(st_select_lex *select, { select_lex= select; SELECT_LEX_UNIT *unit= select_lex->master_unit(); - unit->offset_limit_cnt= unit->global_parameters->offset_limit; - unit->select_limit_cnt= unit->global_parameters->select_limit+ - unit->global_parameters ->offset_limit; - if (unit->select_limit_cnt < unit->global_parameters->select_limit) - unit->select_limit_cnt= HA_POS_ERROR; // no limit - if (unit->select_limit_cnt == HA_POS_ERROR) - select_lex->options&= ~OPTION_FOUND_ROWS; + unit->set_limit(unit->global_parameters, select_lex); unit->item= item; this->select_lex= select_lex; } @@ -1305,17 +1435,17 @@ void subselect_uniquesubquery_engine::fix_length_and_dec(Item_cache **row) int subselect_single_select_engine::exec() { DBUG_ENTER("subselect_single_select_engine::exec"); - char const *save_where= join->thd->where; - SELECT_LEX *save_select= join->thd->lex->current_select; - join->thd->lex->current_select= select_lex; + char const *save_where= thd->where; + SELECT_LEX *save_select= thd->lex->current_select; + thd->lex->current_select= select_lex; if (!optimized) { optimized=1; if (join->optimize()) { - join->thd->where= save_where; + thd->where= save_where; executed= 1; - join->thd->lex->current_select= save_select; + thd->lex->current_select= save_select; DBUG_RETURN(join->error ? join->error : 1); } if (item->engine_changed) @@ -1327,8 +1457,8 @@ int subselect_single_select_engine::exec() { if (join->reinit()) { - join->thd->where= save_where; - join->thd->lex->current_select= save_select; + thd->where= save_where; + thd->lex->current_select= save_select; DBUG_RETURN(1); } item->reset(); @@ -1339,20 +1469,20 @@ int subselect_single_select_engine::exec() item->reset_value_registration(); join->exec(); executed= 1; - join->thd->where= save_where; - join->thd->lex->current_select= save_select; + thd->where= save_where; + thd->lex->current_select= save_select; DBUG_RETURN(join->error||thd->is_fatal_error); } - join->thd->where= save_where; - join->thd->lex->current_select= save_select; + thd->where= save_where; + thd->lex->current_select= save_select; DBUG_RETURN(0); } int subselect_union_engine::exec() { - char const *save_where= unit->thd->where; + char const *save_where= thd->where; int res= unit->exec(); - unit->thd->where= save_where; + thd->where= save_where; return res; } @@ -1475,7 +1605,7 @@ int subselect_indexsubquery_engine::exec() uint subselect_single_select_engine::cols() { - DBUG_ASSERT(select_lex->join); // should be called after fix_fields() + DBUG_ASSERT(select_lex->join != 0); // should be called after fix_fields() return select_lex->join->fields_list.elements; } @@ -1520,7 +1650,7 @@ void subselect_uniquesubquery_engine::exclude() table_map subselect_engine::calc_const_tables(TABLE_LIST *table) { table_map map= 0; - for (; table; table= table->next) + for(; table; table= table->next_leaf) { TABLE *tbl= table->table; if (tbl && tbl->const_table) @@ -1533,14 +1663,13 @@ table_map subselect_engine::calc_const_tables(TABLE_LIST *table) table_map subselect_single_select_engine::upper_select_const_tables() { return calc_const_tables((TABLE_LIST *) select_lex->outer_select()-> - table_list.first); + leaf_tables); } table_map subselect_union_engine::upper_select_const_tables() { - return calc_const_tables((TABLE_LIST *) unit->outer_select()-> - table_list.first); + return calc_const_tables((TABLE_LIST *) unit->outer_select()->leaf_tables); } @@ -1561,7 +1690,7 @@ void subselect_uniquesubquery_engine::print(String *str) str->append("<primary_index_lookup>(", 23); tab->ref.items[0]->print(str); str->append(" in ", 4); - str->append(tab->table->real_name); + str->append(tab->table->s->table_name); KEY *key_info= tab->table->key_info+ tab->ref.key; str->append(" on ", 4); str->append(key_info->name); @@ -1579,12 +1708,12 @@ void subselect_indexsubquery_engine::print(String *str) str->append("<index_lookup>(", 15); tab->ref.items[0]->print(str); str->append(" in ", 4); - str->append(tab->table->real_name); + str->append(tab->table->s->table_name); KEY *key_info= tab->table->key_info+ tab->ref.key; str->append(" on ", 4); str->append(key_info->name); if (check_null) - str->append(" chicking NULL", 14); + str->append(" checking NULL", 14); if (cond) { str->append(" where ", 7); @@ -1596,18 +1725,18 @@ void subselect_indexsubquery_engine::print(String *str) /* change select_result object of engine - SINOPSYS + SYNOPSIS subselect_single_select_engine::change_result() si new subselect Item res new select_result object RETURN - 0 OK - -1 error + FALSE OK + TRUE error */ -int subselect_single_select_engine::change_item(Item_subselect *si, - select_subselect *res) +bool subselect_single_select_engine::change_result(Item_subselect *si, + select_subselect *res) { item= si; result= res; @@ -1618,18 +1747,18 @@ int subselect_single_select_engine::change_item(Item_subselect *si, /* change select_result object of engine - SINOPSYS + SYNOPSIS subselect_single_select_engine::change_result() si new subselect Item res new select_result object RETURN - 0 OK - -1 error + FALSE OK + TRUE error */ -int subselect_union_engine::change_item(Item_subselect *si, - select_subselect *res) +bool subselect_union_engine::change_result(Item_subselect *si, + select_subselect *res) { item= si; int rc= unit->change_result(res, result); @@ -1641,27 +1770,28 @@ int subselect_union_engine::change_item(Item_subselect *si, /* change select_result emulation, never should be called - SINOPSYS + SYNOPSIS subselect_single_select_engine::change_result() si new subselect Item res new select_result object RETURN - -1 error + FALSE OK + TRUE error */ -int subselect_uniquesubquery_engine::change_item(Item_subselect *si, - select_subselect *res) +bool subselect_uniquesubquery_engine::change_result(Item_subselect *si, + select_subselect *res) { DBUG_ASSERT(0); - return -1; + return TRUE; } /* Report about presence of tables in subquery - SINOPSYS + SYNOPSIS subselect_single_select_engine::no_tables() RETURN @@ -1677,7 +1807,7 @@ bool subselect_single_select_engine::no_tables() /* Report about presence of tables in subquery - SINOPSYS + SYNOPSIS subselect_union_engine::no_tables() RETURN @@ -1698,7 +1828,7 @@ bool subselect_union_engine::no_tables() /* Report about presence of tables in subquery - SINOPSYS + SYNOPSIS subselect_uniquesubquery_engine::no_tables() RETURN |