diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item.cc | 45 | ||||
-rw-r--r-- | sql/item.h | 103 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 302 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 234 | ||||
-rw-r--r-- | sql/item_row.cc | 42 | ||||
-rw-r--r-- | sql/item_row.h | 21 | ||||
-rw-r--r-- | sql/item_subselect.cc | 118 | ||||
-rw-r--r-- | sql/item_subselect.h | 23 | ||||
-rw-r--r-- | sql/item_sum.cc | 44 | ||||
-rw-r--r-- | sql/item_sum.h | 61 | ||||
-rw-r--r-- | sql/lex.h | 2 | ||||
-rw-r--r-- | sql/mysqld.cc | 3 | ||||
-rw-r--r-- | sql/sql_class.cc | 4 | ||||
-rw-r--r-- | sql/sql_list.h | 10 | ||||
-rw-r--r-- | sql/sql_select.cc | 15 | ||||
-rw-r--r-- | sql/sql_union.cc | 2 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 8 |
17 files changed, 854 insertions, 183 deletions
diff --git a/sql/item.cc b/sql/item.cc index 5e74820a3f8..4fbbfdd4772 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -46,6 +46,12 @@ Item::Item(): loop_id= 0; } +Item_ref_in_optimizer::Item_ref_in_optimizer(Item_in_optimizer *master, + char *table_name_par, + char *field_name_par): + Item_ref(master->args, table_name_par, field_name_par), owner(master) {} + + bool Item::check_loop(uint id) { DBUG_ENTER("Item::check_loop"); @@ -436,6 +442,20 @@ String *Item_copy_string::val_str(String *str) return &str_value; } +double Item_ref_in_optimizer::val() +{ + return owner->get_cache(); +} +longlong Item_ref_in_optimizer::val_int() +{ + return owner->get_cache_int(); +} +String* Item_ref_in_optimizer::val_str(String* s) +{ + return owner->get_cache_str(s); +} + + /* Functions to convert item to field (for send_fields) */ @@ -511,10 +531,31 @@ bool Item_asterisk_remover::fix_fields(THD *thd, res= item->fix_fields(thd, list, &item); else thd->fatal_error= 1; // no item given => out of memory - *ref= item; DBUG_RETURN(res); } +double Item_ref_null_helper::val() +{ + double tmp= (*ref)->val_result(); + owner->was_null|= null_value= (*ref)->null_value; + return tmp; +} +longlong Item_ref_null_helper::val_int() +{ + longlong tmp= (*ref)->val_int_result(); + owner->was_null|= null_value= (*ref)->null_value; + return tmp; +} +String* Item_ref_null_helper::val_str(String* s) +{ + String* tmp= (*ref)->str_result(s); + owner->was_null|= null_value= (*ref)->null_value; + return tmp; +} +bool Item_ref_null_helper::get_date(TIME *ltime, bool fuzzydate) +{ + return (owner->was_null|= null_value= (*ref)->get_date(ltime, fuzzydate)); +} bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { @@ -686,7 +727,7 @@ void Item_avg_field::make_field(Send_field *tmp_field) init_make_field(tmp_field,FIELD_TYPE_DOUBLE); } -void Item_std_field::make_field(Send_field *tmp_field) +void Item_variance_field::make_field(Send_field *tmp_field) { init_make_field(tmp_field,FIELD_TYPE_DOUBLE); } diff --git a/sql/item.h b/sql/item.h index 4dff0591c09..c4cf534e16c 100644 --- a/sql/item.h +++ b/sql/item.h @@ -33,7 +33,8 @@ public: enum Type {FIELD_ITEM,FUNC_ITEM,SUM_FUNC_ITEM,STRING_ITEM, INT_ITEM,REAL_ITEM,NULL_ITEM,VARBIN_ITEM, COPY_STR_ITEM,FIELD_AVG_ITEM, DEFAULT_ITEM, - PROC_ITEM,COND_ITEM,REF_ITEM,FIELD_STD_ITEM, CONST_ITEM, + PROC_ITEM,COND_ITEM,REF_ITEM,FIELD_STD_ITEM, + FIELD_VARIANCE_ITEM,CONST_ITEM, SUBSELECT_ITEM, ROW_ITEM}; enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE }; @@ -72,7 +73,6 @@ public: virtual double val_result() { return val(); } virtual longlong val_int_result() { return val_int(); } virtual String *str_result(String* tmp) { return val_str(tmp); } - virtual bool is_null_result() { return is_null(); } virtual table_map used_tables() const { return (table_map) 0L; } virtual bool basic_const_item() const { return 0; } virtual Item *new_item() { return 0; } /* Only for const items */ @@ -100,6 +100,8 @@ public: virtual Item* el(uint i) { return this; } virtual Item** addr(uint i) { return 0; } virtual bool check_cols(uint c); + // It is not row => null inside is impossible + virtual bool null_inside() { return 0; }; }; @@ -122,6 +124,25 @@ public: String* val_str(String* s) { return item->val_str(s); } void make_field(Send_field* f) { item->make_field(f); } bool check_cols(uint col) { return item->check_cols(col); } + bool eq(const Item *item, bool binary_cmp) const + { return item->eq(item, binary_cmp); } + bool is_null() + { + item->val_int(); + return item->null_value; + } + bool get_date(TIME *ltime, bool fuzzydate) + { + return (null_value=item->get_date(ltime, fuzzydate)); + } + bool send(THD *thd, String *tmp) { return item->send(thd, tmp); } + int save_in_field(Field *field, bool no_conversions) + { + return item->save_in_field(field, no_conversions); + } + void save_org_in_field(Field *field) { item->save_org_in_field(field); } + enum Item_result result_type () const { return item->result_type(); } + table_map used_tables() const { return item->used_tables(); } }; @@ -138,19 +159,6 @@ public: bool fix_fields(THD *, struct st_table_list *, Item ** ref); }; -/* - To resolve '*' field moved to condition -*/ -class Item_asterisk_remover :public Item_wrapper -{ -public: - Item_asterisk_remover(Item *it) - { - item= it; - } - bool fix_fields(THD *, struct st_table_list *, Item ** ref); -}; - class st_select_lex; class Item_ident :public Item { @@ -188,7 +196,6 @@ public: double val_result(); longlong val_int_result(); String *str_result(String* tmp); - bool is_null_result() { return result_field->is_null(); } bool send(THD *thd, String *str_arg) { return result_field->send(thd,str_arg); @@ -384,9 +391,13 @@ public: enum Item_result result_type () const { return STRING_RESULT; } bool basic_const_item() const { return 1; } bool eq(const Item *item, bool binary_cmp) const; - Item *new_item() { return new Item_string(name,str_value.ptr(),max_length,default_charset_info); } + Item *new_item() + { + return new Item_string(name, str_value.ptr(), max_length, + default_charset_info); + } String *const_string() { return &str_value; } - inline void append(char *str,uint length) { str_value.append(str,length); } + inline void append(char *str, uint length) { str_value.append(str, length); } void print(String *str); }; @@ -470,25 +481,25 @@ public: double val() { double tmp=(*ref)->val_result(); - null_value=(*ref)->is_null_result(); + null_value=(*ref)->null_value; return tmp; } longlong val_int() { longlong tmp=(*ref)->val_int_result(); - null_value=(*ref)->is_null_result(); + null_value=(*ref)->null_value; return tmp; } String *val_str(String* tmp) { tmp=(*ref)->str_result(tmp); - null_value=(*ref)->is_null_result(); + null_value=(*ref)->null_value; return tmp; } bool is_null() { (void) (*ref)->val_int_result(); - return (*ref)->is_null_result(); + return (*ref)->null_value; } bool get_date(TIME *ltime,bool fuzzydate) { @@ -505,6 +516,54 @@ public: bool check_loop(uint id); }; +class Item_in_subselect; +class Item_ref_null_helper: public Item_ref +{ +protected: + Item_in_subselect* owner; +public: + Item_ref_null_helper(Item_in_subselect* master, Item **item, + char *table_name_par,char *field_name_par): + Item_ref(item, table_name_par, field_name_par), owner(master) {} + double val(); + longlong val_int(); + String* val_str(String* s); + bool get_date(TIME *ltime, bool fuzzydate); +}; + +/* + To resolve '*' field moved to condition + and register NULL values +*/ +class Item_asterisk_remover :public Item_ref_null_helper +{ + Item *item; +public: + Item_asterisk_remover(Item_in_subselect *master, Item *it, + char *table, char *field): + Item_ref_null_helper(master, &item, table, field), + item(it) + {} + bool fix_fields(THD *, struct st_table_list *, Item ** ref); +}; + +class Item_in_optimizer; +class Item_ref_in_optimizer: public Item_ref +{ +protected: + Item_in_optimizer* owner; +public: + Item_ref_in_optimizer(Item_in_optimizer* master, + char *table_name_par,char *field_name_par); + double val(); + longlong val_int(); + String* val_str(String* s); + bool fix_fields(THD *, struct st_table_list *, Item ** ref) + { + fixed= 1; + return 0; + } +}; /* The following class is used to optimize comparing of date columns diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index dd8d1aeff02..a30faae9a01 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -90,7 +90,7 @@ static bool convert_constant_item(Field *field, Item **item) void Item_bool_func2::fix_length_and_dec() { - max_length=1; // Function returns 0 or 1 + max_length= 1; // Function returns 0 or 1 /* As some compare functions are generated after sql_yacc, @@ -144,7 +144,14 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) } if ((comparators= (Arg_comparator *) sql_alloc(sizeof(Arg_comparator)*n))) for (uint i=0; i < n; i++) + { + if ((*a)->el(i)->cols() != (*b)->el(i)->cols()) + { + my_error(ER_CARDINALITY_COL, MYF(0), (*a)->el(i)->cols()); + return 1; + } comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i)); + } else { my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); @@ -263,6 +270,61 @@ int Arg_comparator::compare_e_row() return 1; } +longlong Item_in_optimizer::val_int() +{ + int_cache_ok= 1; + flt_cache_ok= 0; + str_cache_ok= 0; + int_cache= args[0]->val_int_result(); + if (args[0]->null_value) + { + null_value= 1; + return 0; + } + longlong tmp= args[1]->val_int_result(); + null_value= args[1]->null_value; + return tmp; +} + +longlong Item_in_optimizer::get_cache_int() +{ + if (!int_cache_ok) + { + int_cache_ok= 1; + flt_cache_ok= 0; + str_cache_ok= 0; + int_cache= args[0]->val_int_result(); + null_value= args[0]->null_value; + } + return int_cache; +} + +double Item_in_optimizer::get_cache() +{ + if (!flt_cache_ok) + { + flt_cache_ok= 1; + int_cache_ok= 0; + str_cache_ok= 0; + flt_cache= args[0]->val_result(); + null_value= args[0]->null_value; + } + return flt_cache; +} + +String *Item_in_optimizer::get_cache_str(String *s) +{ + if (!str_cache_ok) + { + str_cache_ok= 1; + int_cache_ok= 0; + flt_cache_ok= 0; + str_value.set(buffer, sizeof(buffer), s->charset()); + str_cache= args[0]->str_result(&str_value); + null_value= args[0]->null_value; + } + return str_cache; +} longlong Item_func_eq::val_int() { @@ -356,7 +418,8 @@ void Item_func_interval::fix_length_and_dec() intervals[i]=args[i]->val(); } } - maybe_null=0; max_length=2; + maybe_null= 0; + max_length= 2; used_tables_cache|=item->used_tables(); } @@ -415,7 +478,7 @@ bool Item_func_interval::check_loop(uint id) void Item_func_between::fix_length_and_dec() { - max_length=1; + max_length= 1; /* As some compare functions are generated after sql_yacc, @@ -968,8 +1031,8 @@ double Item_func_coalesce::val() void Item_func_coalesce::fix_length_and_dec() { - max_length=0; - decimals=0; + max_length= 0; + decimals= 0; cached_result_type = args[0]->result_type(); for (uint i=0 ; i < arg_count ; i++) { @@ -992,6 +1055,11 @@ static int cmp_double(double *a,double *b) return *a < *b ? -1 : *a == *b ? 0 : 1; } +static int cmp_row(cmp_item_row* a, cmp_item_row* b) +{ + return a->compare(b); +} + int in_vector::find(Item *item) { byte *result=get_value(item); @@ -1014,7 +1082,6 @@ int in_vector::find(Item *item) return (int) ((*compare)(base+start*size,result) == 0); } - in_string::in_string(uint elements,qsort_cmp cmp_func) :in_vector(elements,sizeof(String),cmp_func),tmp(buff,sizeof(buff),default_charset_info) {} @@ -1041,6 +1108,29 @@ byte *in_string::get_value(Item *item) return (byte*) item->val_str(&tmp); } +in_row::in_row(uint elements, Item * item) +{ + DBUG_ENTER("in_row::in_row"); + base= (char*) new cmp_item_row[elements]; + size= sizeof(cmp_item_row); + compare= (qsort_cmp) cmp_row; + tmp.store_value(item); + DBUG_VOID_RETURN; +} + +byte *in_row::get_value(Item *item) +{ + tmp.store_value(item); + return (byte *)&tmp; +} + +void in_row::set(uint pos, Item *item) +{ + DBUG_ENTER("in_row::set"); + DBUG_PRINT("enter", ("pos %u item 0x%lx", pos, (ulong) item)); + ((cmp_item_row*) base)[pos].store_value_by_template(&tmp, item); + DBUG_VOID_RETURN; +} in_longlong::in_longlong(uint elements) :in_vector(elements,sizeof(longlong),(qsort_cmp) cmp_longlong) @@ -1053,13 +1143,12 @@ void in_longlong::set(uint pos,Item *item) byte *in_longlong::get_value(Item *item) { - tmp=item->val_int(); + tmp= item->val_int(); if (item->null_value) - return 0; /* purecov: inspected */ + return 0; return (byte*) &tmp; } - in_double::in_double(uint elements) :in_vector(elements,sizeof(double),(qsort_cmp) cmp_double) {} @@ -1071,21 +1160,173 @@ void in_double::set(uint pos,Item *item) byte *in_double::get_value(Item *item) { - tmp=item->val(); + tmp= item->val(); if (item->null_value) return 0; /* purecov: inspected */ return (byte*) &tmp; } +cmp_item* cmp_item::get_comparator (Item *item) +{ + switch (item->result_type()) { + case STRING_RESULT: + if (item->binary()) + return new cmp_item_binary_string; + else + return new cmp_item_sort_string; + break; + case INT_RESULT: + return new cmp_item_int; + break; + case REAL_RESULT: + return new cmp_item_real; + break; + case ROW_RESULT: + return new cmp_item_row; + break; + } + return 0; // to satisfy compiler :) +} + +cmp_item* cmp_item_sort_string::make_same() +{ + return new cmp_item_sort_string_in_static(); +} + +cmp_item* cmp_item_binary_string::make_same() +{ + return new cmp_item_binary_string_in_static(); +} + +cmp_item* cmp_item_int::make_same() +{ + return new cmp_item_int(); +} + +cmp_item* cmp_item_real::make_same() +{ + return new cmp_item_real(); +} + +cmp_item* cmp_item_row::make_same() +{ + return new cmp_item_row(); +} + +void cmp_item_row::store_value(Item *item) +{ + THD *thd= current_thd; + n= item->cols(); + if ((comparators= (cmp_item **) thd->alloc(sizeof(cmp_item *)*n))) + { + item->null_value= 0; + for (uint i=0; i < n; i++) + if ((comparators[i]= cmp_item::get_comparator(item->el(i)))) + { + comparators[i]->store_value(item->el(i)); + item->null_value|= item->el(i)->null_value; + } + else + { + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); + thd->fatal_error= 1; + return; + } + } + else + { + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); + thd->fatal_error= 1; + return; + } +} + +void cmp_item_row::store_value_by_template(cmp_item *t, Item *item) +{ + cmp_item_row *tmpl= (cmp_item_row*) t; + if (tmpl->n != item->cols()) + { + my_error(ER_CARDINALITY_COL, MYF(0), tmpl->n); + return; + } + n= tmpl->n; + if ((comparators= (cmp_item **) sql_alloc(sizeof(cmp_item *)*n))) + { + item->null_value= 0; + for (uint i=0; i < n; i++) + if ((comparators[i]= tmpl->comparators[i]->make_same())) + { + comparators[i]->store_value_by_template(tmpl->comparators[i], + item->el(i)); + item->null_value|= item->el(i)->null_value; + } + else + { + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); + current_thd->fatal_error= 1; + return; + } + } + else + { + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); + current_thd->fatal_error= 1; + return; + } +} + +int cmp_item_row::cmp(Item *arg) +{ + arg->null_value= 0; + if (arg->cols() != n) + { + my_error(ER_CARDINALITY_COL, MYF(0), n); + return 1; + } + bool was_null= 0; + for (uint i=0; i < n; i++) + if (comparators[i]->cmp(arg->el(i))) + { + if (!arg->el(i)->null_value) + return 1; + was_null= 1; + } + return (arg->null_value= was_null); +} + +int cmp_item_row::compare(cmp_item *c) +{ + int res; + cmp_item_row *cmp= (cmp_item_row *) c; + for (uint i=0; i < n; i++) + if ((res= comparators[i]->compare(cmp->comparators[i]))) + return res; + return 0; +} + +bool Item_func_in::nulls_in_row() +{ + Item **arg,**arg_end; + for (arg= args, arg_end= args+arg_count; arg != arg_end ; arg++) + { + if ((*arg)->null_inside()) + return 1; + } + return 0; +} void Item_func_in::fix_length_and_dec() { - if (const_item()) + /* + Row item with NULLs inside can return NULL or FALSE => + they can't be processed as static + */ + if (const_item() && !nulls_in_row()) { switch (item->result_type()) { case STRING_RESULT: if (item->binary()) - array=new in_string(arg_count,(qsort_cmp) stringcmp); /* purecov: inspected */ + array=new in_string(arg_count,(qsort_cmp) stringcmp); else array=new in_string(arg_count,(qsort_cmp) sortcmp); break; @@ -1096,8 +1337,7 @@ void Item_func_in::fix_length_and_dec() array= new in_double(arg_count); break; case ROW_RESULT: - // This case should never be choosen - DBUG_ASSERT(0); + array= new in_row(arg_count, item); break; } uint j=0; @@ -1106,33 +1346,18 @@ void Item_func_in::fix_length_and_dec() array->set(j,args[i]); if (!args[i]->null_value) // Skip NULL values j++; + else + have_null= 1; } if ((array->used_count=j)) array->sort(); } else { - switch (item->result_type()) { - case STRING_RESULT: - if (item->binary()) - in_item= new cmp_item_binary_string; - else - in_item= new cmp_item_sort_string; - break; - case INT_RESULT: - in_item= new cmp_item_int; - break; - case REAL_RESULT: - in_item= new cmp_item_real; - break; - case ROW_RESULT: - // This case should never be choosen - DBUG_ASSERT(0); - break; - } + in_item= cmp_item:: get_comparator(item); } maybe_null= item->maybe_null; - max_length=2; + max_length= 1; used_tables_cache|=item->used_tables(); const_item_cache&=item->const_item(); } @@ -1152,17 +1377,20 @@ longlong Item_func_in::val_int() if (array) { int tmp=array->find(item); - null_value=item->null_value; + null_value=item->null_value || (!tmp && have_null); return tmp; } in_item->store_value(item); if ((null_value=item->null_value)) return 0; + have_null= 0; for (uint i=0 ; i < arg_count ; i++) { if (!in_item->cmp(args[i]) && !args[i]->null_value) return 1; // Would maybe be nice with i ? + have_null|= args[i]->null_value; } + null_value= have_null; return 0; } @@ -1452,7 +1680,8 @@ longlong Item_func_isnotnull::val_int() void Item_func_like::fix_length_and_dec() { - decimals=0; max_length=1; + decimals= 0; + max_length= 1; // cmp_type=STRING_RESULT; // For quick select } @@ -1559,7 +1788,8 @@ Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) 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; + max_length= 1; + decimals= 0; if (args[0]->binary() || args[1]->binary()) set_charset(my_charset_bin); diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index b4f4872bd95..994e51ef89f 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -17,6 +17,8 @@ /* compare and test functions */ +#include "assert.h" + #ifdef __GNUC__ #pragma interface /* gcc class implementation */ #endif @@ -38,16 +40,12 @@ public: Arg_comparator() {}; Arg_comparator(Item **a1, Item **a2): a(a1), b(a2) {}; - inline void seta(Item **item) { a= item; } - inline void setb(Item **item) { b= item; } - int set_compare_func(Item_bool_func2 *owner, Item_result type); inline int set_compare_func(Item_bool_func2 *owner) { return set_compare_func(owner, item_cmp_type((*a)->result_type(), (*b)->result_type())); } - inline int set_cmp_func(Item_bool_func2 *owner, Item **a1, Item **a2, Item_result type) @@ -87,6 +85,27 @@ public: void fix_length_and_dec() { decimals=0; max_length=1; } }; +class Item_in_optimizer: public Item_bool_func +{ +protected: + char buffer[80]; + longlong int_cache; + double flt_cache; + String *str_cache; + bool int_cache_ok, flt_cache_ok, str_cache_ok; +public: + Item_in_optimizer(Item *a,Item *b): + Item_bool_func(a,b), int_cache_ok(0), flt_cache_ok(0), str_cache_ok(0) {} + bool is_null() { return test(args[0]->is_null() || args[1]->is_null()); } + longlong val_int(); + + double get_cache(); + longlong get_cache_int(); + String *get_cache_str(String *s); + + friend class Item_ref_in_optimizer; +}; + class Item_bool_func2 :public Item_int_func { /* Bool with 2 string args */ protected: @@ -358,6 +377,7 @@ class in_vector :public Sql_alloc uint count; public: uint used_count; + in_vector() {} in_vector(uint elements,uint element_length,qsort_cmp cmp_func) :base((char*) sql_calloc(elements*element_length)), size(element_length), compare(cmp_func), count(elements), @@ -372,7 +392,6 @@ public: int find(Item *item); }; - class in_string :public in_vector { char buff[80]; @@ -384,7 +403,6 @@ public: byte *get_value(Item *item); }; - class in_longlong :public in_vector { longlong tmp; @@ -394,7 +412,6 @@ public: byte *get_value(Item *item); }; - class in_double :public in_vector { double tmp; @@ -404,7 +421,6 @@ public: byte *get_value(Item *item); }; - /* ** Classes for easy comparing of non const items */ @@ -414,88 +430,201 @@ class cmp_item :public Sql_alloc public: cmp_item() {} virtual ~cmp_item() {} - virtual void store_value(Item *item)=0; - virtual int cmp(Item *item)=0; + virtual void store_value(Item *item)= 0; + virtual int cmp(Item *item)= 0; + // for optimized IN with row + virtual int compare(cmp_item *item)= 0; + static cmp_item* get_comparator(Item *); + virtual cmp_item *make_same()= 0; + virtual void store_value_by_template(cmp_item *tmpl, Item *item) + { + store_value(item); + } }; +typedef int (*str_cmp_func_pointer)(const String *, const String *); +class cmp_item_string :public cmp_item +{ +protected: + str_cmp_func_pointer str_cmp_func; + String *value_res; +public: + cmp_item_string (str_cmp_func_pointer cmp): str_cmp_func(cmp) {} + friend class cmp_item_sort_string; + friend class cmp_item_binary_string; + friend class cmp_item_sort_string_in_static; + friend class cmp_item_binary_string_in_static; +}; -class cmp_item_sort_string :public cmp_item { - protected: +class cmp_item_sort_string :public cmp_item_string +{ +protected: char value_buff[80]; - String value,*value_res; -public: - cmp_item_sort_string() :value(value_buff,sizeof(value_buff),default_charset_info) {} + String value; +public: + cmp_item_sort_string(str_cmp_func_pointer cmp): + cmp_item_string(cmp), + value(value_buff, sizeof(value_buff), default_charset_info) {} + cmp_item_sort_string(): + cmp_item_string(&sortcmp), + value(value_buff, sizeof(value_buff), default_charset_info) {} void store_value(Item *item) - { - value_res=item->val_str(&value); - } + { + value_res= item->val_str(&value); + } int cmp(Item *arg) - { - char buff[80]; - String tmp(buff,sizeof(buff),default_charset_info),*res; - if (!(res=arg->val_str(&tmp))) - return 1; /* Can't be right */ - return sortcmp(value_res,res); - } + { + char buff[80]; + String tmp(buff, sizeof(buff), default_charset_info), *res; + if (!(res= arg->val_str(&tmp))) + return 1; /* Can't be right */ + return (*str_cmp_func)(value_res, res); + } + int compare(cmp_item *c) + { + cmp_item_string *cmp= (cmp_item_string *)c; + return (*str_cmp_func)(value_res, cmp->value_res); + } + cmp_item *make_same(); }; class cmp_item_binary_string :public cmp_item_sort_string { public: - cmp_item_binary_string() {} - int cmp(Item *arg) - { - char buff[80]; - String tmp(buff,sizeof(buff),default_charset_info),*res; - if (!(res=arg->val_str(&tmp))) - return 1; /* Can't be right */ - return stringcmp(value_res,res); - } + cmp_item_binary_string(): cmp_item_sort_string(&stringcmp) {} + cmp_item *make_same(); }; - class cmp_item_int :public cmp_item { longlong value; public: void store_value(Item *item) - { - value=item->val_int(); - } + { + value= item->val_int(); + } int cmp(Item *arg) - { - return value != arg->val_int(); - } + { + return value != arg->val_int(); + } + int compare(cmp_item *c) + { + cmp_item_int *cmp= (cmp_item_int *)c; + return (value < cmp->value) ? -1 : ((value == cmp->value) ? 0 : 1); + } + cmp_item *make_same(); }; - class cmp_item_real :public cmp_item { double value; public: void store_value(Item *item) - { - value= item->val(); - } + { + value= item->val(); + } int cmp(Item *arg) - { - return value != arg->val(); - } + { + return value != arg->val(); + } + int compare(cmp_item *c) + { + cmp_item_real *cmp= (cmp_item_real *)c; + return (value < cmp->value)? -1 : ((value == cmp->value) ? 0 : 1); + } + cmp_item *make_same(); +}; + +class cmp_item_row :public cmp_item +{ + cmp_item **comparators; + uint n; +public: + cmp_item_row(): comparators(0), n(0) {} + ~cmp_item_row() + { + if(comparators) + for(uint i= 0; i < n; i++) + if (comparators[i]) + delete comparators[i]; + } + void store_value(Item *item); + int cmp(Item *arg); + int compare(cmp_item *arg); + cmp_item *make_same(); + void store_value_by_template(cmp_item *tmpl, Item *); +}; + + +class in_row :public in_vector +{ + cmp_item_row tmp; +public: + in_row(uint elements, Item *); + void set(uint pos,Item *item); + byte *get_value(Item *item); }; +/* + cmp_item for optimized IN with row (right part string, which never + be changed) +*/ + +class cmp_item_sort_string_in_static :public cmp_item_string +{ + protected: + String value; +public: + cmp_item_sort_string_in_static(str_cmp_func_pointer cmp): + cmp_item_string(cmp) {} + cmp_item_sort_string_in_static(): cmp_item_string(&sortcmp) {} + void store_value(Item *item) + { + value_res= item->val_str(&value); + } + int cmp(Item *item) + { + // Should never be called + DBUG_ASSERT(0); + return 1; + } + int compare(cmp_item *c) + { + cmp_item_string *cmp= (cmp_item_string *)c; + return (*str_cmp_func)(value_res, cmp->value_res); + } + cmp_item * make_same() + { + return new cmp_item_sort_string_in_static(); + } +}; + +class cmp_item_binary_string_in_static :public cmp_item_sort_string_in_static { +public: + cmp_item_binary_string_in_static(): + cmp_item_sort_string_in_static(&stringcmp) {} + cmp_item * make_same() + { + return new cmp_item_binary_string_in_static(); + } +}; class Item_func_in :public Item_int_func { Item *item; in_vector *array; cmp_item *in_item; + bool have_null; public: Item_func_in(Item *a,List<Item> &list) - :Item_int_func(list),item(a),array(0),in_item(0) {} + :Item_int_func(list), item(a), array(0), in_item(0), have_null(0) + { + allowed_arg_cols= item->cols(); + } longlong val_int(); bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref) { - bool res=(item->check_cols(1) || - item->fix_fields(thd, tlist, &item) || + // We do not check item->cols(), because allowed_arg_cols assigned from it + bool res=(item->fix_fields(thd, tlist, &item) || Item_func::fix_fields(thd, tlist, ref)); with_sum_func= with_sum_func || item->with_sum_func; return res; @@ -517,10 +646,9 @@ class Item_func_in :public Item_int_func DBUG_RETURN(1); DBUG_RETURN(item->check_loop(id)); } + bool nulls_in_row(); }; - - /* Functions used by where clause */ class Item_func_isnull :public Item_bool_func diff --git a/sql/item_row.cc b/sql/item_row.cc index 464a8fd0ec5..85a81a50256 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -18,8 +18,10 @@ #include "assert.h" Item_row::Item_row(List<Item> &arg): - Item(), array_holder(1) + Item(), array_holder(1), used_tables_cache(0), const_item_cache(1) { + + //TODO: think placing 2-3 component items in item (as it done for function) if ((arg_count= arg.elements)) items= (Item**) sql_alloc(sizeof(Item*)*arg_count); else @@ -45,16 +47,31 @@ void Item_row::illegal_method_call(const char *method) bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref) { - tables= 0; + null_value= 0; + maybe_null= 0; for (uint i= 0; i < arg_count; i++) { if (items[i]->fix_fields(thd, tabl, items+i)) return 1; - tables |= items[i]->used_tables(); + used_tables_cache |= items[i]->used_tables(); + const_item_cache&= items[i]->const_item(); + maybe_null|= items[i]->maybe_null; } return 0; } +void Item_row::update_used_tables() +{ + used_tables_cache= 0; + const_item_cache= 1; + for (uint i= 0; i < arg_count; i++) + { + items[i]->update_used_tables(); + used_tables_cache|= items[i]->used_tables(); + const_item_cache&= items[i]->const_item(); + } +} + bool Item_row::check_cols(uint c) { if (c != arg_count) @@ -64,3 +81,22 @@ bool Item_row::check_cols(uint c) } return 0; } + +bool Item_row::null_inside() +{ + for (uint i= 0; i < arg_count; i++) + { + if (items[i]->cols() > 1) + { + if (items[i]->null_inside()) + return 1; + } + else + { + items[i]->val_int(); + if (items[i]->null_value) + return 1; + } + } + return 0; +} diff --git a/sql/item_row.h b/sql/item_row.h index 5580250b4fb..4767d19d08f 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -17,13 +17,17 @@ class Item_row: public Item { bool array_holder; - table_map tables; + table_map used_tables_cache; + bool const_item_cache; uint arg_count; Item **items; public: Item_row(List<Item> &); Item_row(Item_row *item): - Item(), array_holder(0), tables(item->tables), arg_count(item->arg_count), + Item(), array_holder(0), + used_tables_cache(item->used_tables_cache), + const_item_cache(item->const_item_cache), + arg_count(item->arg_count), items(item->items) {} @@ -56,11 +60,14 @@ public: return 0; }; bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref); - table_map used_tables() const { return tables; }; + table_map used_tables() const { return used_tables_cache; }; + bool const_item() const { return const_item_cache; }; enum Item_result result_type() const { return ROW_RESULT; } + void update_used_tables(); - virtual uint cols() { return arg_count; } - virtual Item* el(uint i) { return items[i]; } - virtual Item** addr(uint i) { return items + i; } - virtual bool check_cols(uint c); + uint cols() { return arg_count; } + Item* el(uint i) { return items[i]; } + Item** addr(uint i) { return items + i; } + bool check_cols(uint c); + bool null_inside(); }; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index e087664e060..7dd57ef228e 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -33,9 +33,10 @@ SUBSELECT TODO: #include "sql_select.h" Item_subselect::Item_subselect(): - Item_result_field(), engine_owner(1), value_assigned(0), substitution(0) + Item_result_field(), engine_owner(1), value_assigned(0), substitution(0), + have_to_be_excluded(0) { - assign_null(); + reset(); /* item value is NULL if select_subselect not changed this value (i.e. some rows will be found returned) @@ -93,8 +94,10 @@ bool Item_subselect::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { (*ref)= substitution; substitution->name= name; - engine->exclude(); - return substitution->fix_fields(thd, tables, ref); + if (have_to_be_excluded) + engine->exclude(); + substitution= 0; + return (*ref)->fix_fields(thd, tables, ref); } char const *save_where= thd->where; @@ -159,7 +162,7 @@ double Item_singleval_subselect::val () { if (engine->exec()) { - assign_null(); + reset(); return 0; } return real_value; @@ -169,7 +172,7 @@ longlong Item_singleval_subselect::val_int () { if (engine->exec()) { - assign_null(); + reset(); return 0; } return int_value; @@ -179,7 +182,7 @@ String *Item_singleval_subselect::val_str (String *str) { if (engine->exec() || null_value) { - assign_null(); + reset(); return 0; } return &string_value; @@ -208,9 +211,8 @@ Item_in_subselect::Item_in_subselect(THD *thd, Item * left_exp, left_expr= left_exp; init(thd, select_lex, new select_exists_subselect(this)); max_columns= UINT_MAX; - null_value= 0; //can't be NULL - maybe_null= 0; //can't be NULL - value= 0; + maybe_null= 1; + reset(); // We need only 1 row to determinate existence select_lex->master_unit()->global_parameters->select_limit= 1; DBUG_VOID_RETURN; @@ -226,9 +228,7 @@ Item_allany_subselect::Item_allany_subselect(THD *thd, Item * left_exp, func= f; init(thd, select_lex, new select_exists_subselect(this)); max_columns= UINT_MAX; - null_value= 0; //can't be NULL - maybe_null= 0; //can't be NULL - value= 0; + reset(); // We need only 1 row to determinate existence select_lex->master_unit()->global_parameters->select_limit= 1; DBUG_VOID_RETURN; @@ -237,14 +237,15 @@ Item_allany_subselect::Item_allany_subselect(THD *thd, Item * left_exp, void Item_exists_subselect::fix_length_and_dec() { - max_length= 1; + decimals=0; + max_length= 1; } double Item_exists_subselect::val () { if (engine->exec()) { - assign_null(); + reset(); return 0; } return (double) value; @@ -254,7 +255,7 @@ longlong Item_exists_subselect::val_int () { if (engine->exec()) { - assign_null(); + reset(); return 0; } return value; @@ -264,7 +265,50 @@ String *Item_exists_subselect::val_str(String *str) { if (engine->exec()) { - assign_null(); + reset(); + return 0; + } + str->set(value,thd_charset()); + return str; +} + +double Item_in_subselect::val () +{ + if (engine->exec()) + { + reset(); + null_value= 1; + return 0; + } + if (was_null && !value) + null_value= 1; + return (double) value; +} + +longlong Item_in_subselect::val_int () +{ + if (engine->exec()) + { + reset(); + null_value= 1; + return 0; + } + if (was_null && !value) + null_value= 1; + return value; +} + +String *Item_in_subselect::val_str(String *str) +{ + if (engine->exec()) + { + reset(); + null_value= 1; + return 0; + } + if (was_null && !value) + { + null_value= 1; return 0; } str->set(value,thd_charset()); @@ -288,8 +332,23 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex, compare_func_creator func) { DBUG_ENTER("Item_in_subselect::single_value_transformer"); + Item_in_optimizer *optimizer; + substitution= optimizer= new Item_in_optimizer(left_expr, this); + if (!optimizer) + { + current_thd->fatal_error= 1; + DBUG_VOID_RETURN; + } + /* + As far as Item_ref_in_optimizer do not substitude itself on fix_fields + we can use same item for all selects. + */ + Item *expr= new Item_ref_in_optimizer(optimizer, (char *)"<no matter>", + (char*)"<left expr>"); + select_lex->master_unit()->dependent= 1; for (SELECT_LEX * sl= select_lex; sl; sl= sl->next_select()) { + select_lex->dependent= 1; Item *item; if (sl->item_list.elements > 1) { @@ -299,14 +358,14 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex, else item= (Item*) sl->item_list.pop(); - 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) { sl->item_list.push_back(item); - item= (*func)(expr, new Item_ref(sl->item_list.head_ref(), - 0, (char*)"<result>")); + item= (*func)(expr, new Item_ref_null_helper(this, + sl->item_list.head_ref(), + (char *)"<no matter>", + (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); @@ -324,7 +383,9 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex, sl->item_list.push_back(new Item_int(1)); if (sl->table_list.elements) { - item= (*func)(expr, new Item_asterisk_remover(item)); + item= (*func)(expr, new Item_asterisk_remover(this, item, + (char *)"<no matter>", + (char*)"<result>")); if (sl->where) sl->where= new Item_cond_and(sl->where, item); else @@ -340,14 +401,21 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex, } if (select_lex->next_select()) { - // it is in union => we should perform it - sl->having= (*func)(expr, item); + /* + It is in union => we should perform it. + Item_asterisk_remover used only as wrapper to receine NULL value + */ + sl->having= (*func)(expr, + new Item_asterisk_remover(this, item, + (char *)"<no matter>", + (char*)"<result>")); } else { // it is single select without tables => possible optimization item= (*func)(left_expr, item); substitution= item; + have_to_be_excluded= 1; THD *thd= current_thd; if (thd->lex.describe) { @@ -489,7 +557,7 @@ int subselect_single_select_engine::exec() join->thd->where= save_where; DBUG_RETURN(1); } - item->assign_null(); + item->reset(); item->assigned((executed= 0)); } if (!executed) diff --git a/sql/item_subselect.h b/sql/item_subselect.h index d323dab51f1..adae0831c22 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -42,6 +42,8 @@ protected: subselect_engine *engine; /* allowed number of columns (1 for single value subqueries) */ uint max_columns; + /* work with 'substitution' */ + bool have_to_be_excluded; public: Item_subselect(); @@ -65,7 +67,7 @@ public: select_subselect *result); ~Item_subselect(); - virtual void assign_null() + virtual void reset() { null_value= 1; } @@ -110,7 +112,7 @@ public: decimals= item->decimals; res_type= item->res_type; } - virtual void assign_null() + virtual void reset() { null_value= 1; int_value= 0; @@ -144,7 +146,7 @@ public: } Item_exists_subselect(): Item_subselect() {} - virtual void assign_null() + virtual void reset() { value= 0; } @@ -155,6 +157,7 @@ public: double val(); String *val_str(String*); void fix_length_and_dec(); + friend class select_exists_subselect; }; @@ -164,14 +167,26 @@ class Item_in_subselect :public Item_exists_subselect { protected: Item * left_expr; - + bool was_null; public: Item_in_subselect(THD *thd, Item * left_expr, st_select_lex *select_lex); Item_in_subselect(Item_in_subselect *item); Item_in_subselect(): Item_exists_subselect() {} + void reset() + { + value= 0; + null_value= 0; + was_null= 0; + } virtual void select_transformer(st_select_lex *select_lex); void single_value_transformer(st_select_lex *select_lex, Item *left_expr, compare_func_creator func); + longlong val_int(); + double val(); + String *val_str(String*); + + friend class Item_asterisk_remover; + friend class Item_ref_null_helper; }; /* ALL/ANY/SOME subselect */ diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 4a2d716c953..7bed3541777 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -253,12 +253,24 @@ double Item_sum_avg::val() ** Standard deviation */ -void Item_sum_std::reset() +double Item_sum_std::val() { - sum=sum_sqr=0.0; count=0; (void) Item_sum_std::add(); + double tmp= Item_sum_variance::val(); + return tmp <= 0.0 ? 0.0 : sqrt(tmp); } -bool Item_sum_std::add() +/* +** variance +*/ + +void Item_sum_variance::reset() +{ + sum=sum_sqr=0.0; + count=0; + (void) Item_sum_variance::add(); +} + +bool Item_sum_variance::add() { double nr=args[0]->val(); if (!args[0]->null_value) @@ -270,7 +282,7 @@ bool Item_sum_std::add() return 0; } -double Item_sum_std::val() +double Item_sum_variance::val() { if (!count) { @@ -281,11 +293,10 @@ double Item_sum_std::val() /* Avoid problems when the precision isn't good enough */ double tmp=ulonglong2double(count); double tmp2=(sum_sqr - sum*sum/tmp)/tmp; - return tmp2 <= 0.0 ? 0.0 : sqrt(tmp2); + return tmp2 <= 0.0 ? 0.0 : tmp2; } - -void Item_sum_std::reset_field() +void Item_sum_variance::reset_field() { double nr=args[0]->val(); char *res=result_field->ptr; @@ -302,7 +313,7 @@ void Item_sum_std::reset_field() } } -void Item_sum_std::update_field(int offset) +void Item_sum_variance::update_field(int offset) { double nr,old_nr,old_sqr; longlong field_count; @@ -836,6 +847,17 @@ String *Item_avg_field::val_str(String *str) } Item_std_field::Item_std_field(Item_sum_std *item) + : Item_variance_field(item) +{ +} + +double Item_std_field::val() +{ + double tmp= Item_variance_field::val(); + return tmp <= 0.0 ? 0.0 : sqrt(tmp); +} + +Item_variance_field::Item_variance_field(Item_sum_variance *item) { name=item->name; decimals=item->decimals; @@ -844,7 +866,7 @@ Item_std_field::Item_std_field(Item_sum_std *item) maybe_null=1; } -double Item_std_field::val() +double Item_variance_field::val() { double sum,sum_sqr; longlong count; @@ -860,10 +882,10 @@ double Item_std_field::val() null_value=0; double tmp= (double) count; double tmp2=(sum_sqr - sum*sum/tmp)/tmp; - return tmp2 <= 0.0 ? 0.0 : sqrt(tmp2); + return tmp2 <= 0.0 ? 0.0 : tmp2; } -String *Item_std_field::val_str(String *str) +String *Item_variance_field::val_str(String *str) { double nr=val(); if (null_value) diff --git a/sql/item_sum.h b/sql/item_sum.h index 23b8482d41a..b5665c3cf8c 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -27,7 +27,7 @@ class Item_sum :public Item_result_field { public: enum Sumfunctype {COUNT_FUNC,COUNT_DISTINCT_FUNC,SUM_FUNC,AVG_FUNC,MIN_FUNC, - MAX_FUNC, UNIQUE_USERS_FUNC,STD_FUNC,SUM_BIT_FUNC, + MAX_FUNC, UNIQUE_USERS_FUNC,STD_FUNC,VARIANCE_FUNC,SUM_BIT_FUNC, UDF_SUM_FUNC }; Item **args,*tmp_args[2]; @@ -235,14 +235,14 @@ class Item_sum_avg :public Item_sum_num const char *func_name() const { return "avg"; } }; -class Item_sum_std; +class Item_sum_variance; -class Item_std_field :public Item_result_field +class Item_variance_field :public Item_result_field { public: Field *field; - Item_std_field(Item_sum_std *item); - enum Type type() const { return FIELD_STD_ITEM; } + Item_variance_field(Item_sum_variance *item); + enum Type type() const {return FIELD_VARIANCE_ITEM; } double val(); longlong val_int() { return (longlong) val(); } String *val_str(String*); @@ -251,26 +251,63 @@ public: void fix_length_and_dec() {} }; -class Item_sum_std :public Item_sum_num +/* + +variance(a) = + += sum (ai - avg(a))^2 / count(a) ) += sum (ai^2 - 2*ai*avg(a) + avg(a)^2) / count(a) += (sum(ai^2) - sum(2*ai*avg(a)) + sum(avg(a)^2))/count(a) = += (sum(ai^2) - 2*avg(a)*sum(a) + count(a)*avg(a)^2)/count(a) = += (sum(ai^2) - 2*sum(a)*sum(a)/count(a) + count(a)*sum(a)^2/count(a)^2 )/count(a) = += (sum(ai^2) - 2*sum(a)^2/count(a) + sum(a)^2/count(a) )/count(a) = += (sum(ai^2) - sum(a)^2/count(a))/count(a) + +*/ + +class Item_sum_variance : public Item_sum_num { - double sum; - double sum_sqr; + double sum, sum_sqr; ulonglong count; void fix_length_and_dec() { decimals+=4; maybe_null=1; } public: - Item_sum_std(Item *item_par) :Item_sum_num(item_par),count(0) {} - enum Sumfunctype sum_func () const { return STD_FUNC; } + Item_sum_variance(Item *item_par) :Item_sum_num(item_par),count(0) {} + enum Sumfunctype sum_func () const { return VARIANCE_FUNC; } void reset(); bool add(); double val(); void reset_field(); void update_field(int offset); Item *result_item(Field *field) - { return new Item_std_field(this); } - const char *func_name() const { return "std"; } + { return new Item_variance_field(this); } + const char *func_name() const { return "variance"; } }; +class Item_sum_std; + +class Item_std_field :public Item_variance_field +{ +public: + Item_std_field(Item_sum_std *item); + enum Type type() const { return FIELD_STD_ITEM; } + double val(); +}; + +/* + standard_deviation(a) = sqrt(variance(a)) +*/ + +class Item_sum_std :public Item_sum_variance +{ + public: + Item_sum_std(Item *item_par) :Item_sum_variance(item_par){} + enum Sumfunctype sum_func () const { return STD_FUNC; } + double val(); + Item *result_item(Field *field) + { return new Item_std_field(this); } + const char *func_name() const { return "std"; } +}; // This class is a string or number function depending on num_func diff --git a/sql/lex.h b/sql/lex.h index eb03c0b36ec..421ac933f50 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -344,6 +344,7 @@ static SYMBOL symbols[] = { { "SQL_NO_CACHE", SYM(SQL_NO_CACHE_SYM), 0, 0}, { "SQL_SMALL_RESULT", SYM(SQL_SMALL_RESULT),0,0}, { "SQL_THREAD", SYM(SQL_THREAD),0,0}, + { "SOUNDS", SYM(SOUNDS_SYM),0,0}, { "SSL", SYM(SSL_SYM),0,0}, { "STRAIGHT_JOIN", SYM(STRAIGHT_JOIN),0,0}, { "START", SYM(START_SYM),0,0}, @@ -584,6 +585,7 @@ static SYMBOL sql_functions[] = { { "UNIX_TIMESTAMP", SYM(UNIX_TIMESTAMP),0,0}, { "UPPER", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ucase)}, { "USER", SYM(USER),0,0}, + { "VARIANCE", SYM(VARIANCE_SYM),0,0}, { "VERSION", SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_version)}, { "WEEK", SYM(WEEK_SYM),0,0}, { "WEEKDAY", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_weekday)}, diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 811713bec15..9de04ac3454 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -184,7 +184,6 @@ static uint handler_count; static bool opt_enable_named_pipe = 0; #endif #ifdef __WIN__ -static bool opt_console=0,start_mode=0; static pthread_cond_t COND_handler_count; static uint handler_count; static bool opt_console=0, start_mode=0, use_opt_args; @@ -2160,7 +2159,7 @@ The server will not act as a slave."); (void) thr_setconcurrency(concurrency); // 10 by default #if defined(__WIN__) && !defined(EMBEDDED_LIBRARY) //IRENA { - hEventShutdown=CreateEvent(0, FALSE, FALSE, event_name); + hEventShutdown=CreateEvent(0, FALSE, FALSE, shutdown_event_name); pthread_t hThread; if (pthread_create(&hThread,&connection_attrib,handle_shutdown,0)) sql_print_error("Warning: Can't create thread to handle shutdown requests"); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index ebd1d9d2b3c..ba6369b0022 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -933,9 +933,9 @@ bool select_singleval_subselect::send_data(List<Item> &items) calculate value on it & determinate "is it NULL?". */ it->real_value= val_item->val_result(); - if ((it->null_value= val_item->is_null_result())) + if ((it->null_value= val_item->null_value)) { - it->assign_null(); + it->reset(); } else { diff --git a/sql/sql_list.h b/sql/sql_list.h index 56e6528f214..1711a340cae 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -25,8 +25,16 @@ class Sql_alloc { public: - static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); } + static void *operator new(size_t size) + { + return (void*) sql_alloc((uint) size); + } + static void *operator new[](size_t size) + { + return (void*) sql_alloc((uint) size); + } static void operator delete(void *ptr, size_t size) {} /*lint -e715 */ + static void operator delete[](void *ptr, size_t size) {} #ifdef HAVE_purify bool dummy; inline Sql_alloc() :dummy(0) {} diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 2fba71cab47..fe0cd02d056 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -793,6 +793,16 @@ JOIN::exec() HA_POS_ERROR))) DBUG_VOID_RETURN; + /* + We don't have to store rows in temp table that doesn't match HAVING if: + - we are sorting the table and writing complete group rows to the + temp table. + - We are using DISTINCT without resolving the distinct as a GROUP BY + on all columns. + + If having is not handled here, it will be checked before the row + is sent to the client. + */ if (having_list && (sort_and_group || (exec_tmp_table->distinct && !group_list))) having=having_list; @@ -3775,13 +3785,14 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, else return new Field_double(item_sum->max_length,maybe_null, item->name, table, item_sum->decimals); - case Item_sum::STD_FUNC: /* Place for sum & count */ + case Item_sum::VARIANCE_FUNC: /* Place for sum & count */ + case Item_sum::STD_FUNC: if (group) return new Field_string(sizeof(double)*2+sizeof(longlong), maybe_null, item->name,table,my_charset_bin); else return new Field_double(item_sum->max_length, maybe_null, - item->name,table,item_sum->decimals); + item->name,table,item_sum->decimals); case Item_sum::UNIQUE_USERS_FUNC: return new Field_long(9,maybe_null,item->name,table,1); default: diff --git a/sql/sql_union.cc b/sql/sql_union.cc index d3143725878..10175bfe345 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -216,7 +216,7 @@ int st_select_lex_unit::exec() if (optimized && item && item->assigned()) { item->assigned(0); // We will reinit & rexecute unit - item->assign_null(); + item->reset(); table->file->delete_all_rows(); } for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c1057033bd4..8e947ec7587 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -100,6 +100,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token DIV_SYM %token EQ %token EQUAL_SYM +%token SOUNDS_SYM %token GE %token GT_SYM %token LE @@ -158,6 +159,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token SQL_THREAD %token START_SYM %token STD_SYM +%token VARIANCE_SYM %token STOP_SYM %token SUM_SYM %token SUPER_SYM @@ -1833,6 +1835,7 @@ expr_expr: | expr OR expr { $$= new Item_cond_or($1,$3); } | expr XOR expr { $$= new Item_cond_xor($1,$3); } | expr AND expr { $$= new Item_cond_and($1,$3); } + | expr SOUNDS_SYM LIKE expr { $$= Item_bool_func2::eq_creator(new Item_func_soundex($1), new Item_func_soundex($4));} | expr LIKE simple_expr opt_escape { $$= new Item_func_like($1,$3,$4); } | expr NOT LIKE simple_expr opt_escape { $$= new Item_func_not(new Item_func_like($1,$4,$5));} | expr REGEXP expr { $$= new Item_func_regex($1,$3); } @@ -1879,6 +1882,7 @@ no_in_expr: | no_in_expr OR expr { $$= new Item_cond_or($1,$3); } | no_in_expr XOR expr { $$= new Item_cond_xor($1,$3); } | no_in_expr AND expr { $$= new Item_cond_and($1,$3); } + | no_in_expr SOUNDS_SYM LIKE expr { $$= Item_bool_func2::eq_creator(new Item_func_soundex($1), new Item_func_soundex($4));} | no_in_expr LIKE simple_expr opt_escape { $$= new Item_func_like($1,$3,$4); } | no_in_expr NOT LIKE simple_expr opt_escape { $$= new Item_func_not(new Item_func_like($1,$4,$5)); } | no_in_expr REGEXP expr { $$= new Item_func_regex($1,$3); } @@ -1933,6 +1937,7 @@ no_and_expr: | no_and_expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); } | no_and_expr OR expr { $$= new Item_cond_or($1,$3); } | no_and_expr XOR expr { $$= new Item_cond_xor($1,$3); } + | no_and_expr SOUNDS_SYM LIKE expr { $$= Item_bool_func2::eq_creator(new Item_func_soundex($1), new Item_func_soundex($4));} | no_and_expr LIKE simple_expr opt_escape { $$= new Item_func_like($1,$3,$4); } | no_and_expr NOT LIKE simple_expr opt_escape { $$= new Item_func_not(new Item_func_like($1,$4,$5)); } | no_and_expr REGEXP expr { $$= new Item_func_regex($1,$3); } @@ -2335,6 +2340,8 @@ sum_expr: { $$=new Item_sum_max($3); } | STD_SYM '(' in_sum_expr ')' { $$=new Item_sum_std($3); } + | VARIANCE_SYM '(' in_sum_expr ')' + { $$=new Item_sum_variance($3); } | SUM_SYM '(' in_sum_expr ')' { $$=new Item_sum_sum($3); }; @@ -3870,6 +3877,7 @@ keyword: | VALUE_SYM {} | WORK_SYM {} | YEAR_SYM {} + | SOUNDS_SYM {} ; /* Option functions */ |