diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index d442e4d97ced3b7636ef5cf76a697f2731785acb..e2a5494eaf76e475c78a8df8da9ef2df6029d54d 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -81,21 +81,18 @@ select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1); a b 1 7 2 7 -select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1) -union (select * from t4 order by a limit 2) limit 3; +select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1) union (select * from t4 order by a limit 2) limit 3; a b 1 7 2 7 3 8 -select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1) -union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a); +select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1) union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a); a b 1 7 2 7 3 8 4 8 -explain select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1) -union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a); +explain select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1) union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where 2 SUBSELECT t3 ALL NULL NULL NULL NULL 3 Using filesort @@ -330,19 +327,15 @@ Unknown column 'a' in 'having clause' SELECT * from t2 where topic IN (SELECT topic FROM t2 GROUP BY date); mot topic date pseudo joce 40143 2002-10-22 joce -joce 43506 2002-10-22 joce SELECT * from t2 where topic IN (SELECT topic FROM t2 GROUP BY date HAVING topic < 4100); mot topic date pseudo -joce 43506 2002-10-22 joce SELECT * from t2 where topic IN (SELECT SUM(topic) FROM t1); mot topic date pseudo SELECT * from t2 where topic = any (SELECT topic FROM t2 GROUP BY date); mot topic date pseudo joce 40143 2002-10-22 joce -joce 43506 2002-10-22 joce SELECT * from t2 where topic = any (SELECT topic FROM t2 GROUP BY date HAVING topic < 4100); mot topic date pseudo -joce 43506 2002-10-22 joce SELECT * from t2 where topic = any (SELECT SUM(topic) FROM t1); mot topic date pseudo SELECT * from t2 where topic = all (SELECT topic FROM t2 GROUP BY date); @@ -351,6 +344,7 @@ joce 40143 2002-10-22 joce SELECT * from t2 where topic = all (SELECT topic FROM t2 GROUP BY date HAVING topic < 4100); mot topic date pseudo joce 40143 2002-10-22 joce +joce 43506 2002-10-22 joce SELECT * from t2 where topic = all (SELECT SUM(topic) FROM t2); mot topic date pseudo SELECT * from t2 where topic <> any (SELECT SUM(topic) FROM t2); diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 8b174882bc694bd9e13f1be13205aa2579e6f3dc..c22827dff18172da053ee12cc5f16a58b058d9c7 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -42,12 +42,9 @@ select (select a from t3), a from t2; select * from t2 where t2.a=(select a from t1); insert into t3 values (6),(7),(3); select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1); -select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1) -union (select * from t4 order by a limit 2) limit 3; -select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1) -union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a); -explain select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1) -union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a); +select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1) union (select * from t4 order by a limit 2) limit 3; +select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1) union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a); +explain select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1) union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a); select (select a from t3 where a<t2.a*4 order by 1 desc limit 1), a from t2; select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from (select * from t2 where a>1) as tt; @@ -190,7 +187,10 @@ SELECT * from t2 where topic = any (SELECT topic FROM t2 GROUP BY date); SELECT * from t2 where topic = any (SELECT topic FROM t2 GROUP BY date HAVING topic < 4100); SELECT * from t2 where topic = any (SELECT SUM(topic) FROM t1); SELECT * from t2 where topic = all (SELECT topic FROM t2 GROUP BY date); +SELECT topic FROM t2 GROUP BY date; +SELECT topic FROM t2 GROUP BY date HAVING topic < 4100; SELECT * from t2 where topic = all (SELECT topic FROM t2 GROUP BY date HAVING topic < 4100); +SELECT *, date as fff from t2 where not (SELECT date FROM t2 GROUP BY date HAVING topic < 4100 and fff!=date); SELECT * from t2 where topic = all (SELECT SUM(topic) FROM t2); SELECT * from t2 where topic <> any (SELECT SUM(topic) FROM t2); drop table t1,t2; diff --git a/sql/item.cc b/sql/item.cc index 5e74820a3f85e0eff8966ba9a650d8d5d71d920d..81f923faabd1ba2faa13c4bcc46e9fdc1434444d 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -46,6 +46,31 @@ Item::Item(): loop_id= 0; } +Item::Item(Item &item): + loop_id(0), + str_value(item.str_value), + name(item.name), + max_length(item.max_length), + marker(item.marker), + decimals(item.decimals), + maybe_null(item.maybe_null), + null_value(item.null_value), + unsigned_flag(item.unsigned_flag), + with_sum_func(item.with_sum_func), + fixed(item.fixed) +{ + next=current_thd->free_list; // Put in free list + current_thd->free_list= this; +} + +Item_ident::Item_ident(Item_ident &item): + Item(item), + db_name(item.db_name), + table_name(item.table_name), + field_name(item.field_name), + depended_from(item.depended_from) +{} + bool Item::check_loop(uint id) { DBUG_ENTER("Item::check_loop"); @@ -153,6 +178,11 @@ Item_field::Item_field(Field *f) :Item_ident(NullS,f->table_name,f->field_name) fixed= 1; // This item is not needed in fix_fields } +Item_field::Item_field(Item_field &item): + Item_ident(item), + field(item.field), + result_field(item.result_field) +{} void Item_field::set_field(Field *field_par) { @@ -262,6 +292,13 @@ table_map Item_field::used_tables() const return field->table->map; } +Item * Item_field::get_tmp_table_item() +{ + Item_field *new_item= new Item_field(*this); + if (new_item) + new_item->field= new_item->result_field; + return new_item; +} String *Item_int::val_str(String *str) { @@ -535,6 +572,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) SELECT_LEX *last= 0; Item **refer= (Item **)not_found_item; + uint counter= 0; // Prevent using outer fields in subselects, that is not supported now SELECT_LEX *cursel=(SELECT_LEX *) thd->lex.current_select; if (cursel->linkage != DERIVED_TABLE_TYPE) @@ -546,7 +584,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) (last= sl)->get_table_list(), 0)) != not_found_field) break; - if ((refer= find_item_in_list(this, sl->item_list, + if ((refer= find_item_in_list(this, sl->item_list, &counter, REPORT_EXCEPT_NOT_FOUND)) != (Item **)not_found_item) break; @@ -565,8 +603,16 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) } else if (refer != (Item **)not_found_item) { + if (!(*refer)->fixed) + { + my_error(ER_ILLEGAL_REFERENCE, MYF(0), name, + "forward reference in item list"); + return -1; + } + Item_ref *r; - *ref= r= new Item_ref(refer, (char *)table_name, + *ref= r= new Item_ref(last->ref_pointer_array + counter-1 + , (char *)table_name, (char *)field_name); if (!r) return 1; @@ -930,6 +976,7 @@ bool Item_null::send(THD *thd, String *packet) bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) { + uint counter= 0; if (!ref) { SELECT_LEX *sl= thd->lex.current_select->outer_select(); @@ -940,6 +987,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) */ if ((ref= find_item_in_list(this, *(thd->lex.current_select->get_item_list()), + &counter, ((sl && thd->lex.current_select->linkage != DERIVED_TABLE_TYPE) ? @@ -961,7 +1009,8 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) for ( ; sl ; sl= sl->outer_select()) { if ((ref= find_item_in_list(this, (last= sl)->item_list, - REPORT_EXCEPT_NOT_FOUND)) != + &counter, + REPORT_EXCEPT_NOT_FOUND)) != (Item **)not_found_item) break; if ((tmp= find_field_in_tables(thd, this, @@ -980,6 +1029,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) // Call to report error find_item_in_list(this, *(thd->lex.current_select->get_item_list()), + &counter, REPORT_ALL_ERRORS); ref= 0; return 1; @@ -996,17 +1046,35 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) } else { - depended_from= last; + if (!(*ref)->fixed) + { + my_error(ER_ILLEGAL_REFERENCE, MYF(0), name, + "forward reference in item list"); + return -1; + } + ref= (depended_from= last)->ref_pointer_array + counter-1; thd->lex.current_select->mark_as_dependent(last); thd->add_possible_loop(this); } } else if (!ref) return 1; + else + { + if (!(*ref)->fixed) + { + my_error(ER_ILLEGAL_REFERENCE, MYF(0), name, + "forward reference in item list"); + return -1; + } + ref= thd->lex.current_select->ref_pointer_array + counter-1; + } + max_length= (*ref)->max_length; maybe_null= (*ref)->maybe_null; decimals= (*ref)->decimals; } + if (((*ref)->with_sum_func && (depended_from || !(thd->lex.current_select->linkage != GLOBAL_OPTIONS_TYPE && diff --git a/sql/item.h b/sql/item.h index 4dff0591c09c34a1d05cd1ce4a92d5c14386c773..900315a3bf670146d5956d628e1cbbd31c03eedb 100644 --- a/sql/item.h +++ b/sql/item.h @@ -50,6 +50,8 @@ class Item { // alloc & destruct is done as start of select using sql_alloc Item(); + // copy constructor used by Item_field, Item_ref & agregate (sum) functions + Item(Item &item); virtual ~Item() { name=0; } /*lint -e1509 */ void set_name(const char *str,uint length=0); void init_make_field(Send_field *tmp_field,enum enum_field_types type); @@ -67,7 +69,8 @@ class Item { virtual longlong val_int()=0; virtual String *val_str(String*)=0; virtual void make_field(Send_field *field)=0; - virtual Field *tmp_table_field(TABLE *t_arg=(TABLE *)0) { return 0; } + virtual Field *tmp_table_field() { return 0; } + virtual Field *tmp_table_field(TABLE *t_arg) { return 0; } virtual const char *full_name() const { return name ? name : "???"; } virtual double val_result() { return val(); } virtual longlong val_int_result() { return val_int(); } @@ -82,12 +85,14 @@ class Item { virtual bool const_item() const { return used_tables() == 0; } virtual void print(String *str_arg) { str_arg->append(full_name()); } virtual void update_used_tables() {} - virtual void split_sum_func(List<Item> &fields) {} + virtual void split_sum_func(Item **ref_pointer_array, List<Item> &fields) {} virtual bool get_date(TIME *ltime,bool fuzzydate); virtual bool get_time(TIME *ltime); virtual bool is_null() { return 0; }; virtual bool check_loop(uint id); virtual void top_level_item() {} + virtual Item * get_same() { return this; } + virtual Item * get_tmp_table_item() { return get_same(); } virtual bool binary() const { return str_value.charset()->state & MY_CS_BINSORT ? 1 : 0 ; } @@ -159,11 +164,14 @@ class Item_ident :public Item const char *table_name; const char *field_name; st_select_lex *depended_from; + Item_ident(const char *db_name_par,const char *table_name_par, const char *field_name_par) :db_name(db_name_par),table_name(table_name_par), field_name(field_name_par), depended_from(0) { name = (char*) field_name_par; } + // copy constructor used by Item_field & Item_ref + Item_ident(Item_ident &item); const char *full_name() const; }; @@ -179,6 +187,8 @@ class Item_field :public Item_ident const char *field_name_par) :Item_ident(db_par,table_name_par,field_name_par),field(0),result_field(0) {} + // copy constructor need to process subselect with temporary tables + Item_field(Item_field &item); Item_field(Field *field); enum Type type() const { return FIELD_ITEM; } bool eq(const Item *item, bool binary_cmp) const; @@ -202,10 +212,12 @@ class Item_field :public Item_ident { return field->result_type(); } - Field *tmp_table_field(TABLE *t_arg=(TABLE *)0) { return result_field; } + Field *tmp_table_field() { return result_field; } + Field *tmp_table_field(TABLE *t_arg) { return result_field; } bool get_date(TIME *ltime,bool fuzzydate); bool get_time(TIME *ltime); bool is_null() { return field->is_null(); } + Item * get_tmp_table_item(); }; @@ -448,8 +460,13 @@ class Item_result_field :public Item /* Item with result field */ public: Field *result_field; /* Save result here */ Item_result_field() :result_field(0) {} + Item_result_field(Item_result_field &item): Item(item) + { + result_field= item.result_field; + } ~Item_result_field() {} /* Required with gcc 2.95 */ - Field *tmp_table_field(TABLE *t_arg=(TABLE *)0) { return result_field; } + Field *tmp_table_field() { return result_field; } + Field *tmp_table_field(TABLE *t_arg) { return result_field; } table_map used_tables() const { return 1; } virtual void fix_length_and_dec()=0; }; @@ -463,6 +480,8 @@ class Item_ref :public Item_ident :Item_ident(db_par,table_name_par,field_name_par),ref(0) {} Item_ref(Item **item, char *table_name_par,char *field_name_par) :Item_ident(NullS,table_name_par,field_name_par),ref(item) {} + // copy constructor need to process subselect with temporary tables + Item_ref(Item_ref &item): Item_ident(item), ref(item.ref) {} enum Type type() const { return REF_ITEM; } bool eq(const Item *item, bool binary_cmp) const { return ref && (*ref)->eq(item, binary_cmp); } diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index dd8d1aeff0293f71bfdf4db3cdd15e57f229878f..f1859e482065b2a4e7f5e5dbe682fd314eb9aba4 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1175,16 +1175,20 @@ void Item_func_in::update_used_tables() const_item_cache&=item->const_item(); } -void Item_func_in::split_sum_func(List<Item> &fields) +void Item_func_in::split_sum_func(Item **ref_pointer_array, List<Item> &fields) { if (item->with_sum_func && item->type() != SUM_FUNC_ITEM) - item->split_sum_func(fields); + item->split_sum_func(ref_pointer_array, fields); else if (item->used_tables() || item->type() == SUM_FUNC_ITEM) { + uint el= fields.elements; fields.push_front(item); - item=new Item_ref((Item**) fields.head_ref(),0,item->name); + ref_pointer_array[el]= item; + item=new Item_ref(ref_pointer_array + el, + 0, item->name); + } - Item_func::split_sum_func(fields); + Item_func::split_sum_func(ref_pointer_array, fields); } @@ -1281,7 +1285,7 @@ bool Item_cond::check_loop(uint id) DBUG_RETURN(0); } -void Item_cond::split_sum_func(List<Item> &fields) +void Item_cond::split_sum_func(Item **ref_pointer_array, List<Item> &fields) { List_iterator<Item> li(list); Item *item; @@ -1290,11 +1294,13 @@ void Item_cond::split_sum_func(List<Item> &fields) while ((item=li++)) { if (item->with_sum_func && item->type() != SUM_FUNC_ITEM) - item->split_sum_func(fields); + item->split_sum_func(ref_pointer_array, fields); else if (item->used_tables() || item->type() == SUM_FUNC_ITEM) { + uint el= fields.elements; fields.push_front(item); - li.replace(new Item_ref((Item**) fields.head_ref(),0,item->name)); + ref_pointer_array[el]= item; + li.replace(new Item_ref(ref_pointer_array + el, 0, item->name)); } item->update_used_tables(); used_tables_cache|=item->used_tables(); diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index b4f4872bd9576a91af0e674a2b093290d196d41f..adab7a042c5c4cccac8b29fb89a3f1130bed6fe9 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -509,7 +509,7 @@ class Item_func_in :public Item_int_func enum Functype functype() const { return IN_FUNC; } const char *func_name() const { return " IN "; } void update_used_tables(); - void split_sum_func(List<Item> &fields); + void split_sum_func(Item **ref_pointer_array, List<Item> &fields); bool check_loop(uint id) { DBUG_ENTER("Item_func_in::check_loop"); @@ -656,7 +656,7 @@ class Item_cond :public Item_bool_func table_map used_tables() const; void update_used_tables(); void print(String *str); - void split_sum_func(List<Item> &fields); + void split_sum_func(Item **ref_pointer_array, List<Item> &fields); friend int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds); bool check_loop(uint id); void top_level_item() { abort_on_null=1; } diff --git a/sql/item_func.cc b/sql/item_func.cc index c84b554b522be8e1c7ed17c5f9d45a88ee1b88d4..1d4d26d799ee6c1690bd7aaa6611ea43e3fa2969 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -146,17 +146,19 @@ bool Item_func::check_loop(uint id) DBUG_RETURN(0); } -void Item_func::split_sum_func(List<Item> &fields) +void Item_func::split_sum_func(Item **ref_pointer_array, List<Item> &fields) { Item **arg,**arg_end; for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++) { if ((*arg)->with_sum_func && (*arg)->type() != SUM_FUNC_ITEM) - (*arg)->split_sum_func(fields); + (*arg)->split_sum_func(ref_pointer_array, fields); else if ((*arg)->used_tables() || (*arg)->type() == SUM_FUNC_ITEM) { + uint el= fields.elements; fields.push_front(*arg); - *arg=new Item_ref((Item**) fields.head_ref(),0,(*arg)->name); + ref_pointer_array[el]= *arg; + *arg=new Item_ref(ref_pointer_array + el, 0, (*arg)->name); } } } @@ -225,14 +227,11 @@ bool Item_func::eq(const Item *item, bool binary_cmp) const return 1; } - Field *Item_func::tmp_table_field(TABLE *t_arg) { Field *res; LINT_INIT(res); - if (!t_arg) - return result_field; switch (result_type()) { case INT_RESULT: if (max_length > 11) @@ -303,6 +302,16 @@ void Item_func::fix_num_length_and_dec() max_length=float_length(decimals); } +Item * Item_func::get_tmp_table_item() +{ + if (!with_sum_func && !const_item()) + { + return new Item_field(result_field); + } + else + return get_same(); +} + String *Item_int_func::val_str(String *str) { longlong nr=val_int(); diff --git a/sql/item_func.h b/sql/item_func.h index 98e56af368c2bf2ef9de6a80c671e1ea6dd73cf8..dab42f1b3367f16b6e5a73a3dd223ba5a81084c4 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -118,7 +118,7 @@ class Item_func :public Item_result_field inline Item **arguments() const { return args; } inline uint argument_count() const { return arg_count; } inline void remove_arguments() { arg_count=0; } - virtual void split_sum_func(List<Item> &fields); + virtual void split_sum_func(Item **ref_pointer_array, List<Item> &fields); void print(String *str); void print_op(String *str); void fix_num_length_and_dec(); @@ -132,8 +132,10 @@ class Item_func :public Item_result_field } bool is_null() { (void) val_int(); return null_value; } friend class udf_handler; + Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg); bool check_loop(uint id); + Item * get_tmp_table_item(); }; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index e087664e060b7302b17ca41ecf596528e526f66f..f397379b5be2fb50ac6311279a96b5ce8b29ffcf 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -288,6 +288,8 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex, compare_func_creator func) { DBUG_ENTER("Item_in_subselect::single_value_transformer"); + THD *thd= current_thd; + for (SELECT_LEX * sl= select_lex; sl; sl= sl->next_select()) { Item *item; @@ -301,12 +303,16 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex, Item *expr= new Item_outer_select_context_saver(left_expr); - if (sl->having || sl->with_sum_func || sl->group_list.first || - sl->order_list.first) + if (sl->having || sl->with_sum_func || sl->group_list.elements || + sl->order_list.elements) { sl->item_list.push_back(item); - item= (*func)(expr, new Item_ref(sl->item_list.head_ref(), - 0, (char*)"<result>")); + setup_ref_array(thd, &sl->ref_pointer_array, + 1+ select_lex->with_sum_func + + select_lex->order_list.elements + + select_lex->group_list.elements); + item= (*func)(expr, new Item_ref(sl->ref_pointer_array, + 0, (char*)"<result>")); if (sl->having || sl->with_sum_func || sl->group_list.first) if (sl->having) sl->having= new Item_cond_and(sl->having, item); @@ -348,7 +354,6 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex, // it is single select without tables => possible optimization item= (*func)(left_expr, item); substitution= item; - THD *thd= current_thd; if (thd->lex.describe) { char warn_buff[MYSQL_ERRMSG_SIZE]; @@ -424,8 +429,12 @@ int subselect_single_select_engine::prepare() prepared= 1; SELECT_LEX_NODE *save_select= thd->lex.current_select; thd->lex.current_select= select_lex; - if(join->prepare((TABLE_LIST*) select_lex->table_list.first, + if(join->prepare(&select_lex->ref_pointer_array, + (TABLE_LIST*) select_lex->table_list.first, + select_lex->with_wild, select_lex->where, + select_lex->order_list.elements + + select_lex->group_list.elements, (ORDER*) select_lex->order_list.first, (ORDER*) select_lex->group_list.first, select_lex->having, diff --git a/sql/item_sum.cc b/sql/item_sum.cc index a1f772f4d467db1a49876eed1adfb65cdec8a4ec..7e40dc9a94c0cc044d7578aecd7b96ba2073bcc8 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -41,9 +41,22 @@ Item_sum::Item_sum(List<Item> &list) list.empty(); // Fields are used } +Item_sum::Item_sum(Item_sum &item): + Item_result_field(item), quick_group(item.quick_group) +{ + arg_count= item.arg_count; + if (arg_count <= 2) + args=tmp_args; + else + if (!(args=(Item**) sql_alloc(sizeof(Item*)*arg_count))) + return; + for(uint i= 0; i < arg_count; i++) + args[i]= item.args[i]; +} + void Item_sum::mark_as_sum_func() { - current_thd->lex.current_select->with_sum_func=1; + current_thd->lex.current_select->with_sum_func++; with_sum_func= 1; } @@ -90,6 +103,26 @@ void Item_sum::fix_num_length_and_dec() max_length=float_length(decimals); } +Item * Item_sum::get_tmp_table_item() +{ + Item_sum* sum_item= (Item_sum *) get_same(); + if (sum_item && sum_item->result_field) // If not a const sum func + { + Field *result_field= sum_item->result_field; + for (uint i=0 ; i < sum_item->arg_count ; i++) + { + Item *arg= sum_item->args[i]; + if (!arg->const_item()) + { + if (arg->type() == Item::FIELD_ITEM) + ((Item_field*) arg)->field= result_field++; + else + sum_item->args[i]= new Item_field(result_field++); + } + } + } + return sum_item; +} String * Item_sum_num::val_str(String *str) @@ -933,7 +966,7 @@ int dump_leaf(byte* key, uint32 count __attribute__((unused)), The first item->rec_offset bytes are taken care of with restore_record(table,2) in setup() */ - memcpy(buf + item->rec_offset, key, item->tree.size_of_element); + memcpy(buf + item->rec_offset, key, item->tree->size_of_element); if ((error = item->table->file->write_row(buf))) { if (error != HA_ERR_FOUND_DUPP_KEY && @@ -946,11 +979,14 @@ int dump_leaf(byte* key, uint32 count __attribute__((unused)), Item_sum_count_distinct::~Item_sum_count_distinct() { - if (table) - free_tmp_table(current_thd, table); - delete tmp_table_param; - if (use_tree) - delete_tree(&tree); + if (!original) + { + if (table) + free_tmp_table(current_thd, table); + delete tmp_table_param; + if (use_tree) + delete_tree(tree); + } } @@ -1072,8 +1108,8 @@ bool Item_sum_count_distinct::setup(THD *thd) } } - init_tree(&tree, min(thd->variables.max_heap_table_size, - thd->variables.sortbuff_size/16), 0, + init_tree(tree, min(thd->variables.max_heap_table_size, + thd->variables.sortbuff_size/16), 0, key_length, compare_key, 0, NULL, cmp_arg); use_tree = 1; @@ -1085,6 +1121,12 @@ bool Item_sum_count_distinct::setup(THD *thd) */ max_elements_in_tree = ((key_length) ? thd->variables.max_heap_table_size/key_length : 1); + + } + if (original) + { + original->table= table; + original->use_tree= use_tree; } return 0; } @@ -1094,10 +1136,10 @@ int Item_sum_count_distinct::tree_to_myisam() { if (create_myisam_from_heap(current_thd, table, tmp_table_param, HA_ERR_RECORD_FILE_FULL, 1) || - tree_walk(&tree, (tree_walk_action)&dump_leaf, (void*)this, + tree_walk(tree, (tree_walk_action)&dump_leaf, (void*)this, left_root_right)) return 1; - delete_tree(&tree); + delete_tree(tree); use_tree = 0; return 0; } @@ -1105,7 +1147,7 @@ int Item_sum_count_distinct::tree_to_myisam() void Item_sum_count_distinct::reset() { if (use_tree) - reset_tree(&tree); + reset_tree(tree); else if (table) { table->file->extra(HA_EXTRA_NO_CACHE); @@ -1133,13 +1175,13 @@ bool Item_sum_count_distinct::add() If the tree got too big, convert to MyISAM, otherwise insert into the tree. */ - if (tree.elements_in_tree > max_elements_in_tree) + if (tree->elements_in_tree > max_elements_in_tree) { if (tree_to_myisam()) return 1; } - else if (!tree_insert(&tree, table->record[0] + rec_offset, 0, - tree.custom_arg)) + else if (!tree_insert(tree, table->record[0] + rec_offset, 0, + tree->custom_arg)) return 1; } else if ((error=table->file->write_row(table->record[0]))) @@ -1161,7 +1203,7 @@ longlong Item_sum_count_distinct::val_int() if (!table) // Empty query return LL(0); if (use_tree) - return tree.elements_in_tree; + return tree->elements_in_tree; table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); return table->file->records; } diff --git a/sql/item_sum.h b/sql/item_sum.h index 23b8482d41a644925ae103067fee374eacce49b7..5e561a05e644aaa243eb27f2e18644ec4090c706 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -54,6 +54,8 @@ class Item_sum :public Item_result_field mark_as_sum_func(); } Item_sum(List<Item> &list); + //Copy constructor, need to perform subselects with temporary tables + Item_sum(Item_sum &item); ~Item_sum() { result_field=0; } enum Type type() const { return SUM_FUNC_ITEM; } @@ -75,6 +77,7 @@ class Item_sum :public Item_result_field void print(String *str); void fix_num_length_and_dec(); virtual bool setup(THD *thd) {return 0;} + Item * get_tmp_table_item(); }; @@ -85,6 +88,7 @@ class Item_sum_num :public Item_sum Item_sum_num(Item *item_par) :Item_sum(item_par) {} Item_sum_num(Item *a, Item* b) :Item_sum(a,b) {} Item_sum_num(List<Item> &list) :Item_sum(list) {} + Item_sum_num(Item_sum_num &item) :Item_sum(item) {} bool fix_fields(THD *, TABLE_LIST *, Item **); longlong val_int() { return (longlong) val(); } /* Real as default */ String *val_str(String*str); @@ -100,6 +104,7 @@ class Item_sum_int :public Item_sum_num public: Item_sum_int(Item *item_par) :Item_sum_num(item_par) {} Item_sum_int(List<Item> &list) :Item_sum_num(list) {} + Item_sum_int(Item_sum_int &item) :Item_sum_num(item) {} double val() { return (double) val_int(); } String *val_str(String*str); enum Item_result result_type () const { return INT_RESULT; } @@ -113,6 +118,7 @@ class Item_sum_sum :public Item_sum_num public: Item_sum_sum(Item *item_par) :Item_sum_num(item_par),sum(0.0) {} + Item_sum_sum(Item_sum_sum &item) :Item_sum_num(item), sum(item.sum) {} enum Sumfunctype sum_func () const {return SUM_FUNC;} void reset(); bool add(); @@ -120,6 +126,7 @@ class Item_sum_sum :public Item_sum_num void reset_field(); void update_field(int offset); const char *func_name() const { return "sum"; } + Item * get_same() { return new Item_sum_sum(*this); } }; @@ -132,6 +139,10 @@ class Item_sum_count :public Item_sum_int Item_sum_count(Item *item_par) :Item_sum_int(item_par),count(0),used_table_cache(~(table_map) 0) {} + Item_sum_count(Item_sum_count &item): Item_sum_int(item), + count(item.count), + used_table_cache(item.used_table_cache) + {} table_map used_tables() const { return used_table_cache; } bool const_item() const { return !used_table_cache; } enum Sumfunctype sum_func () const { return COUNT_FUNC; } @@ -142,6 +153,7 @@ class Item_sum_count :public Item_sum_int void reset_field(); void update_field(int offset); const char *func_name() const { return "count"; } + Item * get_same() { return new Item_sum_count(*this); } }; @@ -154,7 +166,14 @@ class Item_sum_count_distinct :public Item_sum_int bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref); uint32 *field_lengths; TMP_TABLE_PARAM *tmp_table_param; - TREE tree; + TREE tree_base; + TREE *tree; + /* + Following is 0 normal object and pointer to original one for copy + (to correctly free resources) + */ + Item_sum_count_distinct *original; + uint key_length; // calculated based on max_heap_table_size. If reached, @@ -180,9 +199,19 @@ class Item_sum_count_distinct :public Item_sum_int public: Item_sum_count_distinct(List<Item> &list) - :Item_sum_int(list),table(0),used_table_cache(~(table_map) 0), - tmp_table_param(0),use_tree(0),always_null(0) - { quick_group=0; } + :Item_sum_int(list), table(0), used_table_cache(~(table_map) 0), + tmp_table_param(0), tree(&tree_base), original(0), use_tree(0), + always_null(0) + { quick_group= 0; } + Item_sum_count_distinct(Item_sum_count_distinct &item): + Item_sum_int(item), table(item.table), + used_table_cache(item.used_table_cache), + field_lengths(item.field_lengths), tmp_table_param(item.tmp_table_param), + tree(item.tree), original(&item), key_length(item.key_length), + max_elements_in_tree(item.max_elements_in_tree), + rec_offset(item.rec_offset), use_tree(item.use_tree), + always_null(item.always_null) + {} ~Item_sum_count_distinct(); table_map used_tables() const { return used_table_cache; } enum Sumfunctype sum_func () const { return COUNT_DISTINCT_FUNC; } @@ -193,6 +222,7 @@ class Item_sum_count_distinct :public Item_sum_int void update_field(int offset) { return ; } // Never called const char *func_name() const { return "count_distinct"; } bool setup(THD *thd); + Item * get_same() { return new Item_sum_count_distinct(*this); } }; @@ -224,6 +254,8 @@ class Item_sum_avg :public Item_sum_num public: Item_sum_avg(Item *item_par) :Item_sum_num(item_par),count(0) {} + Item_sum_avg(Item_sum_avg &item) + :Item_sum_num(item), sum(item.sum), count(item.count) {} enum Sumfunctype sum_func () const {return AVG_FUNC;} void reset(); bool add(); @@ -233,6 +265,7 @@ class Item_sum_avg :public Item_sum_num Item *result_item(Field *field) { return new Item_avg_field(this); } const char *func_name() const { return "avg"; } + Item * get_same() { return new Item_sum_avg(*this); } }; class Item_sum_std; @@ -260,6 +293,9 @@ class Item_sum_std :public Item_sum_num public: Item_sum_std(Item *item_par) :Item_sum_num(item_par),count(0) {} + Item_sum_std(Item_sum_std &item): + Item_sum_num(item), sum(item.sum), sum_sqr(item.sum_sqr), + count(item.count) {} enum Sumfunctype sum_func () const { return STD_FUNC; } void reset(); bool add(); @@ -269,6 +305,7 @@ class Item_sum_std :public Item_sum_num Item *result_item(Field *field) { return new Item_std_field(this); } const char *func_name() const { return "std"; } + Item * get_same() { return new Item_sum_std(*this); } }; @@ -288,6 +325,10 @@ class Item_sum_hybrid :public Item_sum Item_sum_hybrid(Item *item_par,int sign) :Item_sum(item_par),cmp_sign(sign), used_table_cache(~(table_map) 0) {} + Item_sum_hybrid(Item_sum_hybrid &item): + Item_sum(item), value(item.value), tmp_value(item.tmp_value), + sum(item.sum), sum_int(item.sum_int), hybrid_type(item.hybrid_type), + cmp_sign(item.cmp_sign), used_table_cache(used_table_cache) {} bool fix_fields(THD *, TABLE_LIST *, Item **); table_map used_tables() const { return used_table_cache; } bool const_item() const { return !used_table_cache; } @@ -318,10 +359,12 @@ class Item_sum_min :public Item_sum_hybrid { public: Item_sum_min(Item *item_par) :Item_sum_hybrid(item_par,1) {} + Item_sum_min(Item_sum_min &item) :Item_sum_hybrid(item) {} enum Sumfunctype sum_func () const {return MIN_FUNC;} bool add(); const char *func_name() const { return "min"; } + Item * get_same() { return new Item_sum_min(*this); } }; @@ -329,10 +372,12 @@ class Item_sum_max :public Item_sum_hybrid { public: Item_sum_max(Item *item_par) :Item_sum_hybrid(item_par,-1) {} + Item_sum_max(Item_sum_max &item) :Item_sum_hybrid(item) {} enum Sumfunctype sum_func () const {return MAX_FUNC;} bool add(); const char *func_name() const { return "max"; } + Item * get_same() { return new Item_sum_max(*this); } }; @@ -344,6 +389,8 @@ class Item_sum_bit :public Item_sum_int public: Item_sum_bit(Item *item_par,ulonglong reset_arg) :Item_sum_int(item_par),reset_bits(reset_arg),bits(reset_arg) {} + Item_sum_bit(Item_sum_bit &item): + Item_sum_int(item), reset_bits(item.reset_bits), bits(item.bits) {} enum Sumfunctype sum_func () const {return SUM_BIT_FUNC;} void reset(); longlong val_int(); @@ -355,9 +402,11 @@ class Item_sum_or :public Item_sum_bit { public: Item_sum_or(Item *item_par) :Item_sum_bit(item_par,LL(0)) {} + Item_sum_or(Item_sum_or &item) :Item_sum_bit(item) {} bool add(); void update_field(int offset); const char *func_name() const { return "bit_or"; } + Item * get_same() { return new Item_sum_or(*this); } }; @@ -365,9 +414,11 @@ class Item_sum_and :public Item_sum_bit { public: Item_sum_and(Item *item_par) :Item_sum_bit(item_par, ~(ulonglong) LL(0)) {} + Item_sum_and(Item_sum_and &item) :Item_sum_bit(item) {} bool add(); void update_field(int offset); const char *func_name() const { return "bit_and"; } + Item * get_same() { return new Item_sum_and(*this); } }; /* @@ -385,6 +436,7 @@ class Item_udf_sum : public Item_sum Item_udf_sum( udf_func *udf_arg, List<Item> &list ) :Item_sum( list ), udf(udf_arg) { quick_group=0;} + Item_udf_sum(Item_udf_sum &item) :Item_sum(item), udf(item.udf) {} ~Item_udf_sum() {} const char *func_name() const { return udf.name(); } bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) @@ -408,11 +460,13 @@ class Item_sum_udf_float :public Item_udf_sum Item_sum_udf_float(udf_func *udf_arg) :Item_udf_sum(udf_arg) {} Item_sum_udf_float(udf_func *udf_arg, List<Item> &list) :Item_udf_sum(udf_arg,list) {} + Item_sum_udf_float(Item_sum_udf_float &item): Item_udf_sum(item) {} ~Item_sum_udf_float() {} longlong val_int() { return (longlong) Item_sum_udf_float::val(); } double val(); String *val_str(String*str); void fix_length_and_dec() { fix_num_length_and_dec(); } + Item * get_same() { return new Item_sum_udf_float(*this); } }; @@ -422,12 +476,14 @@ class Item_sum_udf_int :public Item_udf_sum Item_sum_udf_int(udf_func *udf_arg) :Item_udf_sum(udf_arg) {} Item_sum_udf_int(udf_func *udf_arg, List<Item> &list) :Item_udf_sum(udf_arg,list) {} + Item_sum_udf_int(Item_sum_udf_int &item): Item_udf_sum(item) {} ~Item_sum_udf_int() {} longlong val_int(); double val() { return (double) Item_sum_udf_int::val_int(); } String *val_str(String*str); enum Item_result result_type () const { return INT_RESULT; } void fix_length_and_dec() { decimals=0; max_length=21; } + Item * get_same() { return new Item_sum_udf_int(*this); } }; @@ -437,6 +493,7 @@ class Item_sum_udf_str :public Item_udf_sum Item_sum_udf_str(udf_func *udf_arg) :Item_udf_sum(udf_arg) {} Item_sum_udf_str(udf_func *udf_arg, List<Item> &list) :Item_udf_sum(udf_arg,list) {} + Item_sum_udf_str(Item_sum_udf_str &item): Item_udf_sum(item) {} ~Item_sum_udf_str() {} String *val_str(String *); double val() @@ -451,6 +508,7 @@ class Item_sum_udf_str :public Item_udf_sum } enum Item_result result_type () const { return STRING_RESULT; } void fix_length_and_dec(); + Item * get_same() { return new Item_sum_udf_str(*this); } }; #else /* Dummy functions to get sql_yacc.cc compiled */ @@ -460,12 +518,14 @@ class Item_sum_udf_float :public Item_sum_num public: Item_sum_udf_float(udf_func *udf_arg) :Item_sum_num() {} Item_sum_udf_float(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {} + Item_sum_udf_float(Item_sum_udf_float &item): Item_sum_num(item) {} ~Item_sum_udf_float() {} enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } double val() { return 0.0; } void reset() {} bool add() { return 0; } void update_field(int offset) {} + Item * get_same() { return new Item_sum_udf_float(*this); } }; @@ -474,6 +534,7 @@ class Item_sum_udf_int :public Item_sum_num public: Item_sum_udf_int(udf_func *udf_arg) :Item_sum_num() {} Item_sum_udf_int(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {} + Item_sum_udf_int(Item_sum_udf_int &item): Item_sum_num(item) {} ~Item_sum_udf_int() {} enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } longlong val_int() { return 0; } @@ -481,6 +542,7 @@ class Item_sum_udf_int :public Item_sum_num void reset() {} bool add() { return 0; } void update_field(int offset) {} + Item * get_same() { return new Item_sum_udf_int(*this); } }; @@ -489,6 +551,7 @@ class Item_sum_udf_str :public Item_sum_num public: Item_sum_udf_str(udf_func *udf_arg) :Item_sum_num() {} Item_sum_udf_str(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {} + Item_sum_udf_str(Item_sum_udf_str &item): Item_sum_num(item) {} ~Item_sum_udf_str() {} String *val_str(String *) { null_value=1; return 0; } double val() { null_value=1; return 0.0; } @@ -499,6 +562,7 @@ class Item_sum_udf_str :public Item_sum_num void reset() {} bool add() { return 0; } void update_field(int offset) {} + Item * get_same() { return new Item_sum_udf_str(*this); } }; #endif /* HAVE_DLOPEN */ diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 40397351c18e05ed229fa4affd61aa47d687689b..5b968ed80ebdba4ec6d545398a1524f6c886dd46 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -330,9 +330,10 @@ class Item_date :public Item_func { init_make_field(tmp_field,FIELD_TYPE_DATE); } + Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { - return (!t_arg) ? result_field : new Field_date(maybe_null, name, t_arg, thd_charset()); + return (new Field_date(maybe_null, name, t_arg, thd_charset())); } }; @@ -347,10 +348,10 @@ class Item_date_func :public Item_str_func { init_make_field(tmp_field,FIELD_TYPE_DATETIME); } + Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { - return (!t_arg) ? result_field : new Field_datetime(maybe_null, name, - t_arg, thd_charset()); + return (new Field_datetime(maybe_null, name, t_arg, thd_charset())); } }; @@ -373,10 +374,10 @@ class Item_func_curtime :public Item_func { init_make_field(tmp_field,FIELD_TYPE_TIME); } + Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { - return (!t_arg) ? result_field : - new Field_time(maybe_null, name, t_arg, thd_charset()); + return (new Field_time(maybe_null, name, t_arg, thd_charset())); } }; @@ -475,10 +476,10 @@ class Item_func_sec_to_time :public Item_str_func { init_make_field(tmp_field,FIELD_TYPE_TIME); } + Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { - return (!t_arg) ? result_field : - new Field_time(maybe_null, name, t_arg, thd_charset()); + return (new Field_time(maybe_null, name, t_arg, thd_charset())); } }; @@ -570,10 +571,10 @@ class Item_date_typecast :public Item_typecast { init_make_field(tmp_field,FIELD_TYPE_DATE); } + Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { - return (!t_arg) ? result_field : - new Field_date(maybe_null, name, t_arg, thd_charset()); + return (new Field_date(maybe_null, name, t_arg, thd_charset())); } }; @@ -587,10 +588,10 @@ class Item_time_typecast :public Item_typecast { init_make_field(tmp_field,FIELD_TYPE_TIME); } + Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { - return (!t_arg) ? result_field : - new Field_time(maybe_null, name, t_arg, thd_charset()); + return (new Field_time(maybe_null, name, t_arg, thd_charset())); } }; @@ -604,9 +605,9 @@ class Item_datetime_typecast :public Item_typecast { init_make_field(tmp_field,FIELD_TYPE_DATETIME); } + Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { - return (!t_arg) ? result_field : new Field_datetime(maybe_null, name, - t_arg, thd_charset()); + return (new Field_datetime(maybe_null, name, t_arg, thd_charset())); } }; diff --git a/sql/item_uniq.h b/sql/item_uniq.h index 2004be63de2b9fc89d2ddd7470205e206e18382b..9098dfe7d41a0b01d9f8ef5fe365c605293d29bc 100644 --- a/sql/item_uniq.h +++ b/sql/item_uniq.h @@ -37,6 +37,7 @@ class Item_sum_unique_users :public Item_sum_num public: Item_sum_unique_users(Item *name_arg,int start,int end,Item *item_arg) :Item_sum_num(item_arg) {} + Item_sum_unique_users(Item_sum_unique_users &item): Item_sum_num(item) {} double val() { return 0.0; } enum Sumfunctype sum_func () const {return UNIQUE_USERS_FUNC;} void reset() {} @@ -48,4 +49,5 @@ class Item_sum_unique_users :public Item_sum_num fixed= 1; return 0; } + Item_sum * get_same() { return new Item_sum_unique_users(*this); } }; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 771d105a1c7f7df7d3f61818673909910713959c..b9cd99624ea4abf3b7f7a0343e472744bde67cc4 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -402,18 +402,21 @@ bool net_store_data(String *packet,CONVERT *convert, const char *from, bool net_store_data(String *packet, CONVERT *convert, const char *from); SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length); -int setup_order(THD *thd,TABLE_LIST *tables, List<Item> &fields, - List <Item> &all_fields, ORDER *order); -int setup_group(THD *thd,TABLE_LIST *tables,List<Item> &fields, - List<Item> &all_fields, ORDER *order, +int setup_ref_array(THD *thd, Item ***rref_pointer_array, uint elements); +int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, + List<Item> &fields, List <Item> &all_fields, ORDER *order); +int setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, + List<Item> &fields, List<Item> &all_fields, ORDER *order, bool *hidden_group_fields); int handle_select(THD *thd, LEX *lex, select_result *result); -int mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &list,COND *conds, - ORDER *order, ORDER *group,Item *having,ORDER *proc_param, - ulong select_type,select_result *result, - SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex, - bool fake_select_lex); +int mysql_select(THD *thd, Item ***rref_pointer_array, + TABLE_LIST *tables, uint wild_num, List<Item> &list, + COND *conds, uint og_num, ORDER *order, ORDER *group, + Item *having, ORDER *proc_param, ulong select_type, + select_result *result, SELECT_LEX_UNIT *unit, + SELECT_LEX *select_lex, bool fake_select_lex); +void free_ulderlayed_joins(THD *thd, SELECT_LEX *select); void fix_tables_pointers(SELECT_LEX *select_lex); int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result); @@ -440,7 +443,7 @@ int mysql_alter_table(THD *thd, char *new_db, char *new_name, List<create_field> &fields, List<Key> &keys,List<Alter_drop> &drop_list, List<Alter_column> &alter_list, - ORDER *order, + uint order_num, ORDER *order, bool drop_primary, enum enum_duplicates handle_duplicates, enum enum_enable_or_disable keys_onoff=LEAVE_AS_IS, @@ -456,7 +459,7 @@ int mysql_drop_index(THD *thd, TABLE_LIST *table_list, List<Alter_drop> &drop_list); int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields, List<Item> &values,COND *conds, - ORDER *order, ha_rows limit, + uint order_num, ORDER *order, ha_rows limit, enum enum_duplicates handle_duplicates); int mysql_multi_update(THD *thd, TABLE_LIST *table_list, List<Item> *fields, List<Item> *values, @@ -575,15 +578,17 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables, enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND, IGNORE_ERRORS}; extern const Item **not_found_item; -Item ** find_item_in_list(Item *item, List<Item> &items, +Item ** find_item_in_list(Item *item, List<Item> &items, uint *counter, find_item_error_report_type report_error); bool insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, const char *table_name, List_iterator<Item> *it); bool setup_tables(TABLE_LIST *tables); -int setup_fields(THD *thd,TABLE_LIST *tables,List<Item> &item, - bool set_query_id,List<Item> *sum_func_list, - bool allow_sum_func); +int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, + List<Item> *sum_func_list, uint wild_num); +int setup_fields(THD *thd, Item** ref_pointer_array, TABLE_LIST *tables, + List<Item> &item, bool set_query_id, + List<Item> *sum_func_list, bool allow_sum_func); int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds); int setup_ftfuncs(SELECT_LEX* select); int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index e2b36106fb0d661047862ade3fbccff99b56bffd..870c341c148d2f4eede8b98ca14e5033ca8482ec 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2012,11 +2012,15 @@ const Item **not_found_item= (const Item**) 0x1; /* Find Item in list of items (find_field_in_tables analog) - + + TODO + is it better return only counter? + SYNOPSIS find_item_in_list() find - item to find items - list of items + counter - to return number of found item report_error REPORT_ALL_ERRORS - report errors, return 0 if error REPORT_EXCEPT_NOT_FOUND - do not report 'not found' error and return not_ found_item, report other errors, return 0 @@ -2033,7 +2037,7 @@ const Item **not_found_item= (const Item**) 0x1; */ Item ** -find_item_in_list(Item *find, List<Item> &items, +find_item_in_list(Item *find, List<Item> &items, uint *counter, find_item_error_report_type report_error) { List_iterator<Item> li(items); @@ -2046,8 +2050,10 @@ find_item_in_list(Item *find, List<Item> &items, table_name= ((Item_ident*) find)->table_name; } + uint i= 0; while ((item=li++)) { + i++; if (field_name && item->type() == Item::FIELD_ITEM) { if (!my_strcasecmp(system_charset_info, @@ -2064,11 +2070,13 @@ find_item_in_list(Item *find, List<Item> &items, find->full_name(), current_thd->where); return (Item**) 0; } - found=li.ref(); + found= li.ref(); + *counter= i; } else if (!strcmp(((Item_field*) item)->table_name,table_name)) { - found=li.ref(); + found= li.ref(); + *counter= i; break; } } @@ -2078,7 +2086,8 @@ find_item_in_list(Item *find, List<Item> &items, !my_strcasecmp(system_charset_info, item->name,find->name))) { - found=li.ref(); + found= li.ref(); + *counter= i; break; } } @@ -2096,30 +2105,26 @@ find_item_in_list(Item *find, List<Item> &items, } /**************************************************************************** -** Check that all given fields exists and fill struct with current data +** Expand all '*' in given fields ****************************************************************************/ -int setup_fields(THD *thd, TABLE_LIST *tables, List<Item> &fields, - bool set_query_id, List<Item> *sum_func_list, - bool allow_sum_func) +int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, + List<Item> *sum_func_list, + uint wild_num) { + if (!wild_num) + return 0; reg2 Item *item; List_iterator<Item> it(fields); - DBUG_ENTER("setup_fields"); - - thd->set_query_id=set_query_id; - thd->allow_sum_func= allow_sum_func; - thd->where="field list"; - - while ((item=it++)) - { + while ( wild_num && (item= it++)) + { if (item->type() == Item::FIELD_ITEM && ((Item_field*) item)->field_name && ((Item_field*) item)->field_name[0] == '*') { uint elem= fields.elements; if (insert_fields(thd,tables,((Item_field*) item)->db_name, ((Item_field*) item)->table_name, &it)) - DBUG_RETURN(-1); /* purecov: inspected */ + return (-1); if (sum_func_list) { /* @@ -2129,22 +2134,43 @@ int setup_fields(THD *thd, TABLE_LIST *tables, List<Item> &fields, */ sum_func_list->elements+= fields.elements - elem; } - } - else - { - if (item->check_cols(1) || - item->fix_fields(thd, tables, it.ref())) - DBUG_RETURN(-1); /* purecov: inspected */ - item= *(it.ref()); //Item can be chenged in fix fields - if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM && - sum_func_list) - item->split_sum_func(*sum_func_list); - thd->used_tables|=item->used_tables(); + wild_num--; } } - DBUG_RETURN(test(thd->fatal_error || thd->net.report_error)); + return 0; } +/**************************************************************************** +** Check that all given fields exists and fill struct with current data +****************************************************************************/ + +int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, + List<Item> &fields, bool set_query_id, + List<Item> *sum_func_list, bool allow_sum_func) +{ + reg2 Item *item; + List_iterator<Item> it(fields); + DBUG_ENTER("setup_fields"); + + thd->set_query_id=set_query_id; + thd->allow_sum_func= allow_sum_func; + thd->where="field list"; + + for (uint i= 0; (item= it++); i++) + { + if (item->check_cols(1) || + item->fix_fields(thd, tables, it.ref())) + DBUG_RETURN(-1); /* purecov: inspected */ + item= *(it.ref()); //Item can be chenged in fix fields + if (ref_pointer_array) + ref_pointer_array[i]= item; + if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM && + sum_func_list) + item->split_sum_func(ref_pointer_array, *sum_func_list); + thd->used_tables|=item->used_tables(); + } + DBUG_RETURN(test(thd->fatal_error || thd->net.report_error)); +} /* Remap table numbers if INSERT ... SELECT @@ -2459,7 +2485,7 @@ int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys) create_info.table_charset=default_charset_info; DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name, &create_info, table_list, - fields, keys, drop, alter, (ORDER*)0, FALSE, + fields, keys, drop, alter, 0, (ORDER*)0, FALSE, DUP_ERROR)); } @@ -2476,7 +2502,7 @@ int mysql_drop_index(THD *thd, TABLE_LIST *table_list, List<Alter_drop> &drop) create_info.table_charset=default_charset_info; DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name, &create_info, table_list, - fields, keys, drop, alter, (ORDER*)0, FALSE, + fields, keys, drop, alter, 0, (ORDER*)0, FALSE, DUP_ERROR)); } diff --git a/sql/sql_class.h b/sql/sql_class.h index ca56d2dcdf5941c28398536ed7df2e7767939059..38a96d1af660a38dc77f959b07813082c0bde4de 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -376,7 +376,7 @@ struct system_variables CONVERT *convert_set; }; - +void free_tmp_table(THD *thd, TABLE *entry); /* For each client connection we create a separate thread with THD serving as a thread/connection descriptor @@ -486,6 +486,7 @@ class THD :public ilink { CHARSET_INFO *db_charset; CHARSET_INFO *thd_charset; List<Item> *possible_loops; // Items that may cause loops in subselects + List<TABLE> temporary_tables_should_be_free; // list of temporary tables List <MYSQL_ERROR> warn_list; uint warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END]; uint total_warn_count, old_total_warn_count; @@ -640,6 +641,17 @@ class THD :public ilink { net.report_error= 0; } void add_possible_loop(Item *); + void free_tmp_tables() + { + if (temporary_tables_should_be_free.elements) + { + List_iterator_fast<TABLE> lt(temporary_tables_should_be_free); + TABLE *table; + while ((table= lt++)) + free_tmp_table(this,table); + temporary_tables_should_be_free.empty(); + } + } }; /* diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 88da3e2505ce6907e4572d87bee329121d8d7229..bb1eb1e1dd2e22d15490bd11060641aa2ae3a252 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -92,6 +92,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order, if ((select && select->check_quick(safe_update, limit)) || !limit) { delete select; + free_ulderlayed_joins(thd, &thd->lex.select_lex); send_ok(thd,0L); DBUG_RETURN(0); // Nothing to delete } @@ -103,6 +104,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order, if (safe_update && !using_limit) { delete select; + free_ulderlayed_joins(thd, &thd->lex.select_lex); send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE); DBUG_RETURN(1); } @@ -124,7 +126,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order, table->io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE), MYF(MY_FAE | MY_ZEROFILL)); - if (setup_order(thd, &tables, fields, all_fields, order) || + if (setup_order(thd, 0, &tables, fields, all_fields, order) || !(sortorder=make_unireg_sortorder(order, &length)) || (table->found_records = filesort(thd, table, sortorder, length, (SQL_SELECT *) 0, HA_POS_ERROR, @@ -132,6 +134,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order, == HA_POS_ERROR) { delete select; + free_ulderlayed_joins(thd, &thd->lex.select_lex); DBUG_RETURN(-1); // This will force out message } } @@ -207,6 +210,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order, thd->lock=0; } delete select; + free_ulderlayed_joins(thd, &thd->lex.select_lex); if (error >= 0 || thd->net.report_error) send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN: 0); else diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index f0df681113395886f58e36a0648211506fa2e738..2949dae3985bbceb5596a7d7097efc407a14930b 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -58,7 +58,8 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t) if (!(res=open_and_lock_tables(thd,tables))) { - if (setup_fields(thd,tables,item_list,0,0,1)) + if (setup_wild(thd, tables, item_list, 0, sl->with_wild) || + setup_fields(thd, 0, tables, item_list, 0, 0, 1)) { res=-1; goto exit; @@ -87,9 +88,11 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t) SELECT_LEX_NODE *save_current_select= lex->current_select; lex->current_select= sl; - res= mysql_select(thd, tables, sl->item_list, - sl->where, (ORDER *) sl->order_list.first, - (ORDER*) sl->group_list.first, + res= mysql_select(thd, &sl->ref_pointer_array, tables, sl->with_wild, + sl->item_list, sl->where, + sl->order_list.elements+sl->group_list.elements, + (ORDER *) sl->order_list.first, + (ORDER *) sl->group_list.first, sl->having, (ORDER*) NULL, sl->options | thd->options | SELECT_NO_UNLOCK, derived_result, unit, sl, 0); @@ -122,6 +125,8 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t) } if (res) free_tmp_table(thd,table); + else + thd->temporary_tables_should_be_free.push_front(table); exit: close_thread_tables(thd); } diff --git a/sql/sql_do.cc b/sql/sql_do.cc index 2eef088da5b0894ff8ef4f4c0b34a86498ed5e4a..f25c4632e1e26c882fc716ff4e12a6b5d2bab5f0 100644 --- a/sql/sql_do.cc +++ b/sql/sql_do.cc @@ -25,7 +25,7 @@ int mysql_do(THD *thd, List<Item> &values) List_iterator<Item> li(values); Item *value; DBUG_ENTER("mysql_do"); - if (setup_fields(thd,0, values, 0, 0, 0)) + if (setup_fields(thd, 0, 0, values, 0, 0, 0)) DBUG_RETURN(-1); while ((value = li++)) value->val_int(); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index f45e09cf0bf464aad6f1f9b839ba290cf44844c0..8d5727d9eb1a8dce62318d4818e7640f74110a0c 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -81,7 +81,7 @@ check_insert_fields(THD *thd,TABLE *table,List<Item> &fields, thd->dupp_field=0; if (setup_tables(&table_list) || - setup_fields(thd,&table_list,fields,1,0,0)) + setup_fields(thd, 0, &table_list,fields,1,0,0)) return -1; if (thd->dupp_field) { @@ -171,10 +171,10 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, values= its++; if (check_insert_fields(thd,table,fields,*values,1) || setup_tables(insert_table_list) || - setup_fields(thd, insert_table_list, *values, 0, 0, 0) || + setup_fields(thd, 0, insert_table_list, *values, 0, 0, 0) || (duplic == DUP_UPDATE && - (setup_fields(thd, insert_table_list, update_fields, 0, 0, 0) || - setup_fields(thd, insert_table_list, update_values, 0, 0, 0)))) + (setup_fields(thd, 0, insert_table_list, update_fields, 0, 0, 0) || + setup_fields(thd, 0, insert_table_list, update_values, 0, 0, 0)))) goto abort; if (find_real_table_in_list(table_list->next, table_list->db, table_list->real_name)) @@ -194,7 +194,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, MYF(0),counter); goto abort; } - if (setup_fields(thd,insert_table_list,*values,0,0,0)) + if (setup_fields(thd, 0, insert_table_list, *values, 0, 0, 0)) goto abort; } its.rewind (); @@ -381,11 +381,13 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, thd->cuted_fields); ::send_ok(thd,info.copied+info.deleted,(ulonglong)id,buff); } + free_ulderlayed_joins(thd, &thd->lex.select_lex); DBUG_RETURN(0); abort: if (lock_type == TL_WRITE_DELAYED) end_delayed_insert(thd); + free_ulderlayed_joins(thd, &thd->lex.select_lex); DBUG_RETURN(-1); } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 833f36dbe9f9bba150a4dd9a781964143bd45ae4..0da47b1264975d0616d5ae6c257b0aee2b0897eb 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -944,6 +944,7 @@ void st_select_lex_node::init_query() next= master= slave= link_next= 0; prev= link_prev= 0; dependent= 0; + ref_pointer_array= 0; } void st_select_lex_node::init_select() @@ -967,6 +968,8 @@ void st_select_lex_unit::init_query() union_option= 0; prepared= optimized= executed= 0; item= 0; + union_result= 0; + table= 0; } void st_select_lex::init_query() @@ -979,6 +982,7 @@ void st_select_lex::init_query() join= 0; olap= UNSPECIFIED_OLAP_TYPE; having_fix_field= 0; + with_wild= 0; } void st_select_lex::init_select() @@ -1105,12 +1109,12 @@ bool st_select_lex_node::add_item_to_list(THD *thd, Item *item) bool st_select_lex_node::add_group_to_list(THD *thd, Item *item, bool asc) { - return 1; + return 1; } bool st_select_lex_node::add_order_to_list(THD *thd, Item *item, bool asc) -{ - return add_to_list(thd, order_list,item,asc); +{ + return add_to_list(thd, order_list, item, asc); } bool st_select_lex_node::add_ftfunc_to_list(Item_func_match *func) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 0c761baffa3cf71255352e8f095962aec657e386..a8d55ec91d5e198ceb0339bbbdcef705b520f206 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -208,8 +208,11 @@ class st_select_lex_node { List<List_item> expr_list; List<List_item> when_list; /* WHEN clause (expression) */ ha_rows select_limit, offset_limit; /* LIMIT clause parameters */ - bool with_sum_func; - bool create_refs; + // Arrays of pointers to top elements of all_fields list + Item **ref_pointer_array; + + uint with_sum_func; /* sum function indicator and number of it */ + bool create_refs; bool dependent; /* dependent from outer select subselect */ static void *operator new(size_t size) @@ -269,11 +272,10 @@ class select_union; class st_select_lex_unit: public st_select_lex_node { protected: List<Item> item_list; - List<JOIN*> joins; /* list of *JOINs, to delete it in cleanup() */ TABLE_LIST result_table_list; select_union *union_result; TABLE *table; /* temporary table using for appending UNION results */ - THD *thd; + select_result *result; int res; bool describe, found_rows_for_union, @@ -290,6 +292,8 @@ class st_select_lex_unit: public st_select_lex_node { ha_rows select_limit_cnt, offset_limit_cnt; /* not NULL if union used in subselect, point to subselect item */ Item_subselect *item; + THD *thd; + uint union_option; void init_query(); @@ -336,6 +340,7 @@ class st_select_lex: public st_select_lex_node const char *type; /* type of select for EXPLAIN */ uint in_sum_expr; uint select_number; /* number of select (used for EXPLAIN) */ + uint with_wild; /* item list contain '*' */ bool braces; /* SELECT ... UNION (SELECT ... ) <- this braces */ /* TRUE when having fix field called in processing of this SELECT */ bool having_fix_field; diff --git a/sql/sql_list.h b/sql/sql_list.h index 56e6528f214d55b4a6c33466b2aaa07dc71f1a60..c9f569accf6b0113155899fd35affacc6b6ca11c 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -147,12 +147,20 @@ class base_list :public Sql_alloc { class base_list_iterator { +protected: base_list *list; list_node **el,**prev,*current; + void sublist(base_list &ls, uint elm) + { + ls.first= *el; + ls.last= list->last; + ls.elements= elm; + } public: - base_list_iterator(base_list &list_par) :list(&list_par),el(&list_par.first), - prev(0),current(0) + base_list_iterator(base_list &list_par) + :list(&list_par), el(&list_par.first), prev(0), current(0) {} + inline void *next(void) { prev=el; @@ -212,7 +220,6 @@ class base_list_iterator friend class error_list_iterator; }; - template <class T> class List :public base_list { public: @@ -260,6 +267,10 @@ template <class T> class List_iterator_fast :public base_list_iterator List_iterator_fast(List<T> &a) : base_list_iterator(a) {} inline T* operator++(int) { return (T*) base_list_iterator::next_fast(); } inline void rewind(void) { base_list_iterator::rewind(); } + void sublist(List<T> &list, uint el) + { + base_list_iterator::sublist(list, el); + } }; diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 00450a3b86cc040b3b3d6da600ac045ae1525c6d..2e059612014e784879db771c91f6dc90fde328e6 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -117,7 +117,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, else { // Part field list thd->dupp_field=0; - if (setup_tables(table_list) || setup_fields(thd,table_list,fields,1,0,0)) + if (setup_tables(table_list) || + setup_fields(thd, 0, table_list, fields, 1, 0, 0)) DBUG_RETURN(-1); if (thd->dupp_field) { diff --git a/sql/sql_olap.cc b/sql/sql_olap.cc index 6eb4fbcaaf674d4fdd3ccbd992f8bfce30dea33a..93dff84bf0b50f7f2702670ab4c6cb85f608cb5d 100644 --- a/sql/sql_olap.cc +++ b/sql/sql_olap.cc @@ -164,8 +164,10 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex) if (setup_tables((TABLE_LIST *)select_lex->table_list.first) || - setup_fields(lex->thd,(TABLE_LIST *)select_lex->table_list.first,select_lex->item_list,1,&all_fields,1) || - setup_fields(lex->thd,(TABLE_LIST *)select_lex->table_list.first,item_list_copy,1,&all_fields,1)) + setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first, + select_lex->item_list, 1, &all_fields,1) || + setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first, + item_list_copy, 1, &all_fields, 1)) return -1; if (select_lex->olap == CUBE_TYPE) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 90568bfcc5e2f89c49962d5714456a671c99918e..b608221e7f04c0d08c50900543b0675eac49ddef 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1915,6 +1915,7 @@ mysql_execute_command(THD *thd) &lex->create_info, tables, lex->create_list, lex->key_list, lex->drop_list, lex->alter_list, + select_lex->order_list.elements, (ORDER *) select_lex->order_list.first, lex->drop_primary, lex->duplicates, lex->alter_keys_onoff, lex->simple_alter); @@ -2026,8 +2027,8 @@ mysql_execute_command(THD *thd) res= mysql_alter_table(thd, NullS, NullS, &create_info, tables, lex->create_list, lex->key_list, lex->drop_list, lex->alter_list, - (ORDER *) 0, - 0,DUP_ERROR); + 0, (ORDER *) 0, + 0, DUP_ERROR); } else res = mysql_optimize_table(thd, tables, &lex->check_opt); @@ -2047,6 +2048,7 @@ mysql_execute_command(THD *thd) select_lex->item_list, lex->value_list, select_lex->where, + select_lex->order_list.elements, (ORDER *) select_lex->order_list.first, select_lex->select_limit, lex->duplicates); @@ -2246,10 +2248,12 @@ mysql_execute_command(THD *thd) if (!thd->fatal_error && (result= new multi_delete(thd,aux_tables, table_count))) { - res= mysql_select(thd,select_lex->get_table_list(), + res= mysql_select(thd, &select_lex->ref_pointer_array, + select_lex->get_table_list(), + select_lex->with_wild, select_lex->item_list, select_lex->where, - (ORDER *)NULL,(ORDER *)NULL,(Item *)NULL, + 0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL, (ORDER *)NULL, select_lex->options | thd->options | SELECT_NO_JOIN_CACHE, @@ -2741,6 +2745,7 @@ mysql_execute_command(THD *thd) send_ok(thd); break; } + thd->free_tmp_tables(); thd->proc_info="query end"; // QQ if (res < 0) send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0); @@ -2988,6 +2993,7 @@ mysql_init_query(THD *thd) LEX *lex=&thd->lex; lex->unit.init_query(); lex->unit.init_select(); + lex->unit.thd= thd; lex->select_lex.init_query(); lex->value_list.empty(); lex->param_list.empty(); @@ -3044,6 +3050,7 @@ mysql_new_select(LEX *lex, bool move_down) return 1; unit->init_query(); unit->init_select(); + unit->thd= lex->thd; unit->include_down(lex->current_select); select_lex->include_down(unit); } diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 9d6e6d75ade4fef8ced00ce1c9c1c136c105cc69..6af2528074c12f919e56c2fdfbeb64d2a93fb1a7 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -365,7 +365,7 @@ static int check_prepare_fields(THD *thd,TABLE *table, List<Item> &fields, thd->dupp_field=0; if (setup_tables(&table_list) || - setup_fields(thd,&table_list,fields,1,0,0)) + setup_fields(thd, 0, &table_list, fields, 1, 0, 0)) return -1; if (thd->dupp_field) { @@ -446,8 +446,9 @@ static bool mysql_test_upd_fields(PREP_STMT *stmt, TABLE_LIST *table_list, if (!(table = open_ltable(thd,table_list,table_list->lock_type))) DBUG_RETURN(1); - if (setup_tables(table_list) || setup_fields(thd,table_list,fields,1,0,0) || - setup_conds(thd,table_list,&conds)) + if (setup_tables(table_list) || + setup_fields(thd, 0, table_list, fields, 1, 0, 0) || + setup_conds(thd, table_list, &conds)) DBUG_RETURN(1); /* @@ -488,10 +489,11 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables, thd->used_tables=0; // Updated by setup_fields if (setup_tables(tables) || - setup_fields(thd,tables,fields,1,&all_fields,1) || + setup_fields(thd, 0, tables,fields,1,&all_fields,1) || setup_conds(thd,tables,&conds) || - setup_order(thd,tables,fields,all_fields,order) || - setup_group(thd,tables,fields,all_fields,group,&hidden_group_fields)) + setup_order(thd, 0, tables, fields, all_fields, order) || + setup_group(thd, 0, tables, fields, all_fields, group, + &hidden_group_fields)) DBUG_RETURN(1); if (having) @@ -502,7 +504,7 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables, || thd->fatal_error) DBUG_RETURN(1); if (having->with_sum_func) - having->split_sum_func(all_fields); + having->split_sum_func(0, all_fields); } if (setup_ftfuncs(&thd->lex.select_lex)) DBUG_RETURN(1); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 5b8e20859825649914141bc1947f383a41b1143d..50bea2376c3e205406ad9039f6e4cc00779fe415 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -58,7 +58,7 @@ static bool make_simple_join(JOIN *join,TABLE *tmp_table); static bool make_join_select(JOIN *join,SQL_SELECT *select,COND *item); static void make_join_readinfo(JOIN *join,uint options); static void join_free(JOIN *join, bool full); -static bool only_eq_ref_tables(JOIN *join,ORDER *order,table_map tables); +static bool only_eq_ref_tables(JOIN *join, ORDER *order, table_map tables); static void update_depend_map(JOIN *join); static void update_depend_map(JOIN *join, ORDER *order); static ORDER *remove_const(JOIN *join,ORDER *first_order,COND *cond, @@ -140,8 +140,16 @@ static TABLE *get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables); static void calc_group_buffer(JOIN *join,ORDER *group); static bool alloc_group_fields(JOIN *join,ORDER *group); static bool make_sum_func_list(JOIN *join,List<Item> &fields); -static bool change_to_use_tmp_fields(List<Item> &func); -static bool change_refs_to_tmp_fields(THD *thd, List<Item> &func); +// Create list for using with tempory table +static bool change_to_use_tmp_fields(Item **ref_pointer_array, + List<Item> &new_list1, + List<Item> &new_list2, + uint elements, List<Item> &items); +// Create list for using with tempory table +static bool change_refs_to_tmp_fields(THD *thd, Item **ref_pointer_array, + List<Item> &new_list1, + List<Item> &new_list2, + uint elements, List<Item> &items); static void init_tmptable_sum_functions(Item_sum **func); static void update_tmptable_sum_func(Item_sum **func,TABLE *tmp_table); static void copy_sum_funcs(Item_sum **func_ptr); @@ -164,17 +172,21 @@ int handle_select(THD *thd, LEX *lex, select_result *result) if (select_lex->next_select()) res=mysql_union(thd,lex,result); else - res=mysql_select(thd,(TABLE_LIST*) select_lex->table_list.first, - select_lex->item_list, - select_lex->where, - (ORDER*) select_lex->order_list.first, - (ORDER*) select_lex->group_list.first, - select_lex->having, - (ORDER*) lex->proc_list.first, - select_lex->options | thd->options, - result, &(lex->unit), &(lex->select_lex), 0); + res= mysql_select(thd, &select_lex->ref_pointer_array, + (TABLE_LIST*) select_lex->table_list.first, + select_lex->with_wild, select_lex->item_list, + select_lex->where, + select_lex->order_list.elements + + select_lex->group_list.elements, + (ORDER*) select_lex->order_list.first, + (ORDER*) select_lex->group_list.first, + select_lex->having, + (ORDER*) lex->proc_list.first, + select_lex->options | thd->options, + result, &(lex->unit), &(lex->select_lex), 0); if (res && result) result->abort(); + if (res || thd->net.report_error) { send_error(thd, 0, NullS); @@ -204,7 +216,8 @@ void fix_tables_pointers(SELECT_LEX *select_lex) /* Inline function to setup clauses without sum functions */ -inline int setup_without_group(THD *thd, TABLE_LIST *tables, +inline int setup_without_group(THD *thd, Item **ref_pointer_array, + TABLE_LIST *tables, List<Item> &fields, List<Item> &all_fields, COND **conds, @@ -213,10 +226,11 @@ inline int setup_without_group(THD *thd, TABLE_LIST *tables, { bool save_allow_sum_func= thd->allow_sum_func; thd->allow_sum_func= 0; - int res= (setup_conds(thd,tables, conds) || - setup_order(thd,tables, fields, all_fields, order) || - setup_group(thd,tables, fields, all_fields, group, - hidden_group_fields)); + int res= (setup_conds(thd, tables, conds) || + setup_order(thd, ref_pointer_array, tables, fields, all_fields, + order) || + setup_group(thd, ref_pointer_array, tables, fields, all_fields, + group, hidden_group_fields)); thd->allow_sum_func= save_allow_sum_func; return res; } @@ -232,8 +246,10 @@ inline int setup_without_group(THD *thd, TABLE_LIST *tables, 0 on success */ int -JOIN::prepare(TABLE_LIST *tables_init, - COND *conds_init, ORDER *order_init, ORDER *group_init, +JOIN::prepare(Item ***rref_pointer_array, + TABLE_LIST *tables_init, + uint wild_num, COND *conds_init, uint og_num, + ORDER *order_init, ORDER *group_init, Item *having_init, ORDER *proc_param_init, SELECT_LEX *select, SELECT_LEX_UNIT *unit, bool fake_select_lex) @@ -254,11 +270,19 @@ JOIN::prepare(TABLE_LIST *tables_init, /* Check that all tables, fields, conds and order are ok */ if (setup_tables(tables_list) || - setup_fields(thd,tables_list,fields_list,1,&all_fields,1) || - setup_without_group(thd, tables_list, fields_list, all_fields, - &conds, order, group_list, &hidden_group_fields)) + setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) || + setup_ref_array(thd, rref_pointer_array, (fields_list.elements + + select_lex->with_sum_func + + og_num)) || + setup_fields(thd, (*rref_pointer_array), tables_list, fields_list, 1, + &all_fields, 1) || + setup_without_group(thd, (*rref_pointer_array), tables_list, fields_list, + all_fields, &conds, order, group_list, + &hidden_group_fields)) DBUG_RETURN(-1); /* purecov: inspected */ + ref_pointer_array= *rref_pointer_array; + if (having) { thd->where="having clause"; @@ -270,7 +294,7 @@ JOIN::prepare(TABLE_LIST *tables_init, if (having_fix_rc || thd->net.report_error) DBUG_RETURN(-1); /* purecov: inspected */ if (having->with_sum_func) - having->split_sum_func(all_fields); + having->split_sum_func(ref_pointer_array, all_fields); } if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */ DBUG_RETURN(-1); @@ -303,7 +327,7 @@ JOIN::prepare(TABLE_LIST *tables_init, for (table=tables_list ; table ; table=table->next) tables++; } - procedure=setup_procedure(thd,proc_param,result,fields_list,&error); + procedure= setup_procedure(thd, proc_param, result, fields_list, &error); if (error) DBUG_RETURN(-1); /* purecov: inspected */ if (procedure) @@ -378,6 +402,9 @@ int JOIN::optimize() { DBUG_ENTER("JOIN::optimize"); + if (optimized) + DBUG_RETURN(0); + optimized= 1; #ifdef HAVE_REF_TO_FIELDS // Not done yet /* Add HAVING to WHERE if possible */ @@ -638,7 +665,7 @@ JOIN::optimize() we must add the removed reference to the select for the table. We only need to do this when we have a simple_order or simple_group as in other cases the join is done before the sort. - */ + */ if ((order || group_list) && join_tab[const_tables].type != JT_ALL && join_tab[const_tables].type != JT_FT && (order && simple_order || group_list && simple_group)) @@ -658,19 +685,117 @@ JOIN::optimize() { need_tmp=1; simple_order=simple_group=0; // Force tmp table without sort } + + if (select_options & SELECT_DESCRIBE) + DBUG_RETURN(0); + + tmp_having= having; + having= 0; + + /* Perform FULLTEXT search before all regular searches */ + init_ftfuncs(thd, select_lex, test(order)); + /* Create a tmp table if distinct or if the sort is too complicated */ + if (need_tmp) + { + DBUG_PRINT("info",("Creating tmp table")); + thd->proc_info="Creating tmp table"; + + init_items_ref_array(); + + tmp_table_param.hidden_field_count= (all_fields.elements - + fields_list.elements); + if (!(exec_tmp_table1 = + create_tmp_table(thd, &tmp_table_param, all_fields, + ((!simple_group && !procedure && + !(test_flags & TEST_NO_KEY_GROUP)) ? + group_list : (ORDER*) 0), + group_list ? 0 : select_distinct, + group_list && simple_group, + select_options, + (order == 0 || skip_sort_order) ? select_limit : + HA_POS_ERROR))) + DBUG_RETURN(1); + + //thd->temporary_tables_should_be_free.push_front(exec_tmp_table1); + if (having && + (sort_and_group || (exec_tmp_table1->distinct && !group_list))) + having= tmp_having; + + /* if group or order on first table, sort first */ + if (group_list && simple_group) + { + DBUG_PRINT("info",("Sorting for group")); + thd->proc_info="Sorting for group"; + if (create_sort_index(thd, &join_tab[const_tables], group_list, + HA_POS_ERROR, HA_POS_ERROR) || + make_sum_func_list(this, all_fields) || + alloc_group_fields(this, group_list)) + DBUG_RETURN(1); + group_list=0; + } + else + { + if (make_sum_func_list(this, all_fields)) + DBUG_RETURN(1); + if (!group_list && ! exec_tmp_table1->distinct && order && simple_order) + { + DBUG_PRINT("info",("Sorting for order")); + thd->proc_info="Sorting for order"; + if (create_sort_index(thd, &join_tab[const_tables], order, + HA_POS_ERROR, HA_POS_ERROR)) + DBUG_RETURN(1); + order=0; + } + } + + /* + Optimize distinct when used on some of the tables + SELECT DISTINCT t1.a FROM t1,t2 WHERE t1.b=t2.b + In this case we can stop scanning t2 when we have found one t1.a + */ + + if (exec_tmp_table1->distinct) + { + table_map used_tables= thd->used_tables; + JOIN_TAB *join_tab= this->join_tab+tables-1; + do + { + if (used_tables & join_tab->table->map) + break; + join_tab->not_used_in_distinct=1; + } while (join_tab-- != this->join_tab); + /* Optimize "select distinct b from t1 order by key_part_1 limit #" */ + if (order && skip_sort_order) + { + /* Should always succeed */ + if (test_if_skip_sort_order(&this->join_tab[const_tables], + order, unit->select_limit_cnt, 0)) + order=0; + } + } + + if (select_lex != &thd->lex.select_lex && + select_lex->linkage != DERIVED_TABLE_TYPE) + { + if (!(tmp_join= (JOIN*)thd->alloc(sizeof(JOIN)))) + DBUG_RETURN(-1); + restore_tmp(); + } + } + DBUG_RETURN(0); } /* - Global optimization (with subselect) must be here (TODO) + Restore values in temporary join */ -int -JOIN::global_optimize() +void JOIN::restore_tmp() { - return 0; + memcpy(tmp_join, this, (size_t) sizeof(JOIN)); } + int JOIN::reinit() { @@ -695,6 +820,28 @@ JOIN::reinit() func->null_value= 1; } + if (exec_tmp_table1) + { + exec_tmp_table1->file->extra(HA_EXTRA_RESET_STATE); + exec_tmp_table1->file->delete_all_rows(); + free_io_cache(exec_tmp_table1); + memcpy(ref_pointer_array, items0, ref_pointer_array_size); + } + if (exec_tmp_table2) + { + exec_tmp_table2->file->extra(HA_EXTRA_RESET_STATE); + exec_tmp_table2->file->delete_all_rows(); + free_io_cache(exec_tmp_table2); + } + if (items0) + memcpy(ref_pointer_array, items0, ref_pointer_array_size); + + tmp_table_param.copy_funcs.empty(); + tmp_table_param.copy_field= tmp_table_param.copy_field_end= 0; + + if (tmp_join) + restore_tmp(); + DBUG_RETURN(0); } @@ -743,14 +890,11 @@ JOIN::exec() !group_list, select_options, zero_result_cause, - having,procedure, + having, procedure, unit); DBUG_VOID_RETURN; } - Item *having_list = having; - having = 0; - if (select_options & SELECT_DESCRIBE) { if (!order && !no_order) @@ -761,6 +905,7 @@ JOIN::exec() test_if_skip_sort_order(&join_tab[const_tables], order, select_limit, 0)))) order=0; + having= tmp_having; select_describe(this, need_tmp, order != 0 && !skip_sort_order, select_distinct); @@ -769,120 +914,85 @@ JOIN::exec() } /* Perform FULLTEXT search before all regular searches */ - init_ftfuncs(thd, select_lex, test(order)); + //init_ftfuncs(thd, select_lex, test(order)); + + JOIN *curr_join= this; + List<Item> *curr_all_fields= &all_fields; + List<Item> *curr_fields_list= &fields_list; + TABLE *curr_tmp_table= 0; /* Create a tmp table if distinct or if the sort is too complicated */ if (need_tmp) { - DBUG_PRINT("info",("Creating tmp table")); - thd->proc_info="Creating tmp table"; - - tmp_table_param.hidden_field_count= (all_fields.elements - - fields_list.elements); - if (!(exec_tmp_table = - create_tmp_table(thd, &tmp_table_param, all_fields, - ((!simple_group && !procedure && - !(test_flags & TEST_NO_KEY_GROUP)) ? - group_list : (ORDER*) 0), - group_list ? 0 : select_distinct, - group_list && simple_group, - select_options, - (order == 0 || skip_sort_order) ? select_limit : - HA_POS_ERROR))) - DBUG_VOID_RETURN; - - if (having_list && - (sort_and_group || (exec_tmp_table->distinct && !group_list))) - having=having_list; - - /* if group or order on first table, sort first */ - if (group_list && simple_group) - { - DBUG_PRINT("info",("Sorting for group")); - thd->proc_info="Sorting for group"; - if (create_sort_index(thd, &join_tab[const_tables], group_list, - HA_POS_ERROR, HA_POS_ERROR) || - make_sum_func_list(this, all_fields) || - alloc_group_fields(this, group_list)) - DBUG_VOID_RETURN; - group_list=0; - } - else - { - if (make_sum_func_list(this, all_fields)) - DBUG_VOID_RETURN; - if (!group_list && ! exec_tmp_table->distinct && order && simple_order) - { - DBUG_PRINT("info",("Sorting for order")); - thd->proc_info="Sorting for order"; - if (create_sort_index(thd, &join_tab[const_tables], order, - HA_POS_ERROR, HA_POS_ERROR)) - DBUG_VOID_RETURN; - order=0; - } - } - - /* - Optimize distinct when used on some of the tables - SELECT DISTINCT t1.a FROM t1,t2 WHERE t1.b=t2.b - In this case we can stop scanning t2 when we have found one t1.a - */ - - if (exec_tmp_table->distinct) - { - table_map used_tables= thd->used_tables; - JOIN_TAB *join_tab= this->join_tab+tables-1; - do - { - if (used_tables & join_tab->table->map) - break; - join_tab->not_used_in_distinct=1; - } while (join_tab-- != this->join_tab); - /* Optimize "select distinct b from t1 order by key_part_1 limit #" */ - if (order && skip_sort_order) - { - /* Should always succeed */ - if (test_if_skip_sort_order(&this->join_tab[const_tables], - order, unit->select_limit_cnt, 0)) - order=0; - } - } - + if (tmp_join) + curr_join= tmp_join; + curr_tmp_table= exec_tmp_table1; /* Copy data to the temporary table */ thd->proc_info= "Copying to tmp table"; - if ((tmp_error= do_select(this, (List<Item> *) 0, exec_tmp_table, 0))) + + if ((tmp_error= do_select(curr_join, (List<Item> *) 0, curr_tmp_table, 0))) { error= tmp_error; DBUG_VOID_RETURN; } - if (having) - having= having_list= 0; // Allready done - + curr_tmp_table->file->info(HA_STATUS_VARIABLE); + + if (curr_join->having) + curr_join->having= curr_join->tmp_having= 0; // Allready done + /* Change sum_fields reference to calculated fields in tmp_table */ - if (sort_and_group || exec_tmp_table->group) + curr_join->all_fields= *curr_all_fields; + if (!items1) { - if (change_to_use_tmp_fields(all_fields)) - DBUG_VOID_RETURN; - tmp_table_param.field_count+= tmp_table_param.sum_func_count+ - tmp_table_param.func_count; - tmp_table_param.sum_func_count= tmp_table_param.func_count= 0; + items1= items0 + all_fields.elements; + if (sort_and_group || curr_tmp_table->group) + { + if (change_to_use_tmp_fields(items1, + tmp_fields_list1, tmp_all_fields1, + fields_list.elements, all_fields)) + DBUG_VOID_RETURN; + } + else + { + if (change_refs_to_tmp_fields(thd, items1, + tmp_fields_list1, tmp_all_fields1, + fields_list.elements, all_fields)) + DBUG_VOID_RETURN; + } + curr_join->tmp_all_fields1= tmp_all_fields1; + curr_join->tmp_fields_list1= tmp_fields_list1; + curr_join->items1= items1; + } + curr_all_fields= &tmp_all_fields1; + curr_fields_list= &tmp_fields_list1; + memcpy(ref_pointer_array, items1, ref_pointer_array_size); + + if (sort_and_group || curr_tmp_table->group) + { + curr_join->tmp_table_param.field_count+= + curr_join->tmp_table_param.sum_func_count+ + curr_join->tmp_table_param.func_count; + curr_join->tmp_table_param.sum_func_count= + curr_join->tmp_table_param.func_count= 0; } else { - if (change_refs_to_tmp_fields(thd,all_fields)) - DBUG_VOID_RETURN; - tmp_table_param.field_count+= tmp_table_param.func_count; - tmp_table_param.func_count= 0; + curr_join->tmp_table_param.field_count+= + curr_join->tmp_table_param.func_count; + curr_join->tmp_table_param.func_count= 0; } + + // procedure can't be used inside subselect => we do nothing special for it if (procedure) procedure->update_refs(); - if (exec_tmp_table->group) + + if (curr_tmp_table->group) { // Already grouped - if (!order && !no_order) - order= group_list; /* order by group */ - group_list= 0; + if (!curr_join->order && !curr_join->no_order) + curr_join->order= curr_join->group_list; /* order by group */ + curr_join->group_list= 0; } - + /* If we have different sort & group then we must sort the data by group and copy it to another tmp table @@ -891,142 +1001,199 @@ JOIN::exec() like SEC_TO_TIME(SUM(...)). */ - if (group_list && (!test_if_subpart(group_list,order) || - select_distinct) || - (select_distinct && - tmp_table_param.using_indirect_summary_function)) + if (curr_join->group_list && (!test_if_subpart(curr_join->group_list, + curr_join->order) || + curr_join->select_distinct) || + (curr_join->select_distinct && + curr_join->tmp_table_param.using_indirect_summary_function)) { /* Must copy to another table */ - TABLE *tmp_table2; DBUG_PRINT("info",("Creating group table")); - + /* Free first data from old join */ - join_free(this, 0); - if (make_simple_join(this, exec_tmp_table)) - DBUG_VOID_RETURN; - calc_group_buffer(this, group_list); - count_field_types(&tmp_table_param, all_fields, - select_distinct && !group_list); - tmp_table_param.hidden_field_count= (all_fields.elements- - fields_list.elements); - - /* group data to new table */ - if (!(tmp_table2 = create_tmp_table(thd, &tmp_table_param, all_fields, - (ORDER*) 0, - select_distinct && !group_list, - 1, select_options, HA_POS_ERROR))) + join_free(curr_join, 0); + if (make_simple_join(curr_join, curr_tmp_table)) DBUG_VOID_RETURN; + calc_group_buffer(curr_join, group_list); + count_field_types(&curr_join->tmp_table_param, curr_join->tmp_all_fields1, + curr_join->select_distinct && !curr_join->group_list); + curr_join->tmp_table_param.hidden_field_count= + (curr_join->tmp_all_fields1.elements- + curr_join->tmp_fields_list1.elements); + + + if (exec_tmp_table2) + curr_tmp_table= exec_tmp_table2; + else + { + /* group data to new table */ + if (!(curr_tmp_table= + exec_tmp_table2= create_tmp_table(thd, + &curr_join->tmp_table_param, + *curr_all_fields, + (ORDER*) 0, + curr_join->select_distinct && + !curr_join->group_list, + 1, curr_join->select_options, + HA_POS_ERROR))) + DBUG_VOID_RETURN; + //thd->temporary_tables_should_be_free.push_front(exec_tmp_table2); + curr_join->exec_tmp_table2= exec_tmp_table2; + } if (group_list) { - thd->proc_info="Creating sort index"; - if (create_sort_index(thd, join_tab, group_list, HA_POS_ERROR, - HA_POS_ERROR) || - alloc_group_fields(this, group_list)) + thd->proc_info= "Creating sort index"; + if (create_sort_index(thd, curr_join->join_tab, curr_join->group_list, + HA_POS_ERROR, HA_POS_ERROR) || + alloc_group_fields(curr_join, curr_join->group_list)) { - free_tmp_table(thd,tmp_table2); /* purecov: inspected */ DBUG_VOID_RETURN; } - group_list= 0; + curr_join->group_list= 0; } + thd->proc_info="Copying to group table"; tmp_error= -1; - if (make_sum_func_list(this, all_fields) || - (tmp_error=do_select(this, (List<Item> *) 0,tmp_table2,0))) + if (make_sum_func_list(curr_join, *curr_all_fields) || + (tmp_error= do_select(curr_join, (List<Item> *) 0, curr_tmp_table, + 0))) { - error=tmp_error; - free_tmp_table(thd,tmp_table2); + error= tmp_error; DBUG_VOID_RETURN; } - end_read_record(&join_tab->read_record); - free_tmp_table(thd,exec_tmp_table); - const_tables= tables; // Mark free for join_free() - exec_tmp_table= tmp_table2; - join_tab[0].table= 0; // Table is freed - - if (change_to_use_tmp_fields(all_fields)) // No sum funcs anymore - DBUG_VOID_RETURN; - tmp_table_param.field_count+= tmp_table_param.sum_func_count; - tmp_table_param.sum_func_count= 0; - } - - if (exec_tmp_table->distinct) - select_distinct=0; /* Each row is unique */ - - join_free(this, 0); /* Free quick selects */ + end_read_record(&curr_join->join_tab->read_record); + curr_join->const_tables= curr_join->tables; // Mark free for join_free() + curr_join->join_tab[0].table= 0; // Table is freed + + // No sum funcs anymore + if (!items2) + { + items2= items1 + all_fields.elements; + if (change_to_use_tmp_fields(items2, + tmp_fields_list2, tmp_all_fields2, + fields_list.elements, tmp_all_fields1)) + DBUG_VOID_RETURN; + curr_join->tmp_fields_list2= tmp_fields_list2; + curr_join->tmp_all_fields2= tmp_all_fields2; + } + curr_fields_list= &curr_join->tmp_fields_list2; + curr_all_fields= &curr_join->tmp_all_fields2; + memcpy(ref_pointer_array, items2, ref_pointer_array_size); + curr_join->tmp_table_param.field_count+= + curr_join->tmp_table_param.sum_func_count; + curr_join->tmp_table_param.sum_func_count= 0; + } + if (curr_tmp_table->distinct) + curr_join->select_distinct=0; /* Each row is unique */ + + join_free(curr_join, 0); /* Free quick selects */ if (select_distinct && ! group_list) { thd->proc_info="Removing duplicates"; - if (having_list) - having_list->update_used_tables(); - if (remove_duplicates(this, exec_tmp_table, fields_list, having_list)) + if (curr_join->tmp_having) + curr_join->tmp_having->update_used_tables(); + if (remove_duplicates(curr_join, curr_tmp_table, + curr_join->fields_list, curr_join->tmp_having)) DBUG_VOID_RETURN; - having_list=0; - select_distinct=0; + curr_join->tmp_having=0; + curr_join->select_distinct=0; } - exec_tmp_table->reginfo.lock_type=TL_UNLOCK; - if (make_simple_join(this, exec_tmp_table)) + curr_tmp_table->reginfo.lock_type= TL_UNLOCK; + if (make_simple_join(curr_join, curr_tmp_table)) DBUG_VOID_RETURN; - calc_group_buffer(this, group_list); - count_field_types(&tmp_table_param, all_fields, 0); + calc_group_buffer(curr_join, curr_join->group_list); + count_field_types(&curr_join->tmp_table_param, *curr_all_fields, 0); + } if (procedure) { - if (procedure->change_columns(fields_list) || - result->prepare(fields_list, unit)) + if (procedure->change_columns(*curr_fields_list) || + result->prepare(*curr_fields_list, unit)) DBUG_VOID_RETURN; - count_field_types(&tmp_table_param, all_fields, 0); + count_field_types(&curr_join->tmp_table_param, *curr_all_fields, 0); } - if (group || tmp_table_param.sum_func_count || + + if (curr_join->group || curr_join->tmp_table_param.sum_func_count || (procedure && (procedure->flags & PROC_GROUP))) { - alloc_group_fields(this, group_list); - setup_copy_fields(thd, &tmp_table_param,all_fields); - if (make_sum_func_list(this, all_fields) || thd->fatal_error) + alloc_group_fields(curr_join, curr_join->group_list); + if (!items3) + { + if (!items0) + init_items_ref_array(); + items3= ref_pointer_array + (all_fields.elements*4); + setup_copy_fields(thd, &curr_join->tmp_table_param, + items3, tmp_fields_list3, tmp_all_fields3, + curr_fields_list->elements, *curr_all_fields); + tmp_table_param.save_copy_funcs= curr_join->tmp_table_param.copy_funcs; + tmp_table_param.save_copy_field= curr_join->tmp_table_param.copy_field; + tmp_table_param.save_copy_field_end= + curr_join->tmp_table_param.copy_field_end; + curr_join->tmp_all_fields3= tmp_all_fields3; + curr_join->tmp_fields_list3= tmp_fields_list3; + } + else + { + curr_join->tmp_table_param.copy_funcs= tmp_table_param.save_copy_funcs; + curr_join->tmp_table_param.copy_field= tmp_table_param.save_copy_field; + curr_join->tmp_table_param.copy_field_end= + tmp_table_param.save_copy_field_end; + } + curr_fields_list= &tmp_fields_list3; + curr_all_fields= &tmp_all_fields3; + memcpy(ref_pointer_array, items3, ref_pointer_array_size); + + if (make_sum_func_list(curr_join, *curr_all_fields) || + thd->fatal_error) DBUG_VOID_RETURN; } - if (group_list || order) + if (curr_join->group_list || curr_join->order) { DBUG_PRINT("info",("Sorting for send_fields")); thd->proc_info="Sorting result"; /* If we have already done the group, add HAVING to sorted table */ - if (having_list && ! group_list && ! sort_and_group) + if (curr_join->tmp_having && ! curr_join->group_list && + ! curr_join->sort_and_group) { - having_list->update_used_tables(); // Some tables may have been const - JOIN_TAB *table= &join_tab[const_tables]; - table_map used_tables= const_table_map | table->table->map; + // Some tables may have been const + curr_join->tmp_having->update_used_tables(); + JOIN_TAB *table= &curr_join->join_tab[const_tables]; + table_map used_tables= curr_join->const_table_map | table->table->map; - Item* sort_table_cond= make_cond_for_table(having_list, used_tables, + Item* sort_table_cond= make_cond_for_table(curr_join->tmp_having, + used_tables, used_tables); if (sort_table_cond) { if (!table->select) - if (!(table->select=new SQL_SELECT)) + if (!(table->select= new SQL_SELECT)) DBUG_VOID_RETURN; if (!table->select->cond) - table->select->cond=sort_table_cond; + table->select->cond= sort_table_cond; else // This should never happen - if (!(table->select->cond=new Item_cond_and(table->select->cond, - sort_table_cond))) + if (!(table->select->cond= new Item_cond_and(table->select->cond, + sort_table_cond))) DBUG_VOID_RETURN; table->select_cond=table->select->cond; table->select_cond->top_level_item(); DBUG_EXECUTE("where",print_where(table->select->cond, "select and having");); - having_list= make_cond_for_table(having_list, ~ (table_map) 0, - ~used_tables); + curr_join->tmp_having= make_cond_for_table(curr_join->tmp_having, + ~ (table_map) 0, + ~used_tables); DBUG_EXECUTE("where",print_where(conds,"having after sort");); } } { if (group) - select_limit= HA_POS_ERROR; + curr_join->select_limit= HA_POS_ERROR; else { /* We can abort sorting after thd->select_limit rows if we there is no WHERE clause for any tables after the sorted one. */ - JOIN_TAB *table= &join_tab[const_tables+1]; - JOIN_TAB *end_table= &join_tab[tables]; + JOIN_TAB *table= &curr_join->join_tab[const_tables+1]; + JOIN_TAB *end_table= &curr_join->join_tab[tables]; for (; table < end_table ; table++) { /* @@ -1038,21 +1205,22 @@ JOIN::exec() if (table->select_cond || (table->keyuse && !table->on_expr)) { /* We have to sort all rows */ - select_limit= HA_POS_ERROR; + curr_join->select_limit= HA_POS_ERROR; break; } } } - if (create_sort_index(thd, &join_tab[const_tables], - group_list ? group_list : order, - select_limit, unit->select_limit_cnt)) - DBUG_VOID_RETURN; + if (create_sort_index(thd, &curr_join->join_tab[curr_join->const_tables], + curr_join->group_list ? + curr_join->group_list : curr_join->order, + curr_join->select_limit, unit->select_limit_cnt)) + DBUG_VOID_RETURN; } } - having=having_list; // Actually a parameter + curr_join->having= curr_join->tmp_having; thd->proc_info="Sending data"; error= thd->net.report_error || - do_select(this, &fields_list, NULL, procedure); + do_select(curr_join, curr_fields_list, NULL, procedure); DBUG_VOID_RETURN; } @@ -1065,10 +1233,18 @@ JOIN::cleanup(THD *thd) { DBUG_ENTER("JOIN::cleanup"); + select_lex->join= 0; + + if (tmp_join) + memcpy(this, tmp_join, sizeof(tmp_join)); + + lock=0; // It's faster to unlock later join_free(this, 1); - if (exec_tmp_table) - free_tmp_table(thd, exec_tmp_table); + if (exec_tmp_table1) + free_tmp_table(thd, exec_tmp_table1); + if (exec_tmp_table2) + free_tmp_table(thd, exec_tmp_table2); delete select; delete_dynamic(&keyuse); delete procedure; @@ -1076,18 +1252,7 @@ JOIN::cleanup(THD *thd) unit != 0; unit= unit->next_unit()) { - for (SELECT_LEX *sl= unit->first_select(); - sl != 0; - sl= sl->next_select()) - { - if (sl->join) - { - int err= sl->join->cleanup(thd); - if (err) - error= err; - sl->join= 0; - } - } + error|= unit->cleanup(); } DBUG_RETURN(error); } @@ -1111,11 +1276,12 @@ bool JOIN::check_loop(uint id) } int -mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds, - ORDER *order, ORDER *group,Item *having, ORDER *proc_param, - ulong select_options, select_result *result, - SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex, - bool fake_select_lex) +mysql_select(THD *thd, Item ***rref_pointer_array, + TABLE_LIST *tables, uint wild_num, List<Item> &fields, + COND *conds, uint og_num, ORDER *order, ORDER *group, + Item *having, ORDER *proc_param, ulong select_options, + select_result *result, SELECT_LEX_UNIT *unit, + SELECT_LEX *select_lex, bool fake_select_lex) { int err; bool free_join= 1; @@ -1140,7 +1306,8 @@ mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds, thd->proc_info="init"; thd->used_tables=0; // Updated by setup_fields - if (join->prepare(tables, conds, order, group, having, proc_param, + if (join->prepare(rref_pointer_array, tables, wild_num, + conds, og_num, order, group, having, proc_param, select_lex, unit, fake_select_lex)) { DBUG_RETURN(-1); @@ -1172,7 +1339,7 @@ mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds, goto err; // 1 } - if (thd->net.report_error || (free_join && join->global_optimize())) + if (thd->net.report_error) goto err; join->exec(); @@ -1180,10 +1347,14 @@ mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds, err: if (free_join) { - thd->limit_found_rows = join->send_records; - thd->examined_row_count = join->examined_rows; + JOIN *curr_join= (join->need_tmp&&join->tmp_join? + (join->tmp_join->error=join->error,join->tmp_join): + join); + + thd->limit_found_rows= curr_join->send_records; + thd->examined_row_count= curr_join->examined_rows; thd->proc_info="end"; - err= (fake_select_lex ? join->error : join->cleanup(thd)); + err= (fake_select_lex ? curr_join->error : join->cleanup(thd)); if (thd->net.report_error) err= -1; delete join; @@ -3068,6 +3239,7 @@ join_free(JOIN *join, bool full) delete tab->select; delete tab->quick; x_free(tab->cache.buff); + tab->cache.buff= 0; if (tab->table) { if (tab->table->key_read) @@ -3094,9 +3266,12 @@ join_free(JOIN *join, bool full) mysql_unlock_read_tables(join->thd, join->lock);// Don't free join->lock join->lock=0; } - join->group_fields.delete_elements(); - join->tmp_table_param.copy_funcs.delete_elements(); - join->tmp_table_param.cleanup(); + if (full) + { + join->group_fields.delete_elements(); + join->tmp_table_param.copy_funcs.delete_elements(); + join->tmp_table_param.cleanup(); + } DBUG_VOID_RETURN; } @@ -4124,9 +4299,11 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, { uint alloc_length=ALIGN_SIZE(reclength+MI_UNIQUE_HASH_LENGTH+1); table->rec_buff_length=alloc_length; - if (!(table->record[0]= (byte *) my_malloc(alloc_length*3, MYF(MY_WME)))) + byte * t; + if (!(t= table->record[0]= (byte *) my_malloc(alloc_length*3, MYF(MY_WME)))) goto err; - table->record[1]= table->record[0]+alloc_length; + table->record[1]= t+alloc_length; + //table->record[1]= table->record[0]+alloc_length; table->record[2]= table->record[1]+alloc_length; } copy_func[0]=0; // End marker @@ -6752,31 +6929,32 @@ cp_buffer_from_ref(TABLE_REF *ref) */ static int -find_order_in_list(THD *thd,TABLE_LIST *tables,ORDER *order,List<Item> &fields, +find_order_in_list(THD *thd, Item **ref_pointer_array, + TABLE_LIST *tables,ORDER *order, List<Item> &fields, List<Item> &all_fields) { if ((*order->item)->type() == Item::INT_ITEM) { /* Order by position */ Item *item=0; - List_iterator<Item> li(fields); - for (uint count= (uint) ((Item_int*) (*order->item))->value ; - count-- && (item=li++) ;) ; - if (!item) + uint count= (uint) ((Item_int*) (*order->item))->value; + if (count > fields.elements) { my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR), MYF(0),(*order->item)->full_name(), thd->where); return 1; } - order->item=li.ref(); - order->in_field_list=1; + order->item= ref_pointer_array + count-1; + order->in_field_list= 1; return 0; } - Item **item= find_item_in_list(*order->item, fields, IGNORE_ERRORS); + uint counter= 0; + Item **item= find_item_in_list(*order->item, fields, &counter, + IGNORE_ERRORS); if (item) { - order->item=item; // use it + order->item= ref_pointer_array + counter-1; order->in_field_list=1; return 0; } @@ -6785,24 +6963,43 @@ find_order_in_list(THD *thd,TABLE_LIST *tables,ORDER *order,List<Item> &fields, if (it->check_cols(1) || it->fix_fields(thd, tables, order->item) || thd->fatal_error) return 1; // Wrong field - all_fields.push_front(*order->item); // Add new field to field list - order->item=(Item**) all_fields.head_ref(); + uint el= all_fields.elements; + all_fields.push_front(it); // Add new field to field list + ref_pointer_array[el]= it; + order->item= ref_pointer_array + el; return 0; } +/* + Allocate array of references to address all_fileds list elements +*/ + +int setup_ref_array(THD* thd, Item ***rref_pointer_array, uint elements) +{ + if (*rref_pointer_array) + return 0; + + /* TODO: may be better allocate only one and all other on demand? */ + if (!(*rref_pointer_array= + (Item **)thd->alloc(sizeof(Item*) * elements * 5))) + return -1; + else + return 0; +} /* Change order to point at item in select list. If item isn't a number and doesn't exits in the select list, add it the the field list. */ -int setup_order(THD *thd,TABLE_LIST *tables,List<Item> &fields, - List<Item> &all_fields, ORDER *order) +int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, + List<Item> &fields, List<Item> &all_fields, ORDER *order) { thd->where="order clause"; for (; order; order=order->next) { - if (find_order_in_list(thd,tables,order,fields,all_fields)) + if (find_order_in_list(thd, ref_pointer_array, tables, order, fields, + all_fields)) return 1; } return 0; @@ -6810,8 +7007,9 @@ int setup_order(THD *thd,TABLE_LIST *tables,List<Item> &fields, int -setup_group(THD *thd,TABLE_LIST *tables,List<Item> &fields, - List<Item> &all_fields, ORDER *order, bool *hidden_group_fields) +setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, + List<Item> &fields, List<Item> &all_fields, ORDER *order, + bool *hidden_group_fields) { *hidden_group_fields=0; if (!order) @@ -6829,7 +7027,8 @@ setup_group(THD *thd,TABLE_LIST *tables,List<Item> &fields, thd->where="group statement"; for (; order; order=order->next) { - if (find_order_in_list(thd,tables,order,fields,all_fields)) + if (find_order_in_list(thd, ref_pointer_array, tables, order, fields, + all_fields)) return 1; (*order->item)->marker=1; /* Mark found */ if ((*order->item)->with_sum_func) @@ -6873,9 +7072,11 @@ setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields, DBUG_ENTER("setup_new_fields"); thd->set_query_id=1; // Not really needed, but... + uint counter= 0; for (; new_field ; new_field= new_field->next) { - if ((item= find_item_in_list(*new_field->item, fields, IGNORE_ERRORS))) + if ((item= find_item_in_list(*new_field->item, fields, &counter, + IGNORE_ERRORS))) new_field->item=item; /* Change to shared Item */ else { @@ -7126,41 +7327,55 @@ test_if_group_changed(List<Item_buff> &list) */ bool -setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields) +setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, + Item **ref_pointer_array, + List<Item> &new_list1, List<Item> &new_list2, + uint elements, List<Item> &fields) { Item *pos; - List_iterator<Item> li(fields); + List_iterator_fast<Item> li(fields); Copy_field *copy; DBUG_ENTER("setup_copy_fields"); + new_list1.empty(); + new_list2.empty(); + List_iterator_fast<Item> itr(new_list2); + + uint i, border= fields.elements - elements; if (!(copy=param->copy_field= new Copy_field[param->field_count])) goto err2; param->copy_funcs.empty(); - while ((pos=li++)) + for (i= 0; (pos= li++); i++) { if (pos->type() == Item::FIELD_ITEM) { - Item_field *item=(Item_field*) pos; + Item_field *item; + if (!(item= new Item_field(*((Item_field*) pos)))) + goto err; + pos= item; if (item->field->flags & BLOB_FLAG) { - if (!(pos=new Item_copy_string(pos))) + if (!(pos= new Item_copy_string(pos))) goto err; - VOID(li.replace(pos)); if (param->copy_funcs.push_back(pos)) goto err; - continue; } - - /* set up save buffer and change result_field to point at saved value */ - Field *field= item->field; - item->result_field=field->new_field(&thd->mem_root,field->table); - char *tmp=(char*) sql_alloc(field->pack_length()+1); - if (!tmp) - goto err; - copy->set(tmp, item->result_field); - item->result_field->move_field(copy->to_ptr,copy->to_null_ptr,1); - copy++; + else + { + /* + set up save buffer and change result_field to point at + saved value + */ + Field *field= item->field; + item->result_field=field->new_field(&thd->mem_root,field->table); + char *tmp=(char*) sql_alloc(field->pack_length()+1); + if (!tmp) + goto err; + copy->set(tmp, item->result_field); + item->result_field->move_field(copy->to_ptr,copy->to_null_ptr,1); + copy++; + } } else if ((pos->type() == Item::FUNC_ITEM || pos->type() == Item::COND_ITEM) && @@ -7174,12 +7389,18 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields) */ if (!(pos=new Item_copy_string(pos))) goto err; - VOID(li.replace(pos)); if (param->copy_funcs.push_back(pos)) goto err; } + new_list2.push_back(pos); + ref_pointer_array[((i < border)? fields.elements-i-1 : i-border)]= + pos; } param->copy_field_end= copy; + + for (i= 0; i < border; i++) + itr++; + itr.sublist(new_list1, elements); DBUG_RETURN(0); err: @@ -7244,51 +7465,63 @@ make_sum_func_list(JOIN *join,List<Item> &fields) /* - Change all funcs and sum_funcs to fields in tmp table + Change all funcs and sum_funcs to fields in tmp table, and create + new list of all items */ static bool -change_to_use_tmp_fields(List<Item> &items) +change_to_use_tmp_fields(Item **ref_pointer_array, + List<Item> &new_list1, List<Item> &new_list2, + uint elements, List<Item> &items) { - List_iterator<Item> it(items); + List_iterator_fast<Item> it(items); Item *item_field,*item; + new_list1.empty(); + new_list2.empty(); - while ((item=it++)) + uint i, border= items.elements - elements; + for (i= 0; (item= it++); i++) { Field *field; + if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM) - continue; - if (item->type() == Item::FIELD_ITEM) - { - ((Item_field*) item)->field= - ((Item_field*) item)->result_field; - } - else if ((field=item->tmp_table_field())) - { - if (item->type() == Item::SUM_FUNC_ITEM && field->table->group) - item_field=((Item_sum*) item)->result_item(field); - else - item_field=(Item*) new Item_field(field); - if (!item_field) - return TRUE; // Fatal error - item_field->name=item->name; /*lint -e613 */ -#ifndef DBUG_OFF - if (_db_on_ && !item_field->name) + item_field= item; + else + if (item->type() == Item::FIELD_ITEM) { - char buff[256]; - String str(buff,sizeof(buff),default_charset_info); - str.length(0); - item->print(&str); - item_field->name=sql_strmake(str.ptr(),str.length()); + item_field= item->get_tmp_table_item(); } + else if ((field= item->tmp_table_field())) + { + if (item->type() == Item::SUM_FUNC_ITEM && field->table->group) + item_field= ((Item_sum*) item)->result_item(field); + else + item_field= (Item*) new Item_field(field); + if (!item_field) + return TRUE; // Fatal error + item_field->name= item->name; /*lint -e613 */ +#ifndef DBUG_OFF + if (_db_on_ && !item_field->name) + { + char buff[256]; + String str(buff,sizeof(buff),default_charset_info); + str.length(0); + item->print(&str); + item_field->name= sql_strmake(str.ptr(),str.length()); + } #endif -#ifdef DELETE_ITEMS - delete it.replace(item_field); /*lint -e613 */ -#else - (void) it.replace(item_field); /*lint -e613 */ -#endif - } + } + else + item_field= item; + new_list2.push_back(item_field); + ref_pointer_array[((i < border)? items.elements-i-1 : i-border)]= + item_field; } + + List_iterator_fast<Item> itr(new_list2); + for (i= 0; i < border; i++) + itr++; + itr.sublist(new_list1, elements); return FALSE; } @@ -7299,52 +7532,29 @@ change_to_use_tmp_fields(List<Item> &items) */ static bool -change_refs_to_tmp_fields(THD *thd,List<Item> &items) +change_refs_to_tmp_fields(THD *thd, Item **ref_pointer_array, + List<Item> &new_list1, + List<Item> &new_list2, uint elements, + List<Item> &items) { - List_iterator<Item> it(items); - Item *item; + List_iterator_fast<Item> it(items); + Item *item, *new_item; + new_list1.empty(); + new_list2.empty(); - while ((item= it++)) + uint i, border= items.elements - elements; + for (i= 0; (item= it++); i++) { - if (item->type() == Item::SUM_FUNC_ITEM) - { - if (!item->const_item()) - { - Item_sum *sum_item= (Item_sum*) item; - if (sum_item->result_field) // If not a const sum func - { - Field *result_field=sum_item->result_field; - for (uint i=0 ; i < sum_item->arg_count ; i++) - { - Item *arg= sum_item->args[i]; - if (!arg->const_item()) - { - if (arg->type() == Item::FIELD_ITEM) - ((Item_field*) arg)->field= result_field++; - else - sum_item->args[i]= new Item_field(result_field++); - } - } - } - } - } - else if (item->with_sum_func) - continue; - else if ((item->type() == Item::FUNC_ITEM || - item->type() == Item::COND_ITEM) && - !item->const_item()) - { /* All funcs are stored */ -#ifdef DELETE_ITEMS - delete it.replace(new Item_field(((Item_func*) item)->result_field)); -#else - (void) it.replace(new Item_field(((Item_func*) item)->result_field)); -#endif - } - else if (item->type() == Item::FIELD_ITEM) /* Change refs */ - { - ((Item_field*)item)->field=((Item_field*) item)->result_field; - } + new_list2.push_back(new_item= item->get_tmp_table_item()); + ref_pointer_array[((i < border)? items.elements-i-1 : i-border)]= + new_item; } + + List_iterator_fast<Item> itr(new_list2); + for (i= 0; i < border; i++) + itr++; + itr.sublist(new_list1, elements); + return thd->fatal_error; } @@ -7683,9 +7893,12 @@ int mysql_explain_select(THD *thd, SELECT_LEX *select_lex, char const *type, select_lex->type= type; thd->lex.current_select= select_lex; SELECT_LEX_UNIT *unit= select_lex->master_unit(); - int res= mysql_select(thd,(TABLE_LIST*) select_lex->table_list.first, - select_lex->item_list, + int res= mysql_select(thd, &select_lex->ref_pointer_array, + (TABLE_LIST*) select_lex->table_list.first, + select_lex->with_wild, select_lex->item_list, select_lex->where, + select_lex->order_list.elements + + select_lex->group_list.elements, (ORDER*) select_lex->order_list.first, (ORDER*) select_lex->group_list.first, select_lex->having, @@ -7694,4 +7907,17 @@ int mysql_explain_select(THD *thd, SELECT_LEX *select_lex, char const *type, result, unit, select_lex, 0); DBUG_RETURN(res); } + +/* +*/ + +void free_ulderlayed_joins(THD *thd, SELECT_LEX *select) +{ + for (SELECT_LEX_UNIT *unit= select->first_inner_unit(); + unit; + unit= unit->next_unit()) + unit->cleanup(); +} + + diff --git a/sql/sql_select.h b/sql/sql_select.h index 1fbe20528310bf21c54a5a0beb53a8888988eff4..20972635d33b46b525f0a061810a2810d0014642 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -119,8 +119,10 @@ class TMP_TABLE_PARAM :public Sql_alloc { public: List<Item> copy_funcs; + List<Item> save_copy_funcs; List_iterator_fast<Item> copy_funcs_it; Copy_field *copy_field, *copy_field_end; + Copy_field *save_copy_field, *save_copy_field_end; byte *group_buff; Item_result_field **funcs; MI_COLUMNDEF *recinfo,*start_recinfo; @@ -166,10 +168,13 @@ class JOIN :public Sql_alloc List<Item> *fields; List<Item_buff> group_fields; TABLE *tmp_table; + // used to store 2 possible tmp table of SELECT + TABLE *exec_tmp_table1, *exec_tmp_table2; THD *thd; Item_sum **sum_funcs; Procedure *procedure; Item *having; + Item *tmp_having; // To store Having when processed tenporary table uint select_options; select_result *result; TMP_TABLE_PARAM tmp_table_param; @@ -178,6 +183,8 @@ class JOIN :public Sql_alloc SELECT_LEX_UNIT *unit; // select that processed SELECT_LEX *select_lex; + + JOIN *tmp_join; // copy of this JOIN to be used with temporary tables bool select_distinct, //Is select distinct? no_order, simple_order, simple_group, @@ -186,7 +193,11 @@ class JOIN :public Sql_alloc buffer_result; DYNAMIC_ARRAY keyuse; Item::cond_result cond_value; - List<Item> all_fields; + List<Item> all_fields; // to store all fields that used in query + //Above list changed to use temporary table + List<Item> tmp_all_fields1, tmp_all_fields2, tmp_all_fields3; + //Part, shared with list above, emulate following list + List<Item> tmp_fields_list1, tmp_fields_list2, tmp_fields_list3; List<Item> & fields_list; // hold field list passed to mysql_select int error; @@ -194,11 +205,14 @@ class JOIN :public Sql_alloc COND *conds; // ---"--- TABLE_LIST *tables_list; //hold 'tables' parameter of mysql_selec SQL_SELECT *select; //created in optimisation phase - TABLE *exec_tmp_table; //used in 'exec' to hold temporary - + Item **ref_pointer_array; //used pointer reference for this select + // Copy of above to be used with different lists + Item **items0, **items1, **items2, **items3; + uint ref_pointer_array_size; // size of above in bytes const char *zero_result_cause; // not 0 if exec must return zero result - my_bool union_part; // this subselect is part of union + bool union_part; // this subselect is part of union + bool optimized; // flag to avoid double optimization in EXPLAIN JOIN(THD *thd, List<Item> &fields, ulong select_options, select_result *result): @@ -208,14 +222,16 @@ class JOIN :public Sql_alloc sort_and_group(0), first_record(0), do_send_rows(1), send_records(0), found_records(0), examined_rows(0), + exec_tmp_table1(0), exec_tmp_table2(0), thd(thd), sum_funcs(0), procedure(0), - having(0), + having(0), tmp_having(0), select_options(select_options), result(result), lock(thd->lock), select_lex(0), //for safety + tmp_join(0), select_distinct(test(select_options & SELECT_DISTINCT)), no_order(0), simple_order(0), simple_group(0), skip_sort_order(0), need_tmp(0), @@ -226,8 +242,10 @@ class JOIN :public Sql_alloc fields_list(fields), error(0), select(0), - exec_tmp_table(0), - zero_result_cause(0) + ref_pointer_array(0), items0(0), items1(0), items2(0), items3(0), + ref_pointer_array_size(0), + zero_result_cause(0), + optimized(0) { fields_list = fields; bzero((char*) &keyuse,sizeof(keyuse)); @@ -235,16 +253,23 @@ class JOIN :public Sql_alloc tmp_table_param.end_write_records= HA_POS_ERROR; } - int prepare(TABLE_LIST *tables, - COND *conds, ORDER *order, ORDER *group, Item *having, - ORDER *proc_param, SELECT_LEX *select, SELECT_LEX_UNIT *unit, - bool fake_select_lex); + int prepare(Item ***rref_pointer_array, TABLE_LIST *tables, uint wind_num, + COND *conds, uint og_num, ORDER *order, ORDER *group, + Item *having, ORDER *proc_param, SELECT_LEX *select, + SELECT_LEX_UNIT *unit, bool fake_select_lex); int optimize(); - int global_optimize(); int reinit(); void exec(); int cleanup(THD *thd); bool check_loop(uint id); + void restore_tmp(); + + inline void init_items_ref_array() + { + items0= ref_pointer_array + all_fields.elements; + ref_pointer_array_size= all_fields.elements*sizeof(Item*); + memcpy(items0, ref_pointer_array, ref_pointer_array_size); + } }; @@ -263,7 +288,10 @@ TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, void free_tmp_table(THD *thd, TABLE *entry); void count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields, bool reset_with_sum_func); -bool setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,List<Item> &fields); +bool setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, + Item **ref_pointer_array, + List<Item> &new_list1, List<Item> &new_list2, + uint elements, List<Item> &fields); void copy_fields(TMP_TABLE_PARAM *param); void copy_funcs(Item_result_field **func_ptr); bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, diff --git a/sql/sql_table.cc b/sql/sql_table.cc index d343ccd39f57097419c41f6e16d43ab8b11080ef..072e0de04327c6e87b2480fbd32eeb66cfba9d5f 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -37,7 +37,7 @@ static char *make_unique_key_name(const char *field_name,KEY *start,KEY *end); static int copy_data_between_tables(TABLE *from,TABLE *to, List<create_field> &create, enum enum_duplicates handle_duplicates, - ORDER *order, + uint order_num, ORDER *order, ha_rows *copied,ha_rows *deleted); /***************************************************************************** @@ -1415,7 +1415,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, List<create_field> &fields, List<Key> &keys,List<Alter_drop> &drop_list, List<Alter_column> &alter_list, - ORDER *order, + uint order_num, ORDER *order, bool drop_primary, enum enum_duplicates handle_duplicates, enum enum_enable_or_disable keys_onoff, @@ -1877,7 +1877,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, if (!new_table->is_view) error=copy_data_between_tables(table,new_table,create_list, handle_duplicates, - order, &copied, &deleted); + order_num, order, &copied, &deleted); thd->last_insert_id=next_insert_id; // Needed for correct log thd->count_cuted_fields=0; // Don`t calc cuted fields new_table->time_stamp=save_time_stamp; @@ -2090,7 +2090,7 @@ static int copy_data_between_tables(TABLE *from,TABLE *to, List<create_field> &create, enum enum_duplicates handle_duplicates, - ORDER *order, + uint order_num, ORDER *order, ha_rows *copied, ha_rows *deleted) { @@ -2138,7 +2138,10 @@ copy_data_between_tables(TABLE *from,TABLE *to, tables.db = from->table_cache_key; error=1; - if (setup_order(thd, &tables, fields, all_fields, order) || + if (setup_ref_array(thd, &thd->lex.select_lex.ref_pointer_array, + order_num)|| + setup_order(thd, thd->lex.select_lex.ref_pointer_array, + &tables, fields, all_fields, order) || !(sortorder=make_unireg_sortorder(order, &length)) || (from->found_records = filesort(thd, from, sortorder, length, (SQL_SELECT *) 0, HA_POS_ERROR, diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 6e8c2ebdb5c6a383290c6ba8d7efa84b7a204f7c..70eb39007d2d7bd06901a2c620f93fc6b7f450bb 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -108,7 +108,6 @@ bool select_union::flush() return 0; } -typedef JOIN * JOIN_P; int st_select_lex_unit::prepare(THD *thd, select_result *result) { DBUG_ENTER("st_select_lex_unit::prepare"); @@ -116,11 +115,9 @@ int st_select_lex_unit::prepare(THD *thd, select_result *result) if (prepared) DBUG_RETURN(0); prepared= 1; - union_result=0; res= 0; found_rows_for_union= 0; TMP_TABLE_PARAM tmp_table_param; - this->thd= thd; this->result= result; SELECT_LEX_NODE *lex_select_save= thd->lex.current_select; SELECT_LEX *sl; @@ -143,7 +140,9 @@ int st_select_lex_unit::prepare(THD *thd, select_result *result) while ((item= it++)) if (item_list.push_back(item)) goto err; - if (setup_fields(thd,first_table,item_list,0,0,1)) + if (setup_wild(thd, first_table, item_list, 0, + first_select()->with_wild) || + setup_fields(thd, 0, first_table, item_list, 0, 0, 1)) goto err; } @@ -169,13 +168,11 @@ int st_select_lex_unit::prepare(THD *thd, select_result *result) union_result->tmp_table_param=&tmp_table_param; // prepare selects - joins.empty(); for (sl= first_select(); sl; sl= sl->next_select()) { JOIN *join= new JOIN(thd, sl->item_list, sl->options | thd->options | SELECT_NO_UNLOCK, union_result); - joins.push_back(new JOIN_P(join)); thd->lex.current_select= sl; offset_limit_cnt= sl->offset_limit; select_limit_cnt= sl->select_limit+sl->offset_limit; @@ -184,8 +181,11 @@ int st_select_lex_unit::prepare(THD *thd, select_result *result) if (select_limit_cnt == HA_POS_ERROR) sl->options&= ~OPTION_FOUND_ROWS; - res= join->prepare((TABLE_LIST*) sl->table_list.first, + res= join->prepare(&sl->ref_pointer_array, + (TABLE_LIST*) sl->table_list.first, sl->with_wild, sl->where, + ((sl->braces) ? sl->order_list.elements : 0) + + sl->group_list.elements, (sl->braces) ? (ORDER *)sl->order_list.first : (ORDER *) 0, (ORDER*) sl->group_list.first, @@ -286,8 +286,9 @@ int st_select_lex_unit::exec() select_limit_cnt= HA_POS_ERROR; // no limit if (select_limit_cnt == HA_POS_ERROR) thd->options&= ~OPTION_FOUND_ROWS; - res= mysql_select(thd,&result_table_list, - item_list, NULL, + res= mysql_select(thd, &ref_pointer_array, &result_table_list, + 0, item_list, NULL, + global_parameters->order_list.elements, (ORDER*)global_parameters->order_list.first, (ORDER*) NULL, NULL, (ORDER*) NULL, thd->options, result, this, first_select(), 1); @@ -303,20 +304,24 @@ int st_select_lex_unit::exec() int st_select_lex_unit::cleanup() { DBUG_ENTER("st_select_lex_unit::cleanup"); + + int error= 0; + if (union_result) { delete union_result; - free_tmp_table(thd,table); + if (table) + free_tmp_table(thd, table); table= 0; // Safety } - List_iterator<JOIN*> j(joins); - JOIN** join; - while ((join= j++)) + for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) { - (*join)->cleanup(thd); - delete *join; - delete join; + JOIN *join; + if ((join= sl->join)) + { + error|= sl->join->cleanup(thd); + delete join; + } } - joins.empty(); - DBUG_RETURN(0); + DBUG_RETURN(error); } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index de5cb9ef45be052935c77d455ccd4af4ded2a598..f32260f97f6d336c03f59b54ce42581a38381a67 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -50,7 +50,7 @@ int mysql_update(THD *thd, List<Item> &fields, List<Item> &values, COND *conds, - ORDER *order, + uint order_num, ORDER *order, ha_rows limit, enum enum_duplicates handle_duplicates) { @@ -109,7 +109,7 @@ int mysql_update(THD *thd, /* Check the fields we are going to modify */ table->grant.want_privilege=want_privilege; - if (setup_fields(thd,update_table_list,fields,1,0,0)) + if (setup_fields(thd, 0, update_table_list, fields, 1, 0, 0)) DBUG_RETURN(-1); /* purecov: inspected */ if (table->timestamp_field) { @@ -122,8 +122,9 @@ int mysql_update(THD *thd, /* Check values */ table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege); - if (setup_fields(thd,update_table_list,values,0,0,0)) + if (setup_fields(thd, 0, update_table_list, values, 0, 0, 0)) { + free_ulderlayed_joins(thd, &thd->lex.select_lex); DBUG_RETURN(-1); /* purecov: inspected */ } @@ -134,6 +135,7 @@ int mysql_update(THD *thd, (select && select->check_quick(safe_update, limit)) || !limit) { delete select; + free_ulderlayed_joins(thd, &thd->lex.select_lex); if (error) { DBUG_RETURN(-1); // Error in where @@ -148,6 +150,7 @@ int mysql_update(THD *thd, if (safe_update && !using_limit) { delete select; + free_ulderlayed_joins(thd, &thd->lex.select_lex); send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE); DBUG_RETURN(1); } @@ -175,6 +178,7 @@ int mysql_update(THD *thd, DISK_BUFFER_SIZE, MYF(MY_WME))) { delete select; /* purecov: inspected */ + free_ulderlayed_joins(thd, &thd->lex.select_lex); DBUG_RETURN(-1); } if (old_used_keys & ((key_map) 1 << used_index)) @@ -197,7 +201,10 @@ int mysql_update(THD *thd, table->io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE), MYF(MY_FAE | MY_ZEROFILL)); - if (setup_order(thd, &tables, fields, all_fields, order) || + if (setup_ref_array(thd, &thd->lex.select_lex.ref_pointer_array, + order_num)|| + setup_order(thd, thd->lex.select_lex.ref_pointer_array, + &tables, fields, all_fields, order) || !(sortorder=make_unireg_sortorder(order, &length)) || (table->found_records = filesort(thd, table, sortorder, length, (SQL_SELECT *) 0, @@ -205,6 +212,7 @@ int mysql_update(THD *thd, == HA_POS_ERROR) { delete select; + free_ulderlayed_joins(thd, &thd->lex.select_lex); DBUG_RETURN(-1); } } @@ -258,6 +266,7 @@ int mysql_update(THD *thd, if (error >= 0) { delete select; + free_ulderlayed_joins(thd, &thd->lex.select_lex); DBUG_RETURN(-1); } } @@ -343,6 +352,7 @@ int mysql_update(THD *thd, } delete select; + free_ulderlayed_joins(thd, &thd->lex.select_lex); if (error >= 0) send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0); /* purecov: inspected */ else @@ -357,6 +367,7 @@ int mysql_update(THD *thd, } thd->count_cuted_fields=0; /* calc cuted fields */ free_io_cache(table); + DBUG_RETURN(0); } @@ -388,7 +399,7 @@ int mysql_multi_update(THD *thd, DBUG_RETURN(res); thd->select_limit=HA_POS_ERROR; - if (setup_fields(thd, table_list, *fields, 1, 0, 0)) + if (setup_fields(thd, 0, table_list, *fields, 1, 0, 0)) DBUG_RETURN(-1); /* @@ -411,8 +422,9 @@ int mysql_multi_update(THD *thd, DBUG_RETURN(-1); List<Item> total_list; - res= mysql_select(thd,table_list,total_list, - conds, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL, + res= mysql_select(thd, &select_lex->ref_pointer_array, + table_list, select_lex->with_wild, total_list, + conds, 0, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL, (ORDER *)NULL, options | SELECT_NO_JOIN_CACHE, result, unit, select_lex, 0); @@ -467,7 +479,7 @@ int multi_update::prepare(List<Item> ¬_used_values, SELECT_LEX_UNIT *unit) reference tables */ - if (setup_fields(thd, all_tables, *values, 1,0,0)) + if (setup_fields(thd, 0, all_tables, *values, 1, 0, 0)) DBUG_RETURN(1); /* diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index ed8e8f0fb51102264ec5b0b0ef6dd7a4ed9f0354..de20d8c2b6efd2bbf00197e31058fd76eeb446f5 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1760,8 +1760,10 @@ select_item_list: | select_item | '*' { - if (add_item_to_list(YYTHD, new Item_field(NULL,NULL,"*"))) + THD *thd= YYTHD; + if (add_item_to_list(thd, new Item_field(NULL, NULL, "*"))) YYABORT; + (thd->lex.current_select->select_lex()->with_wild)++; }; @@ -3631,10 +3633,19 @@ insert_ident: | table_wild { $$=$1; }; table_wild: - ident '.' '*' { $$ = new Item_field(NullS,$1.str,"*"); } + ident '.' '*' + { + $$ = new Item_field(NullS,$1.str,"*"); + Lex->current_select->select_lex()->with_wild++; + } | ident '.' ident '.' '*' - { $$ = new Item_field((YYTHD->client_capabilities & - CLIENT_NO_SCHEMA ? NullS : $1.str),$3.str,"*"); }; + { + $$ = new Item_field((YYTHD->client_capabilities & + CLIENT_NO_SCHEMA ? NullS : $1.str), + $3.str,"*"); + Lex->current_select->select_lex()->with_wild++; + } + ; order_ident: expr { $$=$1; };