diff options
-rw-r--r-- | mysql-test/r/row.result | 8 | ||||
-rw-r--r-- | mysql-test/t/row.test | 2 | ||||
-rw-r--r-- | sql/item.cc | 6 | ||||
-rw-r--r-- | sql/item.h | 23 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 82 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 43 | ||||
-rw-r--r-- | sql/item_row.cc | 19 | ||||
-rw-r--r-- | sql/item_row.h | 9 | ||||
-rw-r--r-- | sql/sql_class.cc | 2 |
9 files changed, 123 insertions, 71 deletions
diff --git a/mysql-test/r/row.result b/mysql-test/r/row.result index e0b524d9bb2..1d606fc370c 100644 --- a/mysql-test/r/row.result +++ b/mysql-test/r/row.result @@ -9,7 +9,7 @@ row(1,2,3) IN (row(3,NULL,3), row(1,2,3), row(1,3,3)) 1 select row(10,2,3) IN (row(3,NULL,3), row(1,2,3), row(1,3,3)); row(10,2,3) IN (row(3,NULL,3), row(1,2,3), row(1,3,3)) -NULL +0 select row('a',1.5,3) IN (row(1,2,3), row('a',1.5,3), row('a','a','a')); row('a',1.5,3) IN (row(1,2,3), row('a',1.5,3), row('a','a','a')) 1 @@ -24,7 +24,13 @@ row('a',1.5,3) IN (row(3,NULL,3), row('a',1.5,3), row(1,3,3)) 1 select row('b',1.5,3) IN (row(3,NULL,3), row('a',1.5,3), row(1,3,3)); row('b',1.5,3) IN (row(3,NULL,3), row('a',1.5,3), row(1,3,3)) +0 +select row('b',1.5,3) IN (row('b',NULL,3), row('a',1.5,3), row(1,3,3)); +row('b',1.5,3) IN (row('b',NULL,3), row('a',1.5,3), row(1,3,3)) NULL +select row('b',1.5,3) IN (row('b',NULL,4), row('a',1.5,3), row(1,3,3)); +row('b',1.5,3) IN (row('b',NULL,4), row('a',1.5,3), row(1,3,3)) +0 select row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,row(3,4))); row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,row(3,4))) 1 diff --git a/mysql-test/t/row.test b/mysql-test/t/row.test index 04f31fcbfe1..593e2342856 100644 --- a/mysql-test/t/row.test +++ b/mysql-test/t/row.test @@ -7,6 +7,8 @@ select row('a',0,3) IN (row(3,2,3), row('a','0','3'), row(1,3,3)); select row('a',0,3) IN (row(3,2,3), row('a','a','3'), row(1,3,3)); select row('a',1.5,3) IN (row(3,NULL,3), row('a',1.5,3), row(1,3,3)); select row('b',1.5,3) IN (row(3,NULL,3), row('a',1.5,3), row(1,3,3)); +select row('b',1.5,3) IN (row('b',NULL,3), row('a',1.5,3), row(1,3,3)); +select row('b',1.5,3) IN (row('b',NULL,4), row('a',1.5,3), row(1,3,3)); select row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,row(3,4))); -- error 1239 select row(1,2,row(3,4)) IN (row(3,2,row(3,4)), row(1,2,4)); diff --git a/sql/item.cc b/sql/item.cc index d65f9305471..55bfbdd4534 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -537,19 +537,19 @@ bool Item_asterisk_remover::fix_fields(THD *thd, double Item_ref_null_helper::val() { double tmp= (*ref)->val_result(); - owner->was_null|= null_value= (*ref)->is_null_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)->is_null_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)->is_null_result(); + owner->was_null|= null_value= (*ref)->null_value; return tmp; } bool Item_ref_null_helper::get_date(TIME *ltime, bool fuzzydate) diff --git a/sql/item.h b/sql/item.h index 92d355b1fe0..8b43677b5d4 100644 --- a/sql/item.h +++ b/sql/item.h @@ -72,7 +72,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 +99,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; }; }; @@ -124,13 +125,20 @@ public: 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() { return item->is_null_result(); } + 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) { return item->save_in_field(field); } + 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(); } @@ -187,7 +195,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); @@ -473,25 +480,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) { diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 38c137ef8e3..1d61f8f5819 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, @@ -276,13 +276,13 @@ longlong Item_in_optimizer::val_int() flt_cache_ok= 0; str_cache_ok= 0; int_cache= args[0]->val_int_result(); - if (args[0]->is_null_result()) + if (args[0]->null_value) { null_value= 1; return 0; } longlong tmp= args[1]->val_int_result(); - null_value= args[1]->is_null_result(); + null_value= args[1]->null_value; return tmp; } @@ -294,7 +294,7 @@ longlong Item_in_optimizer::get_cache_int() flt_cache_ok= 0; str_cache_ok= 0; int_cache= args[0]->val_int_result(); - null_value= args[0]->is_null_result(); + null_value= args[0]->null_value; } return int_cache; } @@ -303,11 +303,11 @@ double Item_in_optimizer::get_cache() { if (!flt_cache_ok) { - int_cache_ok= 0; flt_cache_ok= 1; + int_cache_ok= 0; str_cache_ok= 0; flt_cache= args[0]->val_result(); - null_value= args[0]->is_null_result(); + null_value= args[0]->null_value; } return flt_cache; } @@ -316,12 +316,12 @@ 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_cache_ok= 1; - str_cache_buff.set(buffer, sizeof(buffer), s->charset()); - str_cache= args[0]->str_result(&str_cache_buff); - null_value= args[0]->is_null_result(); + 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; } @@ -418,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(); } @@ -477,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, @@ -1030,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++) { @@ -1214,8 +1215,9 @@ cmp_item* cmp_item_row::make_same() void cmp_item_row::store_value(Item *item) { + THD *thd= current_thd; n= item->cols(); - if ((comparators= (cmp_item **) sql_alloc(sizeof(cmp_item *)*n))) + if ((comparators= (cmp_item **) thd->alloc(sizeof(cmp_item *)*n))) { item->null_value= 0; for (uint i=0; i < n; i++) @@ -1227,14 +1229,14 @@ void cmp_item_row::store_value(Item *item) else { my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); - current_thd->fatal_error= 1; + thd->fatal_error= 1; return; } } else { my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); - current_thd->fatal_error= 1; + thd->fatal_error= 1; return; } } @@ -1281,33 +1283,53 @@ int cmp_item_row::cmp(Item *arg) my_error(ER_CARDINALITY_COL, MYF(0), n); return 1; } - for(uint i=0; i < n; i++) - if(comparators[i]->cmp(arg->el(i))) + bool was_null= 0; + for (uint i=0; i < n; i++) + if (comparators[i]->cmp(arg->el(i))) { - arg->null_value|= arg->el(i)->null_value; - return 1; + if (!arg->el(i)->null_value) + return 1; + was_null= 1; } - return 0; + if (!was_null) + return 0; + arg->null_value= 1; + return 1; } 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]))) + 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; @@ -1338,7 +1360,7 @@ void Item_func_in::fix_length_and_dec() 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(); } @@ -1661,7 +1683,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 } @@ -1768,7 +1791,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 c297019f977..994e51ef89f 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -91,7 +91,7 @@ protected: char buffer[80]; longlong int_cache; double flt_cache; - String str_cache_buff, *str_cache; + String *str_cache; bool int_cache_ok, flt_cache_ok, str_cache_ok; public: Item_in_optimizer(Item *a,Item *b): @@ -442,11 +442,14 @@ public: } }; +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; @@ -459,7 +462,11 @@ protected: char value_buff[80]; 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) { @@ -471,32 +478,19 @@ public: 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); + return (*str_cmp_func)(value_res, res); } int compare(cmp_item *c) { cmp_item_string *cmp= (cmp_item_string *)c; - return sortcmp(value_res, cmp->value_res); + 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); - } - int compare(cmp_item *c) - { - cmp_item_string *cmp= (cmp_item_string *)c; - return stringcmp(value_res, cmp->value_res); - } + cmp_item_binary_string(): cmp_item_sort_string(&stringcmp) {} cmp_item *make_same(); }; @@ -580,7 +574,9 @@ class cmp_item_sort_string_in_static :public cmp_item_string protected: String value; public: - cmp_item_sort_string_in_static() {} + 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); @@ -594,7 +590,7 @@ public: int compare(cmp_item *c) { cmp_item_string *cmp= (cmp_item_string *)c; - return sortcmp(value_res, cmp->value_res); + return (*str_cmp_func)(value_res, cmp->value_res); } cmp_item * make_same() { @@ -604,12 +600,8 @@ public: class cmp_item_binary_string_in_static :public cmp_item_sort_string_in_static { public: - cmp_item_binary_string_in_static() {} - int compare(cmp_item *c) - { - cmp_item_string *cmp= (cmp_item_string *)c; - return stringcmp(value_res, cmp->value_res); - } + 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(); @@ -654,6 +646,7 @@ 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 */ diff --git a/sql/item_row.cc b/sql/item_row.cc index e073f8e24e7..85a81a50256 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -81,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 d097fca8f1d..4767d19d08f 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -65,8 +65,9 @@ public: 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/sql_class.cc b/sql/sql_class.cc index b8fa40e11f9..ba6369b0022 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -933,7 +933,7 @@ 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->reset(); } |