Commit 24300918 authored by unknown's avatar unknown

_NEW_ IN/ALL/ANY/SOME behaviour with NULL (SCRUM related)

optimization of left expression evaluation
more descriptive method name


mysql-test/r/func_in.result:
  test of _NEW_ IN behaviour with NULL
mysql-test/r/subselect.result:
  test of _NEW_ IN/ALL/ANY/SOME behaviour with NULL
mysql-test/t/func_in.test:
  test of _NEW_ IN behaviour with NULL
mysql-test/t/subselect.test:
  test of _NEW_ IN/ALL/ANY/SOME behaviour with NULL
sql/item.cc:
  _NEW_ IN/ALL/ANY/SOME behaviour with NULL
  optimization of left expression evaluation
sql/item.h:
  _NEW_ IN/ALL/ANY/SOME behaviour with NULL
  optimization of left expression evaluation
sql/item_cmpfunc.cc:
  _NEW_ IN/ALL/ANY/SOME behaviour with NULL
  optimization of left expression evaluation
sql/item_cmpfunc.h:
  _NEW_ IN/ALL/ANY/SOME behaviour with NULL
  optimization of left expression evaluation
sql/item_subselect.cc:
  _NEW_ IN/ALL/ANY/SOME behaviour with NULL
  optimization of left expression evaluation
sql/item_subselect.h:
  _NEW_ IN/ALL/ANY/SOME behaviour with NULL
  optimization of left expression evaluation
sql/sql_class.cc:
  more descriptive method name
sql/sql_union.cc:
  more descriptive method name
