diff options
-rw-r--r-- | mysql-test/r/subselect.result | 12 | ||||
-rw-r--r-- | mysql-test/t/subselect.test | 5 | ||||
-rw-r--r-- | sql/item.cc | 62 | ||||
-rw-r--r-- | sql/item.h | 11 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 21 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 18 | ||||
-rw-r--r-- | sql/item_func.cc | 19 | ||||
-rw-r--r-- | sql/item_func.h | 19 | ||||
-rw-r--r-- | sql/item_strfunc.h | 16 | ||||
-rw-r--r-- | sql/item_subselect.cc | 9 | ||||
-rw-r--r-- | sql/item_subselect.h | 2 | ||||
-rw-r--r-- | sql/item_sum.cc | 13 | ||||
-rw-r--r-- | sql/item_sum.h | 8 | ||||
-rw-r--r-- | sql/item_uniq.h | 2 | ||||
-rw-r--r-- | sql/sql_base.cc | 6 | ||||
-rw-r--r-- | sql/sql_class.cc | 2 | ||||
-rw-r--r-- | sql/sql_class.h | 1 | ||||
-rw-r--r-- | sql/sql_handler.cc | 2 | ||||
-rw-r--r-- | sql/sql_lex.cc | 4 | ||||
-rw-r--r-- | sql/sql_lex.h | 5 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 4 | ||||
-rw-r--r-- | sql/sql_select.cc | 28 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 7 |
23 files changed, 177 insertions, 99 deletions
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 37a66993ef2..bd92c496f29 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -65,8 +65,8 @@ a select b,(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) from t4; b (select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) 8 7.5000 -8 6.0000 -9 5.5000 +8 4.5000 +9 7.5000 select * from t3 where exists (select * from t2 where t2.b=t3.a); a 7 @@ -74,4 +74,12 @@ select * from t3 where not exists (select * from t2 where t2.b=t3.a); a 6 3 +insert into t4 values (12,7),(1,7),(10,9),(9,6),(7,6),(3,9); +select b,max(a) as ma from t4 group by b having b < (select max(t2.a) +from t2 where t2.b=t4.b); +b ma +select b,max(a) as ma from t4 group by b having b >= (select max(t2.a) +from t2 where t2.b=t4.b); +b ma +7 12 drop table t1,t2,t3,t4; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 78300dc3e09..7b1ebdcbc27 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -28,4 +28,9 @@ select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from select b,(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) from t4; select * from t3 where exists (select * from t2 where t2.b=t3.a); select * from t3 where not exists (select * from t2 where t2.b=t3.a); +insert into t4 values (12,7),(1,7),(10,9),(9,6),(7,6),(3,9); +select b,max(a) as ma from t4 group by b having b < (select max(t2.a) +from t2 where t2.b=t4.b); +select b,max(a) as ma from t4 group by b having b >= (select max(t2.a) +from t2 where t2.b=t4.b); drop table t1,t2,t3,t4; diff --git a/sql/item.cc b/sql/item.cc index 415fe4d72af..81c5168b72d 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -446,12 +446,13 @@ String *Item_copy_string::val_str(String *str) /* ARGSUSED */ bool Item::fix_fields(THD *thd, - struct st_table_list *list) + struct st_table_list *list, + Item ** ref) { return 0; } -bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables) +bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { if (!field) // If field is not checked { @@ -467,7 +468,7 @@ bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables) mention of table name, but if we join tables in one list it will cause error ER_NON_UNIQ_ERROR in find_field_in_tables. */ - SELECT_LEX *last; + SELECT_LEX *last= 0; for (SELECT_LEX *sl= thd->lex.select->outer_select(); sl && !tmp; sl= sl->outer_select()) @@ -476,6 +477,8 @@ bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables) if (!tmp) return 1; else + { + depended_from= last; /* Mark all selects from resolved to 1 before select where was found table as depended (of select where was found table) @@ -493,6 +496,7 @@ bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables) tbl= tbl->next) tbl->shared= 1; } + } } set_field(tmp); } @@ -504,6 +508,14 @@ bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables) table->used_fields++; table->used_keys&=field->part_of_key; } + if (depended_from != 0 && depended_from->having_fix_field) + { + *ref= new Item_ref((char *)db_name, (char *)table_name, + (char *)field_name); + if (!*ref) + return 1; + return (*ref)->fix_fields(thd, tables, ref); + } return 0; } @@ -787,12 +799,50 @@ bool Item_null::send(THD *thd, String *packet) Find field in select list having the same name */ -bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables) +bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) { if (!ref) { - if (!(ref=find_item_in_list(this,thd->lex.select->item_list))) - return 1; + if (!(ref= find_item_in_list(this,thd->lex.select->item_list))) + { + /* + We can't find table field in table list of current select, + consequently we have to find it in outer subselect(s). + We can't join lists of outer & current select, because of scope + of view rules. For example if both tables (outer & current) have + field 'field' it is not mistake to refer to this field without + mention of table name, but if we join tables in one list it will + cause error ER_NON_UNIQ_ERROR in find_field_in_tables. + */ + SELECT_LEX *last=0; + for (SELECT_LEX *sl= thd->lex.select->outer_select(); + sl && !ref; + sl= sl->outer_select()) + ref= find_item_in_list(this, (last= sl)->item_list); + if (!ref) + return 1; + else + { + depended_from= last; + /* + Mark all selects from resolved to 1 before select where was + found table as depended (of select where was found table) + */ + for (SELECT_LEX *s= thd->lex.select; + s &&s != last; + s= s->outer_select()) + if( !s->depended ) + { + s->depended= 1; //Select is depended of outer select + //Tables will be reopened many times + for (TABLE_LIST *tbl= + (TABLE_LIST*)s->table_list.first; + tbl; + tbl= tbl->next) + tbl->shared= 1; + } + } + } max_length= (*ref)->max_length; maybe_null= (*ref)->maybe_null; decimals= (*ref)->decimals; diff --git a/sql/item.h b/sql/item.h index e6debdf2afc..187e3903b84 100644 --- a/sql/item.h +++ b/sql/item.h @@ -52,7 +52,7 @@ public: virtual ~Item() { name=0; } /*lint -e1509 */ void set_name(char* str,uint length=0); void init_make_field(Send_field *tmp_field,enum enum_field_types type); - virtual bool fix_fields(THD *,struct st_table_list *); + virtual bool fix_fields(THD *, struct st_table_list *, Item **); virtual bool save_in_field(Field *field); virtual void save_org_in_field(Field *field) { (void) save_in_field(field); } @@ -85,15 +85,18 @@ public: }; +class st_select_lex; class Item_ident :public Item { public: const char *db_name; 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) + :db_name(db_name_par),table_name(table_name_par), + field_name(field_name_par), depended_from(0) { name = (char*) field_name_par; } const char *full_name() const; }; @@ -120,7 +123,7 @@ public: String *str_result(String* tmp); bool send(THD *thd, String *str_arg) { return result_field->send(thd,str_arg); } void make_field(Send_field *field); - bool fix_fields(THD *,struct st_table_list *); + bool fix_fields(THD *, struct st_table_list *, Item **); bool save_in_field(Field *field); void save_org_in_field(Field *field); table_map used_tables() const; @@ -390,7 +393,7 @@ public: } bool send(THD *thd, String *tmp) { return (*ref)->send(thd, tmp); } void make_field(Send_field *field) { (*ref)->make_field(field); } - bool fix_fields(THD *,struct st_table_list *); + bool fix_fields(THD *, struct st_table_list *, Item **); bool save_in_field(Field *field) { return (*ref)->save_in_field(field); } void save_org_in_field(Field *field) { (*ref)->save_org_in_field(field); } enum Item_result result_type () const { return (*ref)->result_type(); } diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 8433ae5bfba..0fc9a1f0e4c 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -727,12 +727,12 @@ double Item_func_case::val() bool -Item_func_case::fix_fields(THD *thd,TABLE_LIST *tables) +Item_func_case::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { - if (first_expr && first_expr->fix_fields(thd,tables) || - else_expr && else_expr->fix_fields(thd,tables)) + if (first_expr && first_expr->fix_fields(thd, tables, &first_expr) || + else_expr && else_expr->fix_fields(thd, tables, &else_expr)) return 1; - if (Item_func::fix_fields(thd,tables)) + if (Item_func::fix_fields(thd, tables, ref)) return 1; if (first_expr) { @@ -1074,7 +1074,7 @@ longlong Item_func_bit_and::val_int() bool -Item_cond::fix_fields(THD *thd,TABLE_LIST *tables) +Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { List_iterator<Item> li(list); Item *item; @@ -1096,7 +1096,7 @@ Item_cond::fix_fields(THD *thd,TABLE_LIST *tables) #endif item= *li.ref(); // new current item } - if (item->fix_fields(thd,tables)) + if (item->fix_fields(thd, tables, li.ref())) return 1; /* purecov: inspected */ used_tables_cache|=item->used_tables(); with_sum_func= with_sum_func || item->with_sum_func; @@ -1272,9 +1272,9 @@ Item_func::optimize_type Item_func_like::select_optimize() const return OPTIMIZE_NONE; } -bool Item_func_like::fix_fields(THD *thd,struct st_table_list *tlist) +bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref) { - if (Item_bool_func2::fix_fields(thd, tlist)) + if (Item_bool_func2::fix_fields(thd, tlist, ref)) return 1; /* @@ -1324,9 +1324,10 @@ bool Item_func_like::fix_fields(THD *thd,struct st_table_list *tlist) #ifdef USE_REGEX bool -Item_func_regex::fix_fields(THD *thd,TABLE_LIST *tables) +Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { - if (args[0]->fix_fields(thd,tables) || args[1]->fix_fields(thd,tables)) + if (args[0]->fix_fields(thd, tables, args) || + args[1]->fix_fields(thd,tables, args + 1)) return 1; /* purecov: inspected */ with_sum_func=args[0]->with_sum_func || args[1]->with_sum_func; max_length=1; decimals=0; diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 302ad88905e..08c5a30c57c 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -177,9 +177,10 @@ public: Item_func_interval(Item *a,List<Item> &list) :Item_int_func(list),item(a),intervals(0) {} longlong val_int(); - bool fix_fields(THD *thd,struct st_table_list *tlist) + bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref) { - return (item->fix_fields(thd,tlist) || Item_func::fix_fields(thd,tlist)); + return (item->fix_fields(thd, tlist, &item) || + Item_func::fix_fields(thd, tlist, ref)); } void fix_length_and_dec(); ~Item_func_interval() { delete item; } @@ -259,7 +260,7 @@ public: enum Item_result result_type () const { return cached_result_type; } const char *func_name() const { return "case"; } void print(String *str); - bool fix_fields(THD *thd,struct st_table_list *tlist); + bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref); Item *find_item(String *str); }; @@ -409,9 +410,10 @@ class Item_func_in :public Item_int_func Item_func_in(Item *a,List<Item> &list) :Item_int_func(list),item(a),array(0),in_item(0) {} longlong val_int(); - bool fix_fields(THD *thd,struct st_table_list *tlist) + bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref) { - return (item->fix_fields(thd,tlist) || Item_func::fix_fields(thd,tlist)); + return (item->fix_fields(thd, tlist, &item) || + Item_func::fix_fields(thd, tlist, ref)); } void fix_length_and_dec(); ~Item_func_in() { delete item; delete array; delete in_item; } @@ -505,7 +507,7 @@ public: cond_result eq_cmp_result() const { return COND_TRUE; } const char *func_name() const { return "like"; } void fix_length_and_dec(); - bool fix_fields(THD *thd,struct st_table_list *tlist); + bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref); }; #ifdef USE_REGEX @@ -523,7 +525,7 @@ public: regex_compiled(0),regex_is_const(0) {} ~Item_func_regex(); longlong val_int(); - bool fix_fields(THD *thd,struct st_table_list *tlist); + bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref); const char *func_name() const { return "regex"; } }; @@ -552,7 +554,7 @@ public: { list.push_back(i1); list.push_back(i2); } ~Item_cond() { list.delete_elements(); } bool add(Item *item) { return list.push_back(item); } - bool fix_fields(THD *,struct st_table_list *); + bool fix_fields(THD *, struct st_table_list *, Item **ref); enum Type type() const { return COND_ITEM; } List<Item>* argument_list() { return &list; } diff --git a/sql/item_func.cc b/sql/item_func.cc index b14c1b38383..ae3fc7cb8f0 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -58,7 +58,7 @@ Item_func::Item_func(List<Item> &list) } bool -Item_func::fix_fields(THD *thd,TABLE_LIST *tables) +Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { Item **arg,**arg_end; char buff[STACK_BUFF_ALLOC]; // Max argument in function @@ -72,7 +72,7 @@ Item_func::fix_fields(THD *thd,TABLE_LIST *tables) { // Print purify happy for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++) { - if ((*arg)->fix_fields(thd,tables)) + if ((*arg)->fix_fields(thd, tables, arg)) return 1; /* purecov: inspected */ if ((*arg)->maybe_null) maybe_null=1; @@ -1102,7 +1102,7 @@ udf_handler::~udf_handler() bool -udf_handler::fix_fields(THD *thd,TABLE_LIST *tables,Item_result_field *func, +udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, uint arg_count, Item **arguments) { char buff[STACK_BUFF_ALLOC]; // Max argument in function @@ -1146,7 +1146,7 @@ udf_handler::fix_fields(THD *thd,TABLE_LIST *tables,Item_result_field *func, arg != arg_end ; arg++,i++) { - if ((*arg)->fix_fields(thd,tables)) + if ((*arg)->fix_fields(thd, tables, arg)) return 1; if ((*arg)->binary) func->binary=1; @@ -1765,11 +1765,12 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name, } -bool Item_func_set_user_var::fix_fields(THD *thd,TABLE_LIST *tables) +bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables, + Item **ref) { if (!thd) thd=current_thd; - if (Item_func::fix_fields(thd,tables) || + if (Item_func::fix_fields(thd, tables, ref) || !(entry= get_variable(&thd->user_vars, name, 1))) return 1; entry->update_query_id=thd->query_id; @@ -2095,7 +2096,7 @@ void Item_func_match::init_search(bool no_order) } } -bool Item_func_match::fix_fields(THD *thd,struct st_table_list *tlist) +bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) { List_iterator<Item> li(fields); Item *item; @@ -2108,7 +2109,7 @@ bool Item_func_match::fix_fields(THD *thd,struct st_table_list *tlist) modifications to find_best and auto_close as complement to auto_init code above. */ - if (Item_func::fix_fields(thd,tlist) || !const_item()) + if (Item_func::fix_fields(thd, tlist, ref) || !const_item()) { my_error(ER_WRONG_ARGUMENTS,MYF(0),"AGAINST"); return 1; @@ -2116,7 +2117,7 @@ bool Item_func_match::fix_fields(THD *thd,struct st_table_list *tlist) while ((item=li++)) { - if (item->fix_fields(thd,tlist)) + if (item->fix_fields(thd, tlist, li.ref())) return 1; if (item->type() == Item::REF_ITEM) li.replace(item= *((Item_ref *)item)->ref); diff --git a/sql/item_func.h b/sql/item_func.h index 0056126d50e..86b2a17931d 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -99,7 +99,7 @@ public: } Item_func(List<Item> &list); ~Item_func() {} /* Nothing to do; Items are freed automaticly */ - bool fix_fields(THD *,struct st_table_list *); + bool fix_fields(THD *,struct st_table_list *, Item **ref); void make_field(Send_field *field); table_map used_tables() const; void update_used_tables(); @@ -567,9 +567,10 @@ public: Item_func_field(Item *a,List<Item> &list) :Item_int_func(list),item(a) {} ~Item_func_field() { delete item; } longlong val_int(); - bool fix_fields(THD *thd,struct st_table_list *tlist) + bool fix_fields(THD *thd,struct st_table_list *tlist, Item **ref) { - return (item->fix_fields(thd,tlist) || Item_func::fix_fields(thd,tlist)); + return (item->fix_fields(thd, tlist, &item) || + Item_func::fix_fields(thd, tlist, ref)); } void update_used_tables() { @@ -708,11 +709,11 @@ public: :Item_func(list), udf(udf_arg) {} ~Item_udf_func() {} const char *func_name() const { return udf.name(); } - bool fix_fields(THD *thd,struct st_table_list *tables) + bool fix_fields(THD *thd, struct st_table_list *tables, Item **ref) { - bool res=udf.fix_fields(thd,tables,this,arg_count,args); - used_tables_cache=udf.used_tables_cache; - const_item_cache=udf.const_item_cache; + bool res= udf.fix_fields(thd, tables, this, arg_count, args); + used_tables_cache= udf.used_tables_cache; + const_item_cache= udf.const_item_cache; return res; } Item_result result_type () const { return udf.result_type(); } @@ -867,7 +868,7 @@ public: void update_hash(void *ptr, uint length, enum Item_result type); bool update(); enum Item_result result_type () const { return cached_result_type; } - bool fix_fields(THD *thd,struct st_table_list *tables); + bool fix_fields(THD *thd, struct st_table_list *tables, Item **ref); void fix_length_and_dec(); void print(String *str); const char *func_name() const { return "set_user_var"; } @@ -941,7 +942,7 @@ public: } enum Functype functype() const { return FT_FUNC; } void update_used_tables() {} - bool fix_fields(THD *thd,struct st_table_list *tlist); + bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref); bool eq(const Item *, bool binary_cmp) const; longlong val_int() { return val()!=0.0; } double val(); diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index a273abaf614..6e15b8317d1 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -79,10 +79,10 @@ public: String *val_str(String *); void fix_length_and_dec(); void update_used_tables(); - bool fix_fields(THD *thd,struct st_table_list *tlist) + bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) { - return (separator->fix_fields(thd,tlist) - || Item_func::fix_fields(thd,tlist)); + return (separator->fix_fields(thd, tlist, &separator) + || Item_func::fix_fields(thd, tlist, ref)); } const char *func_name() const { return "concat_ws"; } }; @@ -325,9 +325,10 @@ public: double val(); longlong val_int(); String *val_str(String *str); - bool fix_fields(THD *thd,struct st_table_list *tlist) + bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) { - return (item->fix_fields(thd,tlist) || Item_func::fix_fields(thd,tlist)); + return (item->fix_fields(thd, tlist, &item) || + Item_func::fix_fields(thd, tlist, ref)); } void fix_length_and_dec(); void update_used_tables(); @@ -344,9 +345,10 @@ public: Item_func_make_set(Item *a,List<Item> &list) :Item_str_func(list),item(a) {} ~Item_func_make_set() { delete item; } String *val_str(String *str); - bool fix_fields(THD *thd,struct st_table_list *tlist) + bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) { - return (item->fix_fields(thd,tlist) || Item_func::fix_fields(thd,tlist)); + return (item->fix_fields(thd, tlist, &item) || + Item_func::fix_fields(thd, tlist, ref)); } void fix_length_and_dec(); void update_used_tables(); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index d8f9cf40d50..2bff2af45e4 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -75,15 +75,8 @@ void Item_subselect::make_field (Send_field *tmp_field) } } -bool Item_subselect::fix_fields(THD *thd,TABLE_LIST *tables) +bool Item_subselect::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { - - if (thd->having_fix_field) - { - //TODO: subselects in having do not suported now - my_printf_error(ER_SYNTAX_ERROR, ER(ER_SYNTAX_ERROR), MYF(0)); - return 1; - } // Is it one field subselect? if (select_lex->item_list.elements > max_columns) { diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 79832116c67..3f363df33df 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -63,7 +63,7 @@ public: enum Type type() const; bool is_null() { return null_value; } void make_field (Send_field *); - bool fix_fields(THD *thd, TABLE_LIST *tables); + bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref); table_map used_tables() const; friend class select_subselect; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 6ef968c33f7..809dd65d52b 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -112,7 +112,7 @@ Item_sum_int::val_str(String *str) bool -Item_sum_num::fix_fields(THD *thd,TABLE_LIST *tables) +Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { if (!thd->allow_sum_func) { @@ -124,7 +124,7 @@ Item_sum_num::fix_fields(THD *thd,TABLE_LIST *tables) maybe_null=0; for (uint i=0 ; i < arg_count ; i++) { - if (args[i]->fix_fields(thd,tables)) + if (args[i]->fix_fields(thd, tables, args + i)) return 1; if (decimals < args[i]->decimals) decimals=args[i]->decimals; @@ -140,7 +140,7 @@ Item_sum_num::fix_fields(THD *thd,TABLE_LIST *tables) bool -Item_sum_hybrid::fix_fields(THD *thd,TABLE_LIST *tables) +Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { Item *item=args[0]; if (!thd->allow_sum_func) @@ -149,7 +149,7 @@ Item_sum_hybrid::fix_fields(THD *thd,TABLE_LIST *tables) return 1; } thd->allow_sum_func=0; // No included group funcs - if (item->fix_fields(thd,tables)) + if (item->fix_fields(thd, tables, args)) return 1; hybrid_type=item->result_type(); if (hybrid_type == INT_RESULT) @@ -930,9 +930,10 @@ Item_sum_count_distinct::~Item_sum_count_distinct() } -bool Item_sum_count_distinct::fix_fields(THD *thd,TABLE_LIST *tables) +bool Item_sum_count_distinct::fix_fields(THD *thd, TABLE_LIST *tables, + Item **ref) { - if (Item_sum_num::fix_fields(thd,tables) || + if (Item_sum_num::fix_fields(thd, tables, ref) || !(tmp_table_param= new TMP_TABLE_PARAM)) return 1; return 0; diff --git a/sql/item_sum.h b/sql/item_sum.h index a963799b6a7..3e67f1e3624 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -80,7 +80,7 @@ public: 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) {} - bool fix_fields(THD *,struct st_table_list *); + bool fix_fields(THD *, TABLE_LIST *, Item **); longlong val_int() { return (longlong) val(); } /* Real as default */ String *val_str(String*str); void reset_field(); @@ -146,7 +146,7 @@ class Item_sum_count_distinct :public Item_sum_int { TABLE *table; table_map used_table_cache; - bool fix_fields(THD *thd,TABLE_LIST *tables); + bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref); uint32 *field_lengths; TMP_TABLE_PARAM *tmp_table_param; TREE tree; @@ -283,7 +283,7 @@ 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) {} - bool fix_fields(THD *,struct st_table_list *); + bool fix_fields(THD *, TABLE_LIST *, Item **); table_map used_tables() const { return used_table_cache; } bool const_item() const { return !used_table_cache; } @@ -382,7 +382,7 @@ public: { quick_group=0;} ~Item_udf_sum() {} const char *func_name() const { return udf.name(); } - bool fix_fields(THD *thd,struct st_table_list *tables) + bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { return udf.fix_fields(thd,tables,this,this->arg_count,this->args); } diff --git a/sql/item_uniq.h b/sql/item_uniq.h index 4be64ecc74a..e56632e7289 100644 --- a/sql/item_uniq.h +++ b/sql/item_uniq.h @@ -42,5 +42,5 @@ public: bool add() { return 0; } void reset_field() {} void update_field(int offset) {} - bool fix_fields(THD *thd,struct st_table_list *tlist) { return 0;} + bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) { return 0;} }; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 92606716c63..b3ef043f582 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1874,7 +1874,7 @@ int setup_fields(THD *thd, TABLE_LIST *tables, List<Item> &fields, } else { - if (item->fix_fields(thd,tables)) + if (item->fix_fields(thd, tables, it.ref())) DBUG_RETURN(-1); /* purecov: inspected */ if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM && sum_func_list) @@ -2025,7 +2025,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) if (*conds) { thd->where="where clause"; - if ((*conds)->fix_fields(thd,tables)) + if ((*conds)->fix_fields(thd, tables, conds)) DBUG_RETURN(1); } @@ -2036,7 +2036,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) { /* Make a join an a expression */ thd->where="on clause"; - if (table->on_expr->fix_fields(thd,tables)) + if (table->on_expr->fix_fields(thd, tables, &table->on_expr)) DBUG_RETURN(1); thd->cond_count++; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index c8914702ae7..9922eacdec1 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -81,7 +81,7 @@ static void free_var(user_var_entry *entry) THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0), insert_id_used(0), in_lock_tables(0), - global_read_lock(0), bootstrap(0), having_fix_field(0) + global_read_lock(0), bootstrap(0) { host=user=priv_user=db=query=ip=0; host_or_ip="unknown ip"; diff --git a/sql/sql_class.h b/sql/sql_class.h index 9b708e35a1e..a6b7e45ab03 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -453,7 +453,6 @@ public: bool query_error, bootstrap, cleanup_done; bool safe_to_cache_query; bool volatile killed; - bool having_fix_field; //TRUE when having fix field called bool prepare_command; ulong param_count,current_param_number; Error<mysql_st_error> err_list; diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 4ecd5dbca36..a98012653b3 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -106,7 +106,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, } tables->table=table; - if (cond && cond->fix_fields(thd,tables)) + if (cond && cond->fix_fields(thd, tables, &cond)) return -1; if (keyname) diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index bcf212f6bd2..9ae5cdeeb15 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -942,8 +942,8 @@ void st_select_lex::init_select() interval_list.empty(); use_index.empty(); ftfunc_list.empty(); - linkage=UNSPECIFIED_TYPE; - depended= 0; + linkage= UNSPECIFIED_TYPE; + depended= having_fix_field= 0; } /* diff --git a/sql/sql_lex.h b/sql/sql_lex.h index ca824b3eab8..f4e788b67e2 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -253,7 +253,10 @@ public: uint in_sum_expr; bool create_refs, braces, /* SELECT ... UNION (SELECT ... ) <- this braces */ - depended; /* depended from outer select subselect */ + depended, /* depended from outer select subselect */ + /* TRUE when having fix field called in processing of this SELECT */ + having_fix_field; + void init_query(); void init_select(); st_select_lex_unit* master_unit() { return (st_select_lex_unit*) master; } diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index d5896901935..d41aca21fb8 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -448,7 +448,7 @@ static bool mysql_test_upd_fields(THD *thd, TABLE_LIST *table_list, static bool mysql_test_select_fields(THD *thd, TABLE_LIST *tables, List<Item> &fields, List<Item> &values, COND *conds, ORDER *order, ORDER *group, - Item *having,thr_lock_type lock_type) + Item *having, thr_lock_type lock_type) { TABLE *table; bool hidden_group_fields; @@ -470,7 +470,7 @@ static bool mysql_test_select_fields(THD *thd, TABLE_LIST *tables, { thd->where="having clause"; thd->allow_sum_func=1; - if (having->fix_fields(thd,tables) || thd->fatal_error) + if (having->fix_fields(thd, tables, &having) || thd->fatal_error) DBUG_RETURN(1); if (having->with_sum_func) having->split_sum_func(all_fields); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 025a5c600a5..d70b7dfdbed 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -227,10 +227,9 @@ JOIN::prepare(TABLE_LIST *tables_init, { thd->where="having clause"; thd->allow_sum_func=1; - bool having_fix_field_store= thd->having_fix_field; - thd->having_fix_field= 1; - bool having_fix_rc= having->fix_fields(thd,tables_list); - thd->having_fix_field= having_fix_field_store; + select_lex->having_fix_field= 1; + bool having_fix_rc= having->fix_fields(thd, tables_list, &having); + select_lex->having_fix_field= 0; if (having_fix_rc || thd->fatal_error) DBUG_RETURN(-1); /* purecov: inspected */ if (having->with_sum_func) @@ -349,7 +348,7 @@ JOIN::optimize() } else if ((conds=new Item_cond_and(conds,having))) { - conds->fix_fields(thd, tables_list); + conds->fix_fields(thd, tables_list, &conds); conds->change_ref_to_fields(thd, tables_list); having= 0; } @@ -612,6 +611,15 @@ JOIN::reinit() if (setup_tables(tables_list)) DBUG_RETURN(1); + + // Reset of sum functions + first_record= 0; + if (sum_funcs) + { + Item_sum *func, **func_ptr= sum_funcs; + while ((func= *(func_ptr++))) + func->null_value= 1; + } DBUG_RETURN(0); } @@ -3381,7 +3389,7 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value) 21)))) { cond=new_cond; - cond->fix_fields(thd,0); + cond->fix_fields(thd, 0, &cond); } thd->insert_id(0); // Clear for next request } @@ -3395,7 +3403,7 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value) if ((new_cond= new Item_func_eq(args[0],new Item_int("0", 0, 2)))) { cond=new_cond; - cond->fix_fields(thd,0); + cond->fix_fields(thd, 0, &cond); } } } @@ -6429,7 +6437,7 @@ find_order_in_list(THD *thd,TABLE_LIST *tables,ORDER *order,List<Item> &fields, return 0; } order->in_field_list=0; - if ((*order->item)->fix_fields(thd,tables) || thd->fatal_error) + if ((*order->item)->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(); @@ -6527,7 +6535,7 @@ setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields, else { thd->where="procedure list"; - if ((*new_field->item)->fix_fields(thd,tables)) + if ((*new_field->item)->fix_fields(thd, tables, new_field->item)) DBUG_RETURN(1); /* purecov: inspected */ thd->where=0; all_fields.push_front(*new_field->item); @@ -7092,7 +7100,7 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab) Here we pass 0 as the first argument to fix_fields that don't need to do any stack checking (This is already done in the initial fix_fields). */ - cond->fix_fields((THD *) 0,(TABLE_LIST *) 0); + cond->fix_fields((THD *) 0,(TABLE_LIST *) 0, (Item**)&cond); if (join_tab->select) { error=(int) cond->add(join_tab->select->cond); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index faa63afa6c7..f237aac81d3 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2973,7 +2973,7 @@ kill: KILL_SYM expr { LEX *lex=Lex; - if ($2->fix_fields(lex->thd,0)) + if ($2->fix_fields(lex->thd, 0, &$2)) { send_error(&lex->thd->net, ER_SET_CONSTANTS_ONLY); YYABORT; @@ -3469,7 +3469,8 @@ option_value: | '@' ident_or_text equal expr { Item_func_set_user_var *item = new Item_func_set_user_var($2,$4); - if (item->fix_fields(current_thd,0) || item->update()) + if (item->fix_fields(current_thd, 0, (Item**) &item) || + item->update()) { send_error(¤t_thd->net, ER_SET_CONSTANTS_ONLY); YYABORT; @@ -3501,7 +3502,7 @@ option_value: { THD *thd=current_thd; Item *item= $3; - if (item->fix_fields(current_thd,0)) + if (item->fix_fields(current_thd, 0, &item)) { send_error(&thd->net, ER_SET_CONSTANTS_ONLY); YYABORT; |