diff options
Diffstat (limited to 'sql/sql_select.cc')
-rw-r--r-- | sql/sql_select.cc | 756 |
1 files changed, 382 insertions, 374 deletions
diff --git a/sql/sql_select.cc b/sql/sql_select.cc index ddc5a25bd07..04baf5737c6 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -354,7 +354,7 @@ bool handle_select(THD *thd, LEX *lex, select_result *result, ulong setup_tables_done_option) { bool res; - SELECT_LEX *select_lex = &lex->select_lex; + SELECT_LEX *select_lex= lex->first_select_lex(); DBUG_ENTER("handle_select"); MYSQL_SELECT_START(thd->query()); @@ -1051,7 +1051,7 @@ JOIN::prepare(TABLE_LIST *tables_init, while ((select_el= select_it++)) { - if (select_el->with_sum_func) + if (select_el->with_sum_func()) found_sum_func_elem= true; if (select_el->with_field) found_field_elem= true; @@ -1219,14 +1219,14 @@ JOIN::prepare(TABLE_LIST *tables_init, item->max_length))) real_order= TRUE; - if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM) + if (item->with_sum_func() && item->type() != Item::SUM_FUNC_ITEM) item->split_sum_func(thd, ref_ptrs, all_fields, 0); } if (!real_order) order= NULL; } - if (having && having->with_sum_func) + if (having && having->with_sum_func()) having->split_sum_func2(thd, ref_ptrs, all_fields, &having, SPLIT_SUM_SKIP_REGISTERED); if (select_lex->inner_sum_func_list) @@ -1396,6 +1396,7 @@ err: bool JOIN::build_explain() { + DBUG_ENTER("JOIN::build_explain"); create_explain_query_if_not_exists(thd->lex, thd->mem_root); have_query_plan= QEP_AVAILABLE; @@ -1413,8 +1414,7 @@ bool JOIN::build_explain() thd->mem_root= old_mem_root; DBUG_ASSERT(thd->free_list == old_free_list); // no Items were created if (res) - return 1; - + DBUG_RETURN(1); uint select_nr= select_lex->select_number; JOIN_TAB *curr_tab= join_tab + exec_join_tab_cnt(); for (uint i= 0; i < aggr_tables; i++, curr_tab++) @@ -1432,7 +1432,7 @@ bool JOIN::build_explain() get_using_temporary_read_tracker(); } } - return 0; + DBUG_RETURN(0); } @@ -1597,7 +1597,7 @@ JOIN::optimize_inner() { /* Item_cond_and can't be fixed after creation, so we do not check - conds->fixed + conds->is_fixed() */ conds->fix_fields(thd, &conds); conds->change_ref_to_fields(thd, tables_list); @@ -1641,7 +1641,7 @@ JOIN::optimize_inner() if (arena) thd->restore_active_arena(arena, &backup); } - + if (optimize_constant_subqueries()) DBUG_RETURN(1); @@ -1652,9 +1652,28 @@ JOIN::optimize_inner() (void) having->walk(&Item::cleanup_is_expensive_cache_processor, 0, (void *) 0); - if (setup_jtbm_semi_joins(this, join_list, &conds)) + List<Item> eq_list; + + if (setup_degenerate_jtbm_semi_joins(this, join_list, eq_list)) DBUG_RETURN(1); + if (eq_list.elements != 0) + { + Item *new_cond; + + if (eq_list.elements == 1) + new_cond= eq_list.pop(); + else + new_cond= new (thd->mem_root) Item_cond_and(thd, eq_list); + + if (new_cond && + ((new_cond->fix_fields(thd, &new_cond) || + !(conds= and_items(thd, conds, new_cond)) || + conds->fix_fields(thd, &conds)))) + DBUG_RETURN(TRUE); + } + eq_list.empty(); + if (select_lex->cond_pushed_into_where) { conds= and_conds(thd, conds, select_lex->cond_pushed_into_where); @@ -1685,6 +1704,31 @@ JOIN::optimize_inner() DBUG_RETURN(1); } + if (optimizer_flag(thd, OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_SUBQUERY)) + { + TABLE_LIST *tbl; + List_iterator_fast<TABLE_LIST> li(select_lex->leaf_tables); + while ((tbl= li++)) + if (tbl->jtbm_subselect) + { + if (tbl->jtbm_subselect->pushdown_cond_for_in_subquery(thd, conds)) + DBUG_RETURN(1); + } + } + + if (setup_jtbm_semi_joins(this, join_list, eq_list)) + DBUG_RETURN(1); + + if (eq_list.elements != 0) + { + conds= and_new_conditions_to_optimized_cond(thd, conds, &cond_equal, + eq_list, &cond_value); + + if (!conds && + cond_value != Item::COND_FALSE && cond_value != Item::COND_TRUE) + DBUG_RETURN(TRUE); + } + if (optimizer_flag(thd, OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED)) { TABLE_LIST *tbl; @@ -1991,7 +2035,7 @@ int JOIN::optimize_stage2() if (!conds && outer_join) { /* Handle the case where we have an OUTER JOIN without a WHERE */ - conds= new (thd->mem_root) Item_int(thd, (longlong) 1,1); // Always true + conds= new (thd->mem_root) Item_bool(thd, true); // Always true } if (impossible_where) @@ -2130,7 +2174,7 @@ int JOIN::optimize_stage2() if (conds && const_table_map != found_const_table_map && (select_options & SELECT_DESCRIBE)) { - conds=new (thd->mem_root) Item_int(thd, (longlong) 0, 1); // Always false + conds=new (thd->mem_root) Item_bool(thd, false); // Always false } /* Cache constant expressions in WHERE, HAVING, ON clauses. */ @@ -2413,13 +2457,13 @@ int JOIN::optimize_stage2() elements may be lost during further having condition transformation in JOIN::exec. */ - if (having && const_table_map && !having->with_sum_func) + if (having && const_table_map && !having->with_sum_func()) { having->update_used_tables(); having= having->remove_eq_conds(thd, &select_lex->having_value, true); if (select_lex->having_value == Item::COND_FALSE) { - having= new (thd->mem_root) Item_int(thd, (longlong) 0,1); + having= new (thd->mem_root) Item_bool(thd, false); zero_result_cause= "Impossible HAVING noticed after reading const tables"; error= 0; select_lex->mark_const_derived(zero_result_cause); @@ -2457,7 +2501,7 @@ int JOIN::optimize_stage2() { JOIN_TAB *tab= &join_tab[const_tables]; - if (order) + if (order && !need_tmp) { /* Force using of tmp table if sorting by a SP or UDF function due to @@ -3162,7 +3206,7 @@ bool JOIN::make_aggr_tables_info() or end_write_group()) if JOIN::group is set to false. */ // the temporary table was explicitly requested - DBUG_ASSERT(MY_TEST(select_options & OPTION_BUFFER_RESULT)); + DBUG_ASSERT(select_options & OPTION_BUFFER_RESULT); // the temporary table does not have a grouping expression DBUG_ASSERT(!curr_tab->table->group); } @@ -3765,6 +3809,15 @@ bool JOIN::save_explain_data(Explain_query *output, bool can_overwrite, bool need_tmp_table, bool need_order, bool distinct) { + DBUG_ENTER("JOIN::save_explain_data"); + DBUG_PRINT("enter", ("Save explain Select_lex: %u (%p) parent lex: %p stmt_lex: %p present select: %u (%p)", + select_lex->select_number, select_lex, + select_lex->parent_lex, thd->lex->stmt_lex, + (output->get_select(select_lex->select_number) ? + select_lex->select_number : 0), + (output->get_select(select_lex->select_number) ? + output->get_select(select_lex->select_number) + ->select_lex : NULL))); /* If there is SELECT in this statement with the same number it must be the same SELECT @@ -3791,8 +3844,9 @@ bool JOIN::save_explain_data(Explain_query *output, bool can_overwrite, /* It's a degenerate join */ message= zero_result_cause ? zero_result_cause : "No tables used"; } - return save_explain_data_intern(thd->lex->explain, need_tmp_table, need_order, - distinct, message); + bool rc= save_explain_data_intern(thd->lex->explain, need_tmp_table, + need_order, distinct, message); + DBUG_RETURN(rc); } /* @@ -3814,11 +3868,11 @@ bool JOIN::save_explain_data(Explain_query *output, bool can_overwrite, { if (!(join_tab[i].filesort->tracker= new Filesort_tracker(thd->lex->analyze_stmt))) - return 1; + DBUG_RETURN(1); } } } - return 0; + DBUG_RETURN(0); } @@ -4175,10 +4229,10 @@ mysql_select(THD *thd, is it single SELECT in derived table, called in derived table creation */ - if (select_lex->linkage != DERIVED_TABLE_TYPE || + if (select_lex->get_linkage() != DERIVED_TABLE_TYPE || (select_options & SELECT_DESCRIBE)) { - if (select_lex->linkage != GLOBAL_OPTIONS_TYPE) + if (select_lex->get_linkage() != GLOBAL_OPTIONS_TYPE) { /* Original join tabs might be overwritten at first @@ -4870,7 +4924,7 @@ make_join_statistics(JOIN *join, List<TABLE_LIST> &tables_list, if (join->cond_value == Item::COND_FALSE) { join->impossible_where= true; - conds= new (join->thd->mem_root) Item_int(join->thd, (longlong) 0, 1); + conds= new (join->thd->mem_root) Item_bool(join->thd, false); } join->cond_equal= NULL; @@ -10632,7 +10686,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) below to check if we should use 'quick' instead. */ DBUG_PRINT("info", ("Item_int")); - tmp= new (thd->mem_root) Item_int(thd, (longlong) 1, 1); // Always true + tmp= new (thd->mem_root) Item_bool(thd, true); // Always true } } @@ -10760,7 +10814,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) Yet attributes of the just built condition are not needed. Thus we call sel->cond->quick_fix_field for safety. */ - if (sel->cond && !sel->cond->fixed) + if (sel->cond && !sel->cond->is_fixed()) sel->cond->quick_fix_field(); if (sel->test_quick_select(thd, tab->keys, @@ -12769,7 +12823,8 @@ void JOIN::join_free() !(select_options & SELECT_NO_UNLOCK) && !select_lex->subquery_in_having && (select_lex == (thd->lex->unit.fake_select_lex ? - thd->lex->unit.fake_select_lex : &thd->lex->select_lex))) + thd->lex->unit.fake_select_lex : + thd->lex->first_select_lex()))) { /* TODO: unlock tables even if the join isn't top level select in the @@ -13061,7 +13116,7 @@ static void update_depend_map_for_order(JOIN *join, ORDER *order) order->used= 0; // Not item_sum(), RAND() and no reference to table outside of sub select if (!(order->depend_map & (OUTER_REF_TABLE_BIT | RAND_TABLE_BIT)) - && !order->item[0]->with_sum_func && + && !order->item[0]->with_sum_func() && join->join_tab) { for (JOIN_TAB **tab=join->map2table; @@ -13136,7 +13191,23 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond, tab++) tab->cached_eq_ref_table= FALSE; - *simple_order= *join->join_tab[join->const_tables].on_expr_ref ? 0 : 1; + JOIN_TAB *head= join->join_tab + join->const_tables; + *simple_order= head->on_expr_ref[0] == NULL; + if (*simple_order && head->table->file->ha_table_flags() & HA_SLOW_RND_POS) + { + uint u1, u2, u3; + /* + normally the condition is (see filesort_use_addons()) + + length + sortlength <= max_length_for_sort_data + + but for HA_SLOW_RND_POS tables we relax it a bit, as the alternative + is to use a temporary table, which is rather expensive. + + TODO proper cost estimations + */ + *simple_order= filesort_use_addons(head->table, 0, &u1, &u2, &u3); + } } else { @@ -13152,7 +13223,7 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond, for (order=first_order; order ; order=order->next) { table_map order_tables=order->item[0]->used_tables(); - if (order->item[0]->with_sum_func || + if (order->item[0]->with_sum_func() || /* If the outer table of an outer join is const (either by itself or after applying WHERE condition), grouping on a field from such a @@ -13328,7 +13399,7 @@ ORDER *simple_remove_const(ORDER *order, COND *where) ORDER *first= NULL, *prev= NULL; for (; order; order= order->next) { - DBUG_ASSERT(!order->item[0]->with_sum_func); // should never happen + DBUG_ASSERT(!order->item[0]->with_sum_func()); // should never happen if (!const_expression_in_where(where, order->item[0])) { if (!first) @@ -13577,9 +13648,9 @@ finish: FALSE otherwise */ -static bool check_simple_equality(THD *thd, const Item::Context &ctx, - Item *left_item, Item *right_item, - COND_EQUAL *cond_equal) +bool check_simple_equality(THD *thd, const Item::Context &ctx, + Item *left_item, Item *right_item, + COND_EQUAL *cond_equal) { Item *orig_left_item= left_item; Item *orig_right_item= right_item; @@ -14032,7 +14103,7 @@ COND *Item_cond_and::build_equal_items(THD *thd, if (!cond_args->elements && !cond_equal.current_level.elements && !eq_list.elements) - return new (thd->mem_root) Item_int(thd, (longlong) 1, 1); + return new (thd->mem_root) Item_bool(thd, true); List_iterator_fast<Item_equal> it(cond_equal.current_level); while ((item_equal= it++)) @@ -14139,7 +14210,7 @@ COND *Item_func_eq::build_equal_items(THD *thd, Item_equal *item_equal; int n= cond_equal.current_level.elements + eq_list.elements; if (n == 0) - return new (thd->mem_root) Item_int(thd, (longlong) 1, 1); + return new (thd->mem_root) Item_bool(thd, true); else if (n == 1) { if ((item_equal= cond_equal.current_level.pop())) @@ -14530,7 +14601,7 @@ Item *eliminate_item_equal(THD *thd, COND *cond, COND_EQUAL *upper_levels, List<Item> eq_list; Item_func_eq *eq_item= 0; if (((Item *) item_equal)->const_item() && !item_equal->val_int()) - return new (thd->mem_root) Item_int(thd, (longlong) 0, 1); + return new (thd->mem_root) Item_bool(thd, false); Item *item_const= item_equal->get_const(); Item_equal_fields_iterator it(*item_equal); Item *head; @@ -14538,7 +14609,7 @@ Item *eliminate_item_equal(THD *thd, COND *cond, COND_EQUAL *upper_levels, Item *current_sjm_head= NULL; DBUG_ASSERT(!cond || - cond->type() == Item::INT_ITEM || + cond->is_bool_literal() || (cond->type() == Item::FUNC_ITEM && ((Item_func *) cond)->functype() == Item_func::EQ_FUNC) || (cond->type() == Item::COND_ITEM && @@ -14659,13 +14730,13 @@ Item *eliminate_item_equal(THD *thd, COND *cond, COND_EQUAL *upper_levels, cond AND eq_1 AND eq_2 AND eq_3 AND ... - 'cond' is a parameter for this function, which may be NULL, an Item_int(1), + 'cond' is a parameter for this function, which may be NULL, an Item_bool(1), or an Item_func_eq or an Item_cond_and. We want to return a well-formed condition: no nested Item_cond_and objects, or Item_cond_and with a single child: - if 'cond' is an Item_cond_and, we add eq_i as its tail - - if 'cond' is Item_int(1), we return eq_i + - if 'cond' is Item_bool(1), we return eq_i - otherwise, we create our own Item_cond_and and put 'cond' at the front of it. - if we have only one condition to return, we don't create an Item_cond_and @@ -14677,10 +14748,10 @@ Item *eliminate_item_equal(THD *thd, COND *cond, COND_EQUAL *upper_levels, switch (eq_list.elements) { case 0: - res= cond ? cond : new (thd->mem_root) Item_int(thd, (longlong) 1, 1); + res= cond ? cond : new (thd->mem_root) Item_bool(thd, true); break; case 1: - if (!cond || cond->type() == Item::INT_ITEM) + if (!cond || cond->is_bool_literal()) res= eq_item; break; default: @@ -14822,7 +14893,7 @@ static COND* substitute_for_best_equal_field(THD *thd, JOIN_TAB *context_tab, eq_cond= 0; break; } - else if (eq_cond->type() == Item::INT_ITEM && !eq_cond->val_bool()) + else if (eq_cond->is_bool_literal() && !eq_cond->val_bool()) { /* This occurs when eliminate_item_equal() founds that cond is @@ -14847,7 +14918,7 @@ static COND* substitute_for_best_equal_field(THD *thd, JOIN_TAB *context_tab, else { /* Do not add an equality condition if it's always true */ - if (eq_cond->type() != Item::INT_ITEM && + if (!eq_cond->is_bool_literal() && cond_list->push_front(eq_cond, thd->mem_root)) eq_cond= 0; } @@ -15361,7 +15432,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top, conds= and_conds(join->thd, conds, table->on_expr); conds->top_level_item(); /* conds is always a new item as both cond and on_expr existed */ - DBUG_ASSERT(!conds->fixed); + DBUG_ASSERT(!conds->is_fixed()); conds->fix_fields(join->thd, &conds); } else @@ -16429,9 +16500,8 @@ Item_func_isnull::remove_eq_conds(THD *thd, Item::cond_result *cond_value, { Field *field= ((Item_field*) real_item)->field; - if (((field->type() == MYSQL_TYPE_DATE) || - (field->type() == MYSQL_TYPE_DATETIME)) && - (field->flags & NOT_NULL_FLAG)) + if ((field->flags & NOT_NULL_FLAG) && + field->type_handler()->cond_notnull_field_isnull_to_field_eq_zero()) { /* fix to replace 'NULL' dates with '0' (shreeve@uci.edu) */ /* @@ -16447,7 +16517,7 @@ Item_func_isnull::remove_eq_conds(THD *thd, Item::cond_result *cond_value, */ - Item *item0= new(thd->mem_root) Item_int(thd, (longlong) 0, 1); + Item *item0= new(thd->mem_root) Item_bool(thd, false); Item *eq_cond= new(thd->mem_root) Item_func_eq(thd, args[0], item0); if (!eq_cond) return this; @@ -16517,7 +16587,7 @@ Item_func_isnull::remove_eq_conds(THD *thd, Item::cond_result *cond_value, cond= new_cond; /* Item_func_eq can't be fixed after creation so we do not check - cond->fixed, also it do not need tables so we use 0 as second + cond->is_fixed(), also it do not need tables so we use 0 as second argument. */ cond->fix_fields(thd, &cond); @@ -16677,60 +16747,6 @@ const_expression_in_where(COND *cond, Item *comp_item, Field *comp_field, Create internal temporary table ****************************************************************************/ -/** - Create field for temporary table from given field. - - @param thd Thread handler - @param org_field field from which new field will be created - @param name New field name - @param table Temporary table - @param item !=NULL if item->result_field should point to new field. - This is relevant for how fill_record() is going to work: - If item != NULL then fill_record() will update - the record in the original table. - If item == NULL then fill_record() will update - the temporary table - - @retval - NULL on error - @retval - new_created field -*/ - -Field *create_tmp_field_from_field(THD *thd, Field *org_field, - LEX_CSTRING *name, TABLE *table, - Item_field *item) -{ - Field *new_field; - - new_field= org_field->make_new_field(thd->mem_root, table, - table == org_field->table); - if (new_field) - { - new_field->init(table); - new_field->orig_table= org_field->orig_table; - if (item) - item->result_field= new_field; - else - new_field->field_name= *name; - new_field->flags|= org_field->flags & NO_DEFAULT_VALUE_FLAG; - if (org_field->maybe_null() || (item && item->maybe_null)) - new_field->flags&= ~NOT_NULL_FLAG; // Because of outer join - if (org_field->type() == MYSQL_TYPE_VAR_STRING || - org_field->type() == MYSQL_TYPE_VARCHAR) - table->s->db_create_options|= HA_OPTION_PACK_RECORD; - else if (org_field->type() == FIELD_TYPE_DOUBLE) - ((Field_double *) new_field)->not_fixed= TRUE; - new_field->vcol_info= 0; - new_field->cond_selectivity= 1.0; - new_field->next_equal_field= NULL; - new_field->option_list= NULL; - new_field->option_struct= NULL; - } - return new_field; -} - - Field *Item::create_tmp_field_int(TABLE *table, uint convert_int_length) { const Type_handler *h= &type_handler_long; @@ -16740,6 +16756,22 @@ Field *Item::create_tmp_field_int(TABLE *table, uint convert_int_length) *this, table); } +Field *Item::tmp_table_field_from_field_type_maybe_null(TABLE *table, + Tmp_field_src *src, + const Tmp_field_param *param, + bool is_explicit_null) +{ + DBUG_ASSERT(!param->make_copy_field()); + DBUG_ASSERT(!is_result_field()); + Field *result; + if ((result= tmp_table_field_from_field_type(table))) + { + if (result && is_explicit_null) + result->is_created_from_null_item= true; + } + return result; +} + Field *Item_sum::create_tmp_field(bool group, TABLE *table) { @@ -16771,57 +16803,6 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table) } -static void create_tmp_field_from_item_finalize(THD *thd, - Field *new_field, - Item *item, - Item ***copy_func, - bool modify_item) -{ - if (copy_func && - (item->is_result_field() || - (item->real_item()->is_result_field()))) - *((*copy_func)++) = item; // Save for copy_funcs - if (modify_item) - item->set_result_field(new_field); - if (item->type() == Item::NULL_ITEM) - new_field->is_created_from_null_item= TRUE; -} - - -/** - Create field for temporary table using type of given item. - - @param thd Thread handler - @param item Item to create a field for - @param table Temporary table - @param copy_func If set and item is a function, store copy of - item in this array - @param modify_item 1 if item->result_field should point to new - item. This is relevent for how fill_record() - is going to work: - If modify_item is 1 then fill_record() will - update the record in the original table. - If modify_item is 0 then fill_record() will - update the temporary table - - @retval - 0 on error - @retval - new_created field -*/ - -static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, - Item ***copy_func, bool modify_item) -{ - Field *UNINIT_VAR(new_field); - DBUG_ASSERT(thd == table->in_use); - if ((new_field= item->create_tmp_field(false, table))) - create_tmp_field_from_item_finalize(thd, new_field, item, - copy_func, modify_item); - return new_field; -} - - /** Create field for information schema table. @@ -16859,19 +16840,182 @@ Field *Item::create_field_for_schema(THD *thd, TABLE *table) /** + Create a temporary field for Item_field (or its descendant), + either direct or referenced by an Item_ref. +*/ +Field * +Item_field::create_tmp_field_from_item_field(TABLE *new_table, + Item_ref *orig_item, + const Tmp_field_param *param) +{ + DBUG_ASSERT(!is_result_field()); + Field *result; + /* + If item have to be able to store NULLs but underlaid field can't do it, + create_tmp_field_from_field() can't be used for tmp field creation. + */ + if (((maybe_null && in_rollup) || + (new_table->in_use->create_tmp_table_for_derived && /* for mat. view/dt */ + orig_item && orig_item->maybe_null)) && + !field->maybe_null()) + { + /* + The item the ref points to may have maybe_null flag set while + the ref doesn't have it. This may happen for outer fields + when the outer query decided at some point after name resolution phase + that this field might be null. Take this into account here. + */ + Record_addr rec(orig_item ? orig_item->maybe_null : maybe_null); + const Type_handler *handler= type_handler()-> + type_handler_for_tmp_table(this); + result= handler->make_and_init_table_field(orig_item ? &orig_item->name : &name, + rec, *this, new_table); + } + else if (param->table_cant_handle_bit_fields() && + field->type() == MYSQL_TYPE_BIT) + { + const Type_handler *handler= type_handler_long_or_longlong(); + result= handler->make_and_init_table_field(&name, + Record_addr(maybe_null), + *this, new_table); + } + else + { + LEX_CSTRING *tmp= orig_item ? &orig_item->name : &name; + bool tmp_maybe_null= param->modify_item() ? maybe_null : + field->maybe_null(); + result= field->create_tmp_field(new_table->in_use->mem_root, new_table, + tmp_maybe_null); + if (result) + result->field_name= *tmp; + } + if (result && param->modify_item()) + result_field= result; + return result; +} + + +Field *Item_field::create_tmp_field_ex(TABLE *table, + Tmp_field_src *src, + const Tmp_field_param *param) +{ + DBUG_ASSERT(!is_result_field()); + Field *result; + src->set_field(field); + if (!(result= create_tmp_field_from_item_field(table, NULL, param))) + return NULL; + /* + Fields that are used as arguments to the DEFAULT() function already have + their data pointers set to the default value during name resolution. See + Item_default_value::fix_fields. + */ + if (type() != Item::DEFAULT_VALUE_ITEM && field->eq_def(result)) + src->set_default_field(field); + return result; +} + + +Field *Item_ref::create_tmp_field_ex(TABLE *table, + Tmp_field_src *src, + const Tmp_field_param *param) +{ + Item *item= real_item(); + DBUG_ASSERT(is_result_field()); + if (item->type() == Item::FIELD_ITEM) + { + Field *result; + Item_field *field= (Item_field*) item; + Tmp_field_param prm2(*param); + prm2.set_modify_item(false); + src->set_field(field->field); + if (!(result= field->create_tmp_field_from_item_field(table, this, &prm2))) + return NULL; + if (param->modify_item()) + result_field= result; + return result; + } + return Item_result_field::create_tmp_field_ex(table, src, param); +} + + +void Item_result_field::get_tmp_field_src(Tmp_field_src *src, + const Tmp_field_param *param) +{ + if (param->make_copy_field()) + { + DBUG_ASSERT(result_field); + src->set_field(result_field); + } + else + { + src->set_item_result_field(this); // Save for copy_funcs + } +} + + +Field *Item_result_field::create_tmp_field_ex(TABLE *table, + Tmp_field_src *src, + const Tmp_field_param *param) +{ + /* + Possible Item types: + - Item_cache_wrapper (only for CREATE..SELECT ?) + - Item_func + - Item_subselect + */ + DBUG_ASSERT(is_result_field()); + DBUG_ASSERT(type() != NULL_ITEM); + get_tmp_field_src(src, param); + Field *result; + if ((result= tmp_table_field_from_field_type(table)) && param->modify_item()) + result_field= result; + return result; +} + + +Field *Item_func_user_var::create_tmp_field_ex(TABLE *table, + Tmp_field_src *src, + const Tmp_field_param *param) +{ + DBUG_ASSERT(is_result_field()); + DBUG_ASSERT(type() != NULL_ITEM); + get_tmp_field_src(src, param); + Field *result; + if ((result= create_table_field_from_handler(table)) && param->modify_item()) + result_field= result; + return result; +} + + +Field *Item_func_sp::create_tmp_field_ex(TABLE *table, + Tmp_field_src *src, + const Tmp_field_param *param) +{ + Field *result; + get_tmp_field_src(src, param); + if ((result= sp_result_field->create_tmp_field(table->in_use->mem_root, + table))) + { + result->field_name= name; + if (param->modify_item()) + result_field= result; + } + return result; +} + +/** Create field for temporary table. - @param thd Thread handler - @param table Temporary table - @param item Item to create a field for - @param type Type of item (normally item->type) - @param copy_func If set and item is a function, store copy of item + @param table Temporary table + @param item Item to create a field for + @param type Type of item (normally item->type) + @param copy_func If set and item is a function, store copy of item in this array @param from_field if field will be created using other field as example, pointer example field will be written here - @param default_field If field has a default value field, store it here - @param group 1 if we are going to do a relative group by on result - @param modify_item 1 if item->result_field should point to new item. + @param default_field If field has a default value field, store it here + @param group 1 if we are going to do a relative group by on result + @param modify_item 1 if item->result_field should point to new item. This is relevent for how fill_record() is going to work: If modify_item is 1 then fill_record() will update @@ -16880,175 +17024,28 @@ Field *Item::create_field_for_schema(THD *thd, TABLE *table) the temporary table @retval - 0 on error + 0 on error @retval new_created field + Create a temporary field for Item_field (or its descendant), + either direct or referenced by an Item_ref. */ - -Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, +Field *create_tmp_field(TABLE *table, Item *item, Item ***copy_func, Field **from_field, Field **default_field, bool group, bool modify_item, bool table_cant_handle_bit_fields, bool make_copy_field) { - Field *result; - Item::Type orig_type= type; - Item *orig_item= 0; - - DBUG_ASSERT(thd == table->in_use); - - if (type != Item::FIELD_ITEM && - item->real_item()->type() == Item::FIELD_ITEM) - { - orig_item= item; - item= item->real_item(); - type= Item::FIELD_ITEM; - } - - switch (type) { - case Item::TYPE_HOLDER: - case Item::SUM_FUNC_ITEM: - { - result= item->create_tmp_field(group, table); - if (!result) - my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR)); - return result; - } - case Item::FIELD_ITEM: - case Item::DEFAULT_VALUE_ITEM: - case Item::INSERT_VALUE_ITEM: - case Item::TRIGGER_FIELD_ITEM: - { - Item_field *field= (Item_field*) item; - bool orig_modify= modify_item; - if (orig_type == Item::REF_ITEM) - modify_item= 0; - /* - If item have to be able to store NULLs but underlaid field can't do it, - create_tmp_field_from_field() can't be used for tmp field creation. - */ - if (((field->maybe_null && field->in_rollup) || - (thd->create_tmp_table_for_derived && /* for mat. view/dt */ - orig_item && orig_item->maybe_null)) && - !field->field->maybe_null()) - { - bool save_maybe_null= FALSE; - /* - The item the ref points to may have maybe_null flag set while - the ref doesn't have it. This may happen for outer fields - when the outer query decided at some point after name resolution phase - that this field might be null. Take this into account here. - */ - if (orig_item) - { - save_maybe_null= item->maybe_null; - item->maybe_null= orig_item->maybe_null; - } - result= create_tmp_field_from_item(thd, item, table, NULL, - modify_item); - *from_field= field->field; - if (result && modify_item) - field->result_field= result; - if (orig_item) - { - item->maybe_null= save_maybe_null; - result->field_name= orig_item->name; - } - } - else if (table_cant_handle_bit_fields && field->field->type() == - MYSQL_TYPE_BIT) - { - const Type_handler *handler= item->type_handler_long_or_longlong(); - *from_field= field->field; - if ((result= - handler->make_and_init_table_field(&item->name, - Record_addr(item->maybe_null), - *item, table))) - create_tmp_field_from_item_finalize(thd, result, item, - copy_func, modify_item); - if (result && modify_item) - field->result_field= result; - } - else - { - LEX_CSTRING *tmp= orig_item ? &orig_item->name : &item->name; - result= create_tmp_field_from_field(thd, (*from_field= field->field), - tmp, table, - modify_item ? field : - NULL); - } - - if (orig_type == Item::REF_ITEM && orig_modify) - ((Item_ref*)orig_item)->set_result_field(result); - /* - Fields that are used as arguments to the DEFAULT() function already have - their data pointers set to the default value during name resolution. See - Item_default_value::fix_fields. - */ - if (orig_type != Item::DEFAULT_VALUE_ITEM && field->field->eq_def(result)) - *default_field= field->field; - return result; - } - /* Fall through */ - case Item::FUNC_ITEM: - if (((Item_func *) item)->functype() == Item_func::FUNC_SP) - { - Item_func_sp *item_func_sp= (Item_func_sp *) item; - Field *sp_result_field= item_func_sp->get_sp_result_field(); - - if (make_copy_field) - { - DBUG_ASSERT(item_func_sp->result_field); - *from_field= item_func_sp->result_field; - } - else - { - *((*copy_func)++)= item; - } - Field *result_field= - create_tmp_field_from_field(thd, - sp_result_field, - &item_func_sp->name, - table, - NULL); - - if (modify_item) - item->set_result_field(result_field); - - return result_field; - } - - /* Fall through */ - case Item::COND_ITEM: - case Item::FIELD_AVG_ITEM: - case Item::FIELD_STD_ITEM: - case Item::SUBSELECT_ITEM: - /* The following can only happen with 'CREATE TABLE ... SELECT' */ - case Item::PROC_ITEM: - case Item::INT_ITEM: - case Item::REAL_ITEM: - case Item::DECIMAL_ITEM: - case Item::STRING_ITEM: - case Item::DATE_ITEM: - case Item::REF_ITEM: - case Item::NULL_ITEM: - case Item::VARBIN_ITEM: - case Item::CACHE_ITEM: - case Item::WINDOW_FUNC_ITEM: // psergey-winfunc: - case Item::EXPR_CACHE_ITEM: - case Item::PARAM_ITEM: - if (make_copy_field) - { - DBUG_ASSERT(((Item_result_field*)item)->result_field); - *from_field= ((Item_result_field*)item)->result_field; - } - return create_tmp_field_from_item(thd, item, table, - (make_copy_field ? 0 : copy_func), - modify_item); - default: // Dosen't have to be stored - return 0; - } + Tmp_field_src src; + Tmp_field_param prm(group, modify_item, table_cant_handle_bit_fields, + make_copy_field); + Field *result= item->create_tmp_field_ex(table, &src, &prm); + *from_field= src.field(); + *default_field= src.default_field(); + if (src.item_result_field()) + *((*copy_func)++)= src.item_result_field(); + return result; } /* @@ -17064,7 +17061,7 @@ setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps, uint field_count) { uint bitmap_size= bitmap_buffer_size(field_count); - DBUG_ASSERT(table->s->virtual_fields == 0 && table->def_vcol_set == 0); + DBUG_ASSERT(table->s->virtual_fields == 0); my_bitmap_init(&table->def_read_set, (my_bitmap_map*) bitmaps, field_count, FALSE); @@ -17329,7 +17326,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields, } if (not_all_columns) { - if (item->with_sum_func && type != Item::SUM_FUNC_ITEM) + if (item->with_sum_func() && type != Item::SUM_FUNC_ITEM) { if (item->used_tables() & OUTER_REF_TABLE_BIT) item->update_used_tables(); @@ -17359,7 +17356,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields, { Item *tmp_item; Field *new_field= - create_tmp_field(thd, table, arg, arg->type(), ©_func, + create_tmp_field(table, arg, ©_func, tmp_from_field, &default_field[fieldnr], group != 0,not_all_columns, distinct, false); @@ -17409,7 +17406,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields, else { /* - The last parameter to create_tmp_field() is a bit tricky: + The last parameter to create_tmp_field_ex() is a bit tricky: We need to set it to 0 in union, to get fill_record() to modify the temporary table. @@ -17423,7 +17420,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields, */ Field *new_field= (param->schema_table) ? item->create_field_for_schema(thd, table) : - create_tmp_field(thd, table, item, type, ©_func, + create_tmp_field(table, item, ©_func, tmp_from_field, &default_field[fieldnr], group != 0, !force_copy_fields && @@ -17437,8 +17434,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields, */ item->marker == 4 || param->bit_fields_as_long, force_copy_fields); - - if (unlikely(!new_field)) + if (!new_field) { if (unlikely(thd->is_fatal_error)) goto err; // Got OOM @@ -18019,12 +18015,10 @@ bool Virtual_tmp_table::add(List<Spvar_definition> &field_list) while ((cdef= it++)) { Field *tmp; - if (!(tmp= cdef->make_field(s, in_use->mem_root, 0, - (uchar*) (f_maybe_null(cdef->pack_flag) ? "" : 0), - f_maybe_null(cdef->pack_flag) ? 1 : 0, - &cdef->field_name))) + Record_addr addr(f_maybe_null(cdef->pack_flag)); + if (!(tmp= cdef->make_field(s, in_use->mem_root, &addr, &cdef->field_name))) DBUG_RETURN(true); - add(tmp); + add(tmp); } DBUG_RETURN(false); } @@ -18144,7 +18138,7 @@ bool Virtual_tmp_table::sp_set_all_fields_from_item_list(THD *thd, bool Virtual_tmp_table::sp_set_all_fields_from_item(THD *thd, Item *value) { - DBUG_ASSERT(value->fixed); + DBUG_ASSERT(value->is_fixed()); DBUG_ASSERT(value->cols() == s->fields); for (uint i= 0; i < value->cols(); i++) { @@ -18567,7 +18561,7 @@ create_internal_tmp_table_from_heap(THD *thd, TABLE *table, We don't want this error to be converted to a warning, e.g. in case of INSERT IGNORE ... SELECT. */ - table->file->print_error(error, MYF(ME_FATALERROR)); + table->file->print_error(error, MYF(ME_FATAL)); DBUG_RETURN(1); } new_table= *table; @@ -18590,7 +18584,7 @@ create_internal_tmp_table_from_heap(THD *thd, TABLE *table, new_table.no_rows= table->no_rows; if (create_internal_tmp_table(&new_table, table->key_info, start_recinfo, recinfo, - thd->lex->select_lex.options | + thd->lex->first_select_lex()->options | thd->variables.option_bits)) goto err2; if (open_tmp_table(&new_table)) @@ -22741,7 +22735,7 @@ static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field, if (unlikely(copy_blobs(first_field))) { my_message(ER_OUTOFMEMORY, ER_THD(thd,ER_OUTOFMEMORY), - MYF(ME_FATALERROR)); + MYF(ME_FATAL)); error=0; goto err; } @@ -23018,12 +23012,7 @@ find_order_in_list(THD *thd, Ref_ptr_array ref_pointer_array, uint counter; enum_resolution_type resolution; - /* - Local SP variables may be int but are expressions, not positions. - (And they can't be used before fix_fields is called for them). - */ - if (order_item->type() == Item::INT_ITEM && order_item->basic_const_item() && - !from_window_spec) + if (order_item->is_order_clause_position() && !from_window_spec) { /* Order by position */ uint count; if (order->counter_used) @@ -23137,7 +23126,7 @@ find_order_in_list(THD *thd, Ref_ptr_array ref_pointer_array, inspite of that fix_fields() calls find_item_in_list() one more time. - We check order_item->fixed because Item_func_group_concat can put + We check order_item->is_fixed() because Item_func_group_concat can put arguments for which fix_fields already was called. */ if (order_item->fix_fields_if_needed_for_order_by(thd, order->item) || @@ -23247,7 +23236,7 @@ setup_group(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables, all_fields, true, true, from_window_spec)) return 1; (*ord->item)->marker= UNDEF_POS; /* Mark found */ - if ((*ord->item)->with_sum_func && context_analysis_place == IN_GROUP_BY) + if ((*ord->item)->with_sum_func() && context_analysis_place == IN_GROUP_BY) { my_error(ER_WRONG_GROUP_FIELD, MYF(0), (*ord->item)->full_name()); return 1; @@ -23406,7 +23395,7 @@ create_distinct_group(THD *thd, Ref_ptr_array ref_pointer_array, li.rewind(); while ((item=li++)) { - if (!item->const_item() && !item->with_sum_func && !item->marker) + if (!item->const_item() && !item->with_sum_func() && !item->marker) { /* Don't put duplicate columns from the SELECT list into the @@ -23503,9 +23492,11 @@ count_field_types(SELECT_LEX *select_lex, TMP_TABLE_PARAM *param, } else { + With_sum_func_cache *cache= field->get_with_sum_func_cache(); param->func_count++; - if (reset_with_sum_func) - field->with_sum_func=0; + // "field" can point to Item_std_field, so "cache" can be NULL here. + if (reset_with_sum_func && cache) + cache->reset_with_sum_func(); } } } @@ -23645,7 +23636,7 @@ void calc_group_buffer(TMP_TABLE_PARAM *param, ORDER *group) { /* Group strings are taken as varstrings and require an length field. - A field is not yet created by create_tmp_field() + A field is not yet created by create_tmp_field_ex() and the sizes should match up. */ key_length+= group_item->max_length + HA_KEY_BLOB_LENGTH; @@ -23655,7 +23646,7 @@ void calc_group_buffer(TMP_TABLE_PARAM *param, ORDER *group) default: /* This case should never be choosen */ DBUG_ASSERT(0); - my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR)); + my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATAL)); } } parts++; @@ -23909,7 +23900,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, real_pos->real_type() == Item::SUBSELECT_ITEM || real_pos->type() == Item::CACHE_ITEM || real_pos->type() == Item::COND_ITEM) && - !real_pos->with_sum_func) + !real_pos->with_sum_func()) { // Save for send fields pos= real_pos; /* TODO: @@ -23918,7 +23909,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, on how the value is to be used: In some cases this may be an argument in a group function, like: IF(ISNULL(col),0,COUNT(*)) */ - if (!(pos=new (thd->mem_root) Item_copy_string(thd, pos))) + if (!(pos= pos->type_handler()->create_item_copy(thd, pos))) goto err; if (i < border) // HAVING, ORDER and GROUP BY { @@ -24116,7 +24107,7 @@ change_to_use_tmp_fields(THD *thd, Ref_ptr_array ref_pointer_array, for (uint i= 0; (item= it++); i++) { Field *field; - if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM) + if (item->with_sum_func() && item->type() != Item::SUM_FUNC_ITEM) item_field= item; else if (item->type() == Item::FIELD_ITEM) { @@ -24424,7 +24415,7 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab) } if (unlikely(thd->is_fatal_error)) DBUG_RETURN(TRUE); - if (!cond->fixed) + if (!cond->is_fixed()) { Item *tmp_item= (Item*) cond; cond->fix_fields(thd, &tmp_item); @@ -24643,7 +24634,7 @@ bool JOIN::rollup_init() Marking the expression item as 'with_sum_func' will ensure this. */ if (changed) - item->with_sum_func= 1; + item->get_with_sum_func_cache()->set_with_sum_func(); } } return 0; @@ -25131,7 +25122,8 @@ bool JOIN_TAB::save_explain_data(Explain_table_access *eta, */ if (real_table->merged_for_insert) { - TABLE_LIST *view_child= real_table->view->select_lex.table_list.first; + TABLE_LIST *view_child= + real_table->view->first_select_lex()->table_list.first; for (;view_child; view_child= view_child->next_local) { if (view_child->table == table) @@ -25584,8 +25576,9 @@ int JOIN::save_explain_data_intern(Explain_query *output, { JOIN *join= this; /* Legacy: this code used to be a non-member function */ DBUG_ENTER("JOIN::save_explain_data_intern"); - DBUG_PRINT("info", ("Select %p, type %s, message %s", - join->select_lex, join->select_lex->type, + DBUG_PRINT("info", ("Select %p (%u), type %s, message %s", + join->select_lex, join->select_lex->select_number, + join->select_lex->type, message ? message : "NULL")); DBUG_ASSERT(have_query_plan == QEP_AVAILABLE); /* fake_select_lex is created/printed by Explain_union */ @@ -25611,7 +25604,7 @@ int JOIN::save_explain_data_intern(Explain_query *output, explain->select_id= join->select_lex->select_number; explain->select_type= join->select_lex->type; - explain->linkage= select_lex->linkage; + explain->linkage= select_lex->get_linkage(); explain->using_temporary= need_tmp; explain->using_filesort= need_order_arg; /* Setting explain->message means that all other members are invalid */ @@ -25634,7 +25627,7 @@ int JOIN::save_explain_data_intern(Explain_query *output, explain->select_id= select_lex->select_number; explain->select_type= select_lex->type; - explain->linkage= select_lex->linkage; + explain->linkage= select_lex->get_linkage(); explain->using_temporary= need_tmp; explain->using_filesort= need_order_arg; explain->message= "Storage engine handles GROUP BY"; @@ -25657,7 +25650,7 @@ int JOIN::save_explain_data_intern(Explain_query *output, join->select_lex->set_explain_type(true); xpl_sel->select_id= join->select_lex->select_number; xpl_sel->select_type= join->select_lex->type; - xpl_sel->linkage= select_lex->linkage; + xpl_sel->linkage= select_lex->get_linkage(); if (select_lex->master_unit()->derived) xpl_sel->connection_type= Explain_node::EXPLAIN_NODE_DERIVED; @@ -25801,7 +25794,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, for such queries, we'll get here before having called subquery_expr->fix_fields(), which will cause failure to */ - if (unit->item && !unit->item->fixed) + if (unit->item && !unit->item->is_fixed()) { Item *ref= unit->item; if (unit->item->fix_fields(thd, &ref)) @@ -26241,6 +26234,18 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) { str->append("/* select#"); str->append_ulonglong(select_number); + if (thd->lex->describe & DESCRIBE_EXTENDED2) + { + str->append("/"); + str->append_ulonglong(nest_level); + + if (master_unit()->fake_select_lex && + master_unit()->first_select() == this) + { + str->append(" Filter Select: "); + master_unit()->fake_select_lex->print(thd, str, query_type); + } + } str->append(" */ "); } @@ -26272,18 +26277,21 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) str->append(STRING_WITH_LEN("sql_buffer_result ")); if (options & OPTION_FOUND_ROWS) str->append(STRING_WITH_LEN("sql_calc_found_rows ")); - switch (sql_cache) + if (this == parent_lex->first_select_lex()) { - case SQL_NO_CACHE: - str->append(STRING_WITH_LEN("sql_no_cache ")); - break; - case SQL_CACHE: - str->append(STRING_WITH_LEN("sql_cache ")); - break; - case SQL_CACHE_UNSPECIFIED: - break; - default: - DBUG_ASSERT(0); + switch (parent_lex->sql_cache) + { + case LEX::SQL_NO_CACHE: + str->append(STRING_WITH_LEN("sql_no_cache ")); + break; + case LEX::SQL_CACHE: + str->append(STRING_WITH_LEN("sql_cache ")); + break; + case LEX::SQL_CACHE_UNSPECIFIED: + break; + default: + DBUG_ASSERT(0); + } } //Item List |