parent 60aeed17
select 1 in (1,2,3);
1 in (1,2,3)
1
select 10 in (1,2,3);
10 in (1,2,3)
0
select NULL in (1,2,3);
NULL in (1,2,3)
NULL
select 1 in (1,NULL,3);
1 in (1,NULL,3)
1
select 3 in (1,NULL,3);
3 in (1,NULL,3)
1
select 10 in (1,NULL,3);
10 in (1,NULL,3)
NULL
select 1.5 in (1.5,2.5,3.5);
1.5 in (1.5,2.5,3.5)
1
select 10.5 in (1.5,2.5,3.5);
10.5 in (1.5,2.5,3.5)
0
select NULL in (1.5,2.5,3.5);
NULL in (1.5,2.5,3.5)
NULL
select 1.5 in (1.5,NULL,3.5);
1.5 in (1.5,NULL,3.5)
1
select 3.5 in (1.5,NULL,3.5);
3.5 in (1.5,NULL,3.5)
1
select 10.5 in (1.5,NULL,3.5);
10.5 in (1.5,NULL,3.5)
NULL
drop table if exists t1; drop table if exists t1;
CREATE TABLE t1 (a int, b int, c int);
insert into t1 values (1,2,3), (1,NULL,3);
select 1 in (a,b,c) from t1;
1 in (a,b,c)
1
1
select 3 in (a,b,c) from t1;
3 in (a,b,c)
1
1
select 10 in (a,b,c) from t1;
10 in (a,b,c)
0
NULL
select NULL in (a,b,c) from t1;
NULL in (a,b,c)
NULL
NULL
drop table t1;
CREATE TABLE t1 (a float, b float, c float);
insert into t1 values (1.5,2.5,3.5), (1.5,NULL,3.5);
select 1.5 in (a,b,c) from t1;
1.5 in (a,b,c)
1
1
select 3.5 in (a,b,c) from t1;
3.5 in (a,b,c)
1
1
select 10.5 in (a,b,c) from t1;
10.5 in (a,b,c)
0
NULL
drop table t1;
CREATE TABLE t1 (a varchar(10), b varchar(10), c varchar(10));
insert into t1 values ('A','BC','EFD'), ('A',NULL,'EFD');
select 'A' in (a,b,c) from t1;
'A' in (a,b,c)
1
1
select 'EFD' in (a,b,c) from t1;
'EFD' in (a,b,c)
1
1
select 'XSFGGHF' in (a,b,c) from t1;
'XSFGGHF' in (a,b,c)
0
NULL
drop table t1;
CREATE TABLE t1 (field char(1)); CREATE TABLE t1 (field char(1));
INSERT INTO t1 VALUES ('A'),(NULL); INSERT INTO t1 VALUES ('A'),(NULL);
SELECT * from t1 WHERE field IN (NULL); SELECT * from t1 WHERE field IN (NULL);
field field
SELECT * from t1 WHERE field NOT IN (NULL); SELECT * from t1 WHERE field NOT IN (NULL);
field field
A
SELECT * from t1 where field = field; SELECT * from t1 where field = field;
field field
A A
...@@ -16,6 +100,7 @@ NULL ...@@ -16,6 +100,7 @@ NULL
DELETE FROM t1 WHERE field NOT IN (NULL); DELETE FROM t1 WHERE field NOT IN (NULL);
SELECT * FROM t1; SELECT * FROM t1;
field field
A
NULL NULL
drop table t1; drop table t1;
create table t1 (id int(10) primary key); create table t1 (id int(10) primary key);
......
...@@ -598,3 +598,105 @@ INSERT INTO t1 values (1),(1); ...@@ -598,3 +598,105 @@ INSERT INTO t1 values (1),(1);
UPDATE t SET id=(SELECT * FROM t1); UPDATE t SET id=(SELECT * FROM t1);
Subselect returns more than 1 record Subselect returns more than 1 record
drop table t; drop table t;
create table t (a int);
insert into t values (1),(2),(3);
select 1 IN (SELECT * from t);
1 IN (SELECT * from t)
1
select 10 IN (SELECT * from t);
10 IN (SELECT * from t)
0
select NULL IN (SELECT * from t);
NULL IN (SELECT * from t)
NULL
update t set a=NULL where a=2;
select 1 IN (SELECT * from t);
1 IN (SELECT * from t)
1
select 3 IN (SELECT * from t);
3 IN (SELECT * from t)
1
select 10 IN (SELECT * from t);
10 IN (SELECT * from t)
NULL
select 1 > ALL (SELECT * from t);
1 > ALL (SELECT * from t)
0
select 10 > ALL (SELECT * from t);
10 > ALL (SELECT * from t)
NULL
select 1 > ANY (SELECT * from t);
1 > ANY (SELECT * from t)
NULL
select 10 > ANY (SELECT * from t);
10 > ANY (SELECT * from t)
1
drop table t;
create table t (a varchar(20));
insert into t values ('A'),('BC'),('DEF');
select 'A' IN (SELECT * from t);
'A' IN (SELECT * from t)
1
select 'XYZS' IN (SELECT * from t);
'XYZS' IN (SELECT * from t)
0
select NULL IN (SELECT * from t);
NULL IN (SELECT * from t)
NULL
update t set a=NULL where a='BC';
select 'A' IN (SELECT * from t);
'A' IN (SELECT * from t)
1
select 'DEF' IN (SELECT * from t);
'DEF' IN (SELECT * from t)
1
select 'XYZS' IN (SELECT * from t);
'XYZS' IN (SELECT * from t)
NULL
select 'A' > ALL (SELECT * from t);
'A' > ALL (SELECT * from t)
0
select 'XYZS' > ALL (SELECT * from t);
'XYZS' > ALL (SELECT * from t)
NULL
select 'A' > ANY (SELECT * from t);
'A' > ANY (SELECT * from t)
NULL
select 'XYZS' > ANY (SELECT * from t);
'XYZS' > ANY (SELECT * from t)
1
drop table t;
create table t (a float);
insert into t values (1.5),(2.5),(3.5);
select 1.5 IN (SELECT * from t);
1.5 IN (SELECT * from t)
1
select 10.5 IN (SELECT * from t);
10.5 IN (SELECT * from t)
0
select NULL IN (SELECT * from t);
NULL IN (SELECT * from t)
NULL
update t set a=NULL where a=2.5;
select 1.5 IN (SELECT * from t);
1.5 IN (SELECT * from t)
1
select 3.5 IN (SELECT * from t);
3.5 IN (SELECT * from t)
1
select 10.5 IN (SELECT * from t);
10.5 IN (SELECT * from t)
NULL
select 1.5 > ALL (SELECT * from t);
1.5 > ALL (SELECT * from t)
0
select 10.5 > ALL (SELECT * from t);
10.5 > ALL (SELECT * from t)
NULL
select 1.5 > ANY (SELECT * from t);
1.5 > ANY (SELECT * from t)
NULL
select 10.5 > ANY (SELECT * from t);
10.5 > ANY (SELECT * from t)
1
drop table t;
...@@ -2,7 +2,39 @@ ...@@ -2,7 +2,39 @@
# test of IN (NULL) # test of IN (NULL)
# #
select 1 in (1,2,3);
select 10 in (1,2,3);
select NULL in (1,2,3);
select 1 in (1,NULL,3);
select 3 in (1,NULL,3);
select 10 in (1,NULL,3);
select 1.5 in (1.5,2.5,3.5);
select 10.5 in (1.5,2.5,3.5);
select NULL in (1.5,2.5,3.5);
select 1.5 in (1.5,NULL,3.5);
select 3.5 in (1.5,NULL,3.5);
select 10.5 in (1.5,NULL,3.5);
drop table if exists t1; drop table if exists t1;
CREATE TABLE t1 (a int, b int, c int);
insert into t1 values (1,2,3), (1,NULL,3);
select 1 in (a,b,c) from t1;
select 3 in (a,b,c) from t1;
select 10 in (a,b,c) from t1;
select NULL in (a,b,c) from t1;
drop table t1;
CREATE TABLE t1 (a float, b float, c float);
insert into t1 values (1.5,2.5,3.5), (1.5,NULL,3.5);
select 1.5 in (a,b,c) from t1;
select 3.5 in (a,b,c) from t1;
select 10.5 in (a,b,c) from t1;
drop table t1;
CREATE TABLE t1 (a varchar(10), b varchar(10), c varchar(10));
insert into t1 values ('A','BC','EFD'), ('A',NULL,'EFD');
select 'A' in (a,b,c) from t1;
select 'EFD' in (a,b,c) from t1;
select 'XSFGGHF' in (a,b,c) from t1;
drop table t1;
CREATE TABLE t1 (field char(1)); CREATE TABLE t1 (field char(1));
INSERT INTO t1 VALUES ('A'),(NULL); INSERT INTO t1 VALUES ('A'),(NULL);
SELECT * from t1 WHERE field IN (NULL); SELECT * from t1 WHERE field IN (NULL);
......
...@@ -362,3 +362,48 @@ INSERT INTO t1 values (1),(1); ...@@ -362,3 +362,48 @@ INSERT INTO t1 values (1),(1);
-- error 1240 -- error 1240
UPDATE t SET id=(SELECT * FROM t1); UPDATE t SET id=(SELECT * FROM t1);
drop table t; drop table t;
#NULL test
create table t (a int);
insert into t values (1),(2),(3);
select 1 IN (SELECT * from t);
select 10 IN (SELECT * from t);
select NULL IN (SELECT * from t);
update t set a=NULL where a=2;
select 1 IN (SELECT * from t);
select 3 IN (SELECT * from t);
select 10 IN (SELECT * from t);
select 1 > ALL (SELECT * from t);
select 10 > ALL (SELECT * from t);
select 1 > ANY (SELECT * from t);
select 10 > ANY (SELECT * from t);
drop table t;
create table t (a varchar(20));
insert into t values ('A'),('BC'),('DEF');
select 'A' IN (SELECT * from t);
select 'XYZS' IN (SELECT * from t);
select NULL IN (SELECT * from t);
update t set a=NULL where a='BC';
select 'A' IN (SELECT * from t);
select 'DEF' IN (SELECT * from t);
select 'XYZS' IN (SELECT * from t);
select 'A' > ALL (SELECT * from t);
select 'XYZS' > ALL (SELECT * from t);
select 'A' > ANY (SELECT * from t);
select 'XYZS' > ANY (SELECT * from t);
drop table t;
create table t (a float);
insert into t values (1.5),(2.5),(3.5);
select 1.5 IN (SELECT * from t);
select 10.5 IN (SELECT * from t);
select NULL IN (SELECT * from t);
update t set a=NULL where a=2.5;
select 1.5 IN (SELECT * from t);
select 3.5 IN (SELECT * from t);
select 10.5 IN (SELECT * from t);
select 1.5 > ALL (SELECT * from t);
select 10.5 > ALL (SELECT * from t);
select 1.5 > ANY (SELECT * from t);
select 10.5 > ANY (SELECT * from t);
drop table t;
...@@ -46,6 +46,12 @@ Item::Item(): ...@@ -46,6 +46,12 @@ Item::Item():
loop_id= 0; 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) bool Item::check_loop(uint id)
{ {
DBUG_ENTER("Item::check_loop"); DBUG_ENTER("Item::check_loop");
...@@ -436,6 +442,20 @@ String *Item_copy_string::val_str(String *str) ...@@ -436,6 +442,20 @@ String *Item_copy_string::val_str(String *str)
return &str_value; 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) Functions to convert item to field (for send_fields)
*/ */
...@@ -511,10 +531,31 @@ bool Item_asterisk_remover::fix_fields(THD *thd, ...@@ -511,10 +531,31 @@ bool Item_asterisk_remover::fix_fields(THD *thd,
res= item->fix_fields(thd, list, &item); res= item->fix_fields(thd, list, &item);
else else
thd->fatal_error= 1; // no item given => out of memory thd->fatal_error= 1; // no item given => out of memory
*ref= item;
DBUG_RETURN(res); DBUG_RETURN(res);
} }
double Item_ref_null_helper::val()
{
double tmp= (*ref)->val_result();
owner->was_null|= null_value= (*ref)->is_null_result();
return tmp;
}
longlong Item_ref_null_helper::val_int()
{
longlong tmp= (*ref)->val_int_result();
owner->was_null|= null_value= (*ref)->is_null_result();
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();
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) bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{ {
......
...@@ -122,6 +122,18 @@ class Item_wrapper :public Item ...@@ -122,6 +122,18 @@ class Item_wrapper :public Item
String* val_str(String* s) { return item->val_str(s); } String* val_str(String* s) { return item->val_str(s); }
void make_field(Send_field* f) { item->make_field(f); } void make_field(Send_field* f) { item->make_field(f); }
bool check_cols(uint col) { return item->check_cols(col); } 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 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); }
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 +150,6 @@ class Item_outer_select_context_saver :public Item_wrapper ...@@ -138,19 +150,6 @@ class Item_outer_select_context_saver :public Item_wrapper
bool fix_fields(THD *, struct st_table_list *, Item ** ref); 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 st_select_lex;
class Item_ident :public Item class Item_ident :public Item
{ {
...@@ -378,9 +377,13 @@ class Item_string :public Item ...@@ -378,9 +377,13 @@ class Item_string :public Item
enum Item_result result_type () const { return STRING_RESULT; } enum Item_result result_type () const { return STRING_RESULT; }
bool basic_const_item() const { return 1; } bool basic_const_item() const { return 1; }
bool eq(const Item *item, bool binary_cmp) const; 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; } 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); void print(String *str);
}; };
...@@ -498,6 +501,54 @@ class Item_ref :public Item_ident ...@@ -498,6 +501,54 @@ class Item_ref :public Item_ident
bool check_loop(uint id); 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 The following class is used to optimize comparing of date columns
......
...@@ -263,6 +263,61 @@ int Arg_comparator::compare_e_row() ...@@ -263,6 +263,61 @@ int Arg_comparator::compare_e_row()
return 1; 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]->is_null_result())
{
null_value= 1;
return 0;
}
longlong tmp= args[1]->val_int_result();
null_value= args[1]->is_null_result();
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]->is_null_result();
}
return int_cache;
}
double Item_in_optimizer::get_cache()
{
if (!flt_cache_ok)
{
int_cache_ok= 0;
flt_cache_ok= 1;
str_cache_ok= 0;
flt_cache= args[0]->val_result();
null_value= args[0]->is_null_result();
}
return flt_cache;
}
String *Item_in_optimizer::get_cache_str(String *s)
{
if (!str_cache_ok)
{
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();
}
return str_cache;
}
longlong Item_func_eq::val_int() longlong Item_func_eq::val_int()
{ {
...@@ -1092,6 +1147,8 @@ void Item_func_in::fix_length_and_dec() ...@@ -1092,6 +1147,8 @@ void Item_func_in::fix_length_and_dec()
array->set(j,args[i]); array->set(j,args[i]);
if (!args[i]->null_value) // Skip NULL values if (!args[i]->null_value) // Skip NULL values
j++; j++;
else
have_null= 1;
} }
if ((array->used_count=j)) if ((array->used_count=j))
array->sort(); array->sort();
...@@ -1138,17 +1195,20 @@ longlong Item_func_in::val_int() ...@@ -1138,17 +1195,20 @@ longlong Item_func_in::val_int()
if (array) if (array)
{ {
int tmp=array->find(item); int tmp=array->find(item);
null_value=item->null_value; null_value=item->null_value || (!tmp && have_null);
return tmp; return tmp;
} }
in_item->store_value(item); in_item->store_value(item);
if ((null_value=item->null_value)) if ((null_value=item->null_value))
return 0; return 0;
have_null= 0;
for (uint i=0 ; i < arg_count ; i++) for (uint i=0 ; i < arg_count ; i++)
{ {
if (!in_item->cmp(args[i]) && !args[i]->null_value) if (!in_item->cmp(args[i]) && !args[i]->null_value)
return 1; // Would maybe be nice with i ? return 1; // Would maybe be nice with i ?
have_null|= args[i]->null_value;
} }
null_value= have_null;
return 0; return 0;
} }
......
...@@ -87,6 +87,27 @@ class Item_bool_func :public Item_int_func ...@@ -87,6 +87,27 @@ class Item_bool_func :public Item_int_func
void fix_length_and_dec() { decimals=0; max_length=1; } 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_buff, *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 class Item_bool_func2 :public Item_int_func
{ /* Bool with 2 string args */ { /* Bool with 2 string args */
protected: protected:
...@@ -488,9 +509,10 @@ class Item_func_in :public Item_int_func ...@@ -488,9 +509,10 @@ class Item_func_in :public Item_int_func
Item *item; Item *item;
in_vector *array; in_vector *array;
cmp_item *in_item; cmp_item *in_item;
bool have_null;
public: public:
Item_func_in(Item *a,List<Item> &list) 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) {}
longlong val_int(); longlong val_int();
bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref) bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref)
{ {
......
...@@ -33,9 +33,10 @@ SUBSELECT TODO: ...@@ -33,9 +33,10 @@ SUBSELECT TODO:
#include "sql_select.h" #include "sql_select.h"
Item_subselect::Item_subselect(): 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 item value is NULL if select_subselect not changed this value
(i.e. some rows will be found returned) (i.e. some rows will be found returned)
...@@ -93,8 +94,10 @@ bool Item_subselect::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) ...@@ -93,8 +94,10 @@ bool Item_subselect::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{ {
(*ref)= substitution; (*ref)= substitution;
substitution->name= name; substitution->name= name;
if (have_to_be_excluded)
engine->exclude(); engine->exclude();
return substitution->fix_fields(thd, tables, ref); substitution= 0;
return (*ref)->fix_fields(thd, tables, ref);
} }
char const *save_where= thd->where; char const *save_where= thd->where;
...@@ -159,7 +162,7 @@ double Item_singleval_subselect::val () ...@@ -159,7 +162,7 @@ double Item_singleval_subselect::val ()
{ {
if (engine->exec()) if (engine->exec())
{ {
assign_null(); reset();
return 0; return 0;
} }
return real_value; return real_value;
...@@ -169,7 +172,7 @@ longlong Item_singleval_subselect::val_int () ...@@ -169,7 +172,7 @@ longlong Item_singleval_subselect::val_int ()
{ {
if (engine->exec()) if (engine->exec())
{ {
assign_null(); reset();
return 0; return 0;
} }
return int_value; return int_value;
...@@ -179,7 +182,7 @@ String *Item_singleval_subselect::val_str (String *str) ...@@ -179,7 +182,7 @@ String *Item_singleval_subselect::val_str (String *str)
{ {
if (engine->exec() || null_value) if (engine->exec() || null_value)
{ {
assign_null(); reset();
return 0; return 0;
} }
return &string_value; return &string_value;
...@@ -208,9 +211,8 @@ Item_in_subselect::Item_in_subselect(THD *thd, Item * left_exp, ...@@ -208,9 +211,8 @@ Item_in_subselect::Item_in_subselect(THD *thd, Item * left_exp,
left_expr= left_exp; left_expr= left_exp;
init(thd, select_lex, new select_exists_subselect(this)); init(thd, select_lex, new select_exists_subselect(this));
max_columns= UINT_MAX; max_columns= UINT_MAX;
null_value= 0; //can't be NULL maybe_null= 1;
maybe_null= 0; //can't be NULL reset();
value= 0;
// We need only 1 row to determinate existence // We need only 1 row to determinate existence
select_lex->master_unit()->global_parameters->select_limit= 1; select_lex->master_unit()->global_parameters->select_limit= 1;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
...@@ -226,9 +228,7 @@ Item_allany_subselect::Item_allany_subselect(THD *thd, Item * left_exp, ...@@ -226,9 +228,7 @@ Item_allany_subselect::Item_allany_subselect(THD *thd, Item * left_exp,
func= f; func= f;
init(thd, select_lex, new select_exists_subselect(this)); init(thd, select_lex, new select_exists_subselect(this));
max_columns= UINT_MAX; max_columns= UINT_MAX;
null_value= 0; //can't be NULL reset();
maybe_null= 0; //can't be NULL
value= 0;
// We need only 1 row to determinate existence // We need only 1 row to determinate existence
select_lex->master_unit()->global_parameters->select_limit= 1; select_lex->master_unit()->global_parameters->select_limit= 1;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
...@@ -237,6 +237,7 @@ Item_allany_subselect::Item_allany_subselect(THD *thd, Item * left_exp, ...@@ -237,6 +237,7 @@ Item_allany_subselect::Item_allany_subselect(THD *thd, Item * left_exp,
void Item_exists_subselect::fix_length_and_dec() void Item_exists_subselect::fix_length_and_dec()
{ {
decimals=0;
max_length= 1; max_length= 1;
} }
...@@ -244,7 +245,7 @@ double Item_exists_subselect::val () ...@@ -244,7 +245,7 @@ double Item_exists_subselect::val ()
{ {
if (engine->exec()) if (engine->exec())
{ {
assign_null(); reset();
return 0; return 0;
} }
return (double) value; return (double) value;
...@@ -254,7 +255,7 @@ longlong Item_exists_subselect::val_int () ...@@ -254,7 +255,7 @@ longlong Item_exists_subselect::val_int ()
{ {
if (engine->exec()) if (engine->exec())
{ {
assign_null(); reset();
return 0; return 0;
} }
return value; return value;
...@@ -264,7 +265,50 @@ String *Item_exists_subselect::val_str(String *str) ...@@ -264,7 +265,50 @@ String *Item_exists_subselect::val_str(String *str)
{ {
if (engine->exec()) 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; return 0;
} }
str->set(value,thd_charset()); str->set(value,thd_charset());
...@@ -288,8 +332,23 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex, ...@@ -288,8 +332,23 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex,
compare_func_creator func) compare_func_creator func)
{ {
DBUG_ENTER("Item_in_subselect::single_value_transformer"); 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()) for (SELECT_LEX * sl= select_lex; sl; sl= sl->next_select())
{ {
select_lex->dependent= 1;
Item *item; Item *item;
if (sl->item_list.elements > 1) if (sl->item_list.elements > 1)
{ {
...@@ -299,14 +358,14 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex, ...@@ -299,14 +358,14 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex,
else else
item= (Item*) sl->item_list.pop(); 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 || if (sl->having || sl->with_sum_func || sl->group_list.first ||
sl->order_list.first) sl->order_list.first)
{ {
sl->item_list.push_back(item); sl->item_list.push_back(item);
item= (*func)(expr, new Item_ref(sl->item_list.head_ref(), item= (*func)(expr, new Item_ref_null_helper(this,
0, (char*)"<result>")); 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->with_sum_func || sl->group_list.first)
if (sl->having) if (sl->having)
sl->having= new Item_cond_and(sl->having, item); 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, ...@@ -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)); sl->item_list.push_back(new Item_int(1));
if (sl->table_list.elements) 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) if (sl->where)
sl->where= new Item_cond_and(sl->where, item); sl->where= new Item_cond_and(sl->where, item);
else else
...@@ -340,14 +401,21 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex, ...@@ -340,14 +401,21 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex,
} }
if (select_lex->next_select()) 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 else
{ {
// it is single select without tables => possible optimization // it is single select without tables => possible optimization
item= (*func)(left_expr, item); item= (*func)(left_expr, item);
substitution= item; substitution= item;
have_to_be_excluded= 1;
THD *thd= current_thd; THD *thd= current_thd;
if (thd->lex.describe) if (thd->lex.describe)
{ {
...@@ -489,7 +557,7 @@ int subselect_single_select_engine::exec() ...@@ -489,7 +557,7 @@ int subselect_single_select_engine::exec()
join->thd->where= save_where; join->thd->where= save_where;
DBUG_RETURN(1); DBUG_RETURN(1);
} }
item->assign_null(); item->reset();
item->assigned((executed= 0)); item->assigned((executed= 0));
} }
if (!executed) if (!executed)
......
...@@ -42,6 +42,8 @@ class Item_subselect :public Item_result_field ...@@ -42,6 +42,8 @@ class Item_subselect :public Item_result_field
subselect_engine *engine; subselect_engine *engine;
/* allowed number of columns (1 for single value subqueries) */ /* allowed number of columns (1 for single value subqueries) */
uint max_columns; uint max_columns;
/* work with 'substitution' */
bool have_to_be_excluded;
public: public:
Item_subselect(); Item_subselect();
...@@ -65,7 +67,7 @@ class Item_subselect :public Item_result_field ...@@ -65,7 +67,7 @@ class Item_subselect :public Item_result_field
select_subselect *result); select_subselect *result);
~Item_subselect(); ~Item_subselect();
virtual void assign_null() virtual void reset()
{ {
null_value= 1; null_value= 1;
} }
...@@ -110,7 +112,7 @@ class Item_singleval_subselect :public Item_subselect ...@@ -110,7 +112,7 @@ class Item_singleval_subselect :public Item_subselect
decimals= item->decimals; decimals= item->decimals;
res_type= item->res_type; res_type= item->res_type;
} }
virtual void assign_null() virtual void reset()
{ {
null_value= 1; null_value= 1;
int_value= 0; int_value= 0;
...@@ -144,7 +146,7 @@ class Item_exists_subselect :public Item_subselect ...@@ -144,7 +146,7 @@ class Item_exists_subselect :public Item_subselect
} }
Item_exists_subselect(): Item_subselect() {} Item_exists_subselect(): Item_subselect() {}
virtual void assign_null() virtual void reset()
{ {
value= 0; value= 0;
} }
...@@ -155,6 +157,7 @@ class Item_exists_subselect :public Item_subselect ...@@ -155,6 +157,7 @@ class Item_exists_subselect :public Item_subselect
double val(); double val();
String *val_str(String*); String *val_str(String*);
void fix_length_and_dec(); void fix_length_and_dec();
friend class select_exists_subselect; friend class select_exists_subselect;
}; };
...@@ -164,14 +167,26 @@ class Item_in_subselect :public Item_exists_subselect ...@@ -164,14 +167,26 @@ class Item_in_subselect :public Item_exists_subselect
{ {
protected: protected:
Item * left_expr; Item * left_expr;
bool was_null;
public: public:
Item_in_subselect(THD *thd, Item * left_expr, st_select_lex *select_lex); Item_in_subselect(THD *thd, Item * left_expr, st_select_lex *select_lex);
Item_in_subselect(Item_in_subselect *item); Item_in_subselect(Item_in_subselect *item);
Item_in_subselect(): Item_exists_subselect() {} 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); virtual void select_transformer(st_select_lex *select_lex);
void single_value_transformer(st_select_lex *select_lex, void single_value_transformer(st_select_lex *select_lex,
Item *left_expr, compare_func_creator func); 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 */ /* ALL/ANY/SOME subselect */
......
...@@ -937,7 +937,7 @@ bool select_singleval_subselect::send_data(List<Item> &items) ...@@ -937,7 +937,7 @@ bool select_singleval_subselect::send_data(List<Item> &items)
it->real_value= val_item->val_result(); it->real_value= val_item->val_result();
if ((it->null_value= val_item->is_null_result())) if ((it->null_value= val_item->is_null_result()))
{ {
it->assign_null(); it->reset();
} }
else else
{ {
......
...@@ -216,7 +216,7 @@ int st_select_lex_unit::exec() ...@@ -216,7 +216,7 @@ int st_select_lex_unit::exec()
if (optimized && item && item->assigned()) if (optimized && item && item->assigned())
{ {
item->assigned(0); // We will reinit & rexecute unit item->assigned(0); // We will reinit & rexecute unit
item->assign_null(); item->reset();
table->file->delete_all_rows(); table->file->delete_all_rows();
} }
for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment