Commit 100a101a authored by bell@sanja.is.com.ua's avatar bell@sanja.is.com.ua

Merge

parents 7c799b17 223f305c
...@@ -46,7 +46,7 @@ SELECT 1 FROM (SELECT 1 as a) as b HAVING (SELECT a)=1; ...@@ -46,7 +46,7 @@ SELECT 1 FROM (SELECT 1 as a) as b HAVING (SELECT a)=1;
1 1
1 1
SELECT (SELECT 1), a; SELECT (SELECT 1), a;
ERROR 42S22: Unknown column 'a' in 'field list' ERROR 42S22: Unknown column 'a' in 'checking transformed subquery'
SELECT 1 as a FROM (SELECT 1) as b HAVING (SELECT a)=1; SELECT 1 as a FROM (SELECT 1) as b HAVING (SELECT a)=1;
a a
1 1
...@@ -677,7 +677,6 @@ id ...@@ -677,7 +677,6 @@ id
EXPLAIN SELECT * FROM t2 WHERE id IN (SELECT 1+(select 1)); EXPLAIN SELECT * FROM t2 WHERE id IN (SELECT 1+(select 1));
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ref id id 5 const 1 Using where; Using index 1 PRIMARY t2 ref id id 5 const 1 Using where; Using index
3 SUBQUERY NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings: Warnings:
Note 1247 Select 3 was reduced during optimisation Note 1247 Select 3 was reduced during optimisation
Note 1247 Select 2 was reduced during optimisation Note 1247 Select 2 was reduced during optimisation
...@@ -1025,7 +1024,7 @@ CREATE TABLE t1 SELECT (SELECT 1 as a UNION SELECT 1+1 limit 1,1) as a; ...@@ -1025,7 +1024,7 @@ CREATE TABLE t1 SELECT (SELECT 1 as a UNION SELECT 1+1 limit 1,1) as a;
SHOW CREATE TABLE t1; SHOW CREATE TABLE t1;
Table Create Table Table Create Table
t1 CREATE TABLE `t1` ( t1 CREATE TABLE `t1` (
`a` bigint(1) NOT NULL default '0' `a` bigint(17) NOT NULL default '0'
) TYPE=MyISAM CHARSET=latin1 ) TYPE=MyISAM CHARSET=latin1
drop table t1; drop table t1;
create table t1 (a int); create table t1 (a int);
...@@ -1200,3 +1199,53 @@ SELECT 'c373e9f5ad0791a0dab5444553544200' IN(SELECT t1.FOLDERID FROM t1 WHERE t1 ...@@ -1200,3 +1199,53 @@ SELECT 'c373e9f5ad0791a0dab5444553544200' IN(SELECT t1.FOLDERID FROM t1 WHERE t1
'c373e9f5ad0791a0dab5444553544200' IN(SELECT t1.FOLDERID FROM t1 WHERE t1.PARENTID='2f6161e879db43c1a5b82c21ddc49089' AND t1.FOLDERNAME = 'Level1') 'c373e9f5ad0791a0dab5444553544200' IN(SELECT t1.FOLDERID FROM t1 WHERE t1.PARENTID='2f6161e879db43c1a5b82c21ddc49089' AND t1.FOLDERNAME = 'Level1')
0 0
drop table t1; drop table t1;
create table t1 (a int not null, b int, primary key (a));
create table t2 (a int not null, primary key (a));
create table t3 (a int not null, b int, primary key (a));
insert into t1 values (1,10), (2,20), (3,30), (4,40);
insert into t2 values (2), (3), (4), (5);
insert into t3 values (10,3), (20,4), (30,5);
select * from t2 where t2.a in (select a from t1);
a
2
3
4
explain select * from t2 where t2.a in (select a from t1);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 index NULL PRIMARY 4 NULL 4 Using where; Using index
2 DEPENDENT SUBQUERY t1 eq_ref PRIMARY PRIMARY 4 func 1 Using where; Using index
select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
a
2
3
explain select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 index NULL PRIMARY 4 NULL 4 Using where; Using index
2 DEPENDENT SUBQUERY t1 eq_ref PRIMARY PRIMARY 4 func 1 Using where
2 DEPENDENT SUBQUERY t3 eq_ref PRIMARY PRIMARY 4 test.t1.b 1 Using where; Using index
drop table t1, t2, t3;
create table t1 (a int, b int, index a (a));
create table t2 (a int, index a (a));
create table t3 (a int, b int, index a (a));
insert into t1 values (1,10), (2,20), (3,30), (4,40);
insert into t2 values (2), (3), (4), (5);
insert into t3 values (10,3), (20,4), (30,5);
select * from t2 where t2.a in (select a from t1);
a
2
3
4
explain select * from t2 where t2.a in (select a from t1);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 index NULL a 5 NULL 4 Using where; Using index
2 DEPENDENT SUBQUERY t1 ref a a 5 func 10 Using where; Using index
select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
a
2
3
explain select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 index NULL a 5 NULL 4 Using where; Using index
2 DEPENDENT SUBQUERY t1 ref a a 5 func 10 Using where
2 DEPENDENT SUBQUERY t3 index a a 5 NULL 3 Using where; Using index
drop table t1, t2, t3;
...@@ -792,3 +792,38 @@ INSERT INTO t1 VALUES("2f6161e879db43c1a5b82c21ddc49089", "Default", "System", " ...@@ -792,3 +792,38 @@ INSERT INTO t1 VALUES("2f6161e879db43c1a5b82c21ddc49089", "Default", "System", "
INSERT INTO t1 VALUES("c373e9f5ad0791724315444553544200", "AddDocumentTest", "admin", "2003-06-09 10:51:25", "Movie Reviews", "0", "2003-06-09 10:51:25", "admin", "0", "2f6161e879db43c1a5b82c21ddc49089", "03eea05112b845949f3fd03278b5fe43", NULL); INSERT INTO t1 VALUES("c373e9f5ad0791724315444553544200", "AddDocumentTest", "admin", "2003-06-09 10:51:25", "Movie Reviews", "0", "2003-06-09 10:51:25", "admin", "0", "2f6161e879db43c1a5b82c21ddc49089", "03eea05112b845949f3fd03278b5fe43", NULL);
SELECT 'c373e9f5ad0791a0dab5444553544200' IN(SELECT t1.FOLDERID FROM t1 WHERE t1.PARENTID='2f6161e879db43c1a5b82c21ddc49089' AND t1.FOLDERNAME = 'Level1'); SELECT 'c373e9f5ad0791a0dab5444553544200' IN(SELECT t1.FOLDERID FROM t1 WHERE t1.PARENTID='2f6161e879db43c1a5b82c21ddc49089' AND t1.FOLDERNAME = 'Level1');
drop table t1; drop table t1;
#
# IN subselect optimization test
#
create table t1 (a int not null, b int, primary key (a));
create table t2 (a int not null, primary key (a));
create table t3 (a int not null, b int, primary key (a));
insert into t1 values (1,10), (2,20), (3,30), (4,40);
insert into t2 values (2), (3), (4), (5);
insert into t3 values (10,3), (20,4), (30,5);
select * from t2 where t2.a in (select a from t1);
explain select * from t2 where t2.a in (select a from t1);
select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
explain select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
drop table t1, t2, t3;
create table t1 (a int, b int, index a (a));
create table t2 (a int, index a (a));
create table t3 (a int, b int, index a (a));
insert into t1 values (1,10), (2,20), (3,30), (4,40);
disable_query_log;
# making table large enough
let $1 = 10000;
while ($1)
{
eval insert into t1 values (rand()*100000+200,rand()*100000);
dec $1;
}
enable_query_log;
insert into t2 values (2), (3), (4), (5);
insert into t3 values (10,3), (20,4), (30,5);
select * from t2 where t2.a in (select a from t1);
explain select * from t2 where t2.a in (select a from t1);
select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
explain select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
drop table t1, t2, t3;
...@@ -1412,17 +1412,15 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) ...@@ -1412,17 +1412,15 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
} }
} }
/* /*
* The following conditional is changed as to correctly identify The following conditional is changed as to correctly identify
* incorrect references in group functions or forward references incorrect references in group functions or forward references
* with sub-select's / derived tables, while it prevents this with sub-select's / derived tables, while it prevents this
* check when Item_ref is created in an expression involving check when Item_ref is created in an expression involving
* summing function, which is to be placed in the user variable. summing function, which is to be placed in the user variable.
* */
*/
if (((*ref)->with_sum_func && name && if (((*ref)->with_sum_func && name &&
(depended_from || (depended_from ||
!(thd->lex.current_select->linkage != GLOBAL_OPTIONS_TYPE && !(thd->lex.current_select->linkage != GLOBAL_OPTIONS_TYPE &&
thd->lex.current_select->select_lex()->having_fix_field))) || thd->lex.current_select->select_lex()->having_fix_field))) ||
!(*ref)->fixed) !(*ref)->fixed)
...@@ -1669,11 +1667,11 @@ Item_cache* Item_cache::get_cache(Item_result type) ...@@ -1669,11 +1667,11 @@ Item_cache* Item_cache::get_cache(Item_result type)
void Item_cache_str::store(Item *item) void Item_cache_str::store(Item *item)
{ {
str_value.set(buffer, sizeof(buffer), item->charset()); value_buff.set(buffer, sizeof(buffer), item->charset());
value= item->str_result(&str_value); value= item->str_result(&value_buff);
if ((null_value= item->null_value)) if ((null_value= item->null_value))
value= 0; value= 0;
else if (value != &str_value) else if (value != &value_buff)
{ {
/* /*
We copy string value to avoid changing value if 'item' is table field We copy string value to avoid changing value if 'item' is table field
...@@ -1683,10 +1681,10 @@ void Item_cache_str::store(Item *item) ...@@ -1683,10 +1681,10 @@ void Item_cache_str::store(Item *item)
(select c from t1 where a=t2.a) (select c from t1 where a=t2.a)
from t2; from t2;
*/ */
str_value.copy(*value); value_buff.copy(*value);
value= &str_value; value= &value_buff;
} }
set_charset(&item->collation);
} }
double Item_cache_str::val() double Item_cache_str::val()
{ {
......
...@@ -159,7 +159,7 @@ class Item { ...@@ -159,7 +159,7 @@ class Item {
virtual bool get_time(TIME *ltime); virtual bool get_time(TIME *ltime);
virtual bool get_date_result(TIME *ltime,bool fuzzydate) virtual bool get_date_result(TIME *ltime,bool fuzzydate)
{ return get_date(ltime,fuzzydate); } { return get_date(ltime,fuzzydate); }
virtual bool is_null() { return 0; }; virtual bool is_null() { return 0; }
virtual void top_level_item() {} virtual void top_level_item() {}
virtual void set_result_field(Field *field) {} virtual void set_result_field(Field *field) {}
virtual bool is_result_field() { return 0; } virtual bool is_result_field() { return 0; }
...@@ -626,6 +626,15 @@ class Item_ref_null_helper: public Item_ref ...@@ -626,6 +626,15 @@ class Item_ref_null_helper: public Item_ref
longlong val_int(); longlong val_int();
String* val_str(String* s); String* val_str(String* s);
bool get_date(TIME *ltime, bool fuzzydate); bool get_date(TIME *ltime, bool fuzzydate);
void print(String *str)
{
str->append("ref_null_helper(");
if (ref && *ref)
(*ref)->print(str);
else
str->append('?');
str->append(')');
}
}; };
...@@ -671,6 +680,15 @@ class Item_asterisk_remover :public Item_ref_null_helper ...@@ -671,6 +680,15 @@ class Item_asterisk_remover :public Item_ref_null_helper
{} {}
bool fix_fields(THD *, struct st_table_list *, Item ** ref); bool fix_fields(THD *, struct st_table_list *, Item ** ref);
Item **storage() {return &item;} Item **storage() {return &item;}
void print(String *str)
{
str->append("ref_null_helper('");
if (item)
item->print(str);
else
str->append('?');
str->append(')');
}
}; };
/* /*
...@@ -902,7 +920,7 @@ class Item_cache_real: public Item_cache ...@@ -902,7 +920,7 @@ class Item_cache_real: public Item_cache
class Item_cache_str: public Item_cache class Item_cache_str: public Item_cache
{ {
char buffer[80]; char buffer[80];
String *value; String *value, value_buff;
public: public:
Item_cache_str(): Item_cache() { } Item_cache_str(): Item_cache() { }
......
...@@ -367,16 +367,24 @@ int Arg_comparator::compare_e_row() ...@@ -367,16 +367,24 @@ int Arg_comparator::compare_e_row()
return 1; return 1;
} }
bool Item_in_optimizer::preallocate_row()
bool Item_in_optimizer::fix_left(THD *thd,
struct st_table_list *tables,
Item **ref)
{ {
return (!(cache= Item_cache::get_cache(ROW_RESULT))); if (args[0]->fix_fields(thd, tables, ref) ||
(!cache && !(cache= Item_cache::get_cache(args[0]->result_type()))))
return 1;
cache->setup(args[0]);
return 0;
} }
bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables, bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
Item ** ref) Item ** ref)
{ {
if (args[0]->fix_fields(thd, tables, args)) if (fix_left(thd, tables, ref))
return 1; return 1;
if (args[0]->maybe_null) if (args[0]->maybe_null)
maybe_null=1; maybe_null=1;
...@@ -389,9 +397,6 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables, ...@@ -389,9 +397,6 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
with_sum_func= args[0]->with_sum_func; with_sum_func= args[0]->with_sum_func;
used_tables_cache= args[0]->used_tables(); used_tables_cache= args[0]->used_tables();
const_item_cache= args[0]->const_item(); const_item_cache= args[0]->const_item();
if (!cache && !(cache= Item_cache::get_cache(args[0]->result_type())))
return 1;
cache->setup(args[0]);
if (cache->cols() == 1) if (cache->cols() == 1)
{ {
if (args[0]->used_tables()) if (args[0]->used_tables())
...@@ -410,7 +415,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables, ...@@ -410,7 +415,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
((Item_cache *)cache->el(i))->set_used_tables(0); ((Item_cache *)cache->el(i))->set_used_tables(0);
} }
} }
if (args[1]->fix_fields(thd, tables, args)) if (!args[1]->fixed && args[1]->fix_fields(thd, tables, args))
return 1; return 1;
Item_in_subselect * sub= (Item_in_subselect *)args[1]; Item_in_subselect * sub= (Item_in_subselect *)args[1];
if (args[0]->cols() != sub->engine->cols()) if (args[0]->cols() != sub->engine->cols())
...@@ -1648,7 +1653,8 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) ...@@ -1648,7 +1653,8 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
} }
if (abort_on_null) if (abort_on_null)
item->top_level_item(); item->top_level_item();
if (item->fix_fields(thd, tables, li.ref()) || item->check_cols(1)) if ((!item->fixed &&
item->fix_fields(thd, tables, li.ref())) || item->check_cols(1))
return 1; /* purecov: inspected */ return 1; /* purecov: inspected */
used_tables_cache|=item->used_tables(); used_tables_cache|=item->used_tables();
with_sum_func= with_sum_func || item->with_sum_func; with_sum_func= with_sum_func || item->with_sum_func;
......
...@@ -91,9 +91,8 @@ class Item_in_optimizer: public Item_bool_func ...@@ -91,9 +91,8 @@ class Item_in_optimizer: public Item_bool_func
public: public:
Item_in_optimizer(Item *a, Item_in_subselect *b): Item_in_optimizer(Item *a, Item_in_subselect *b):
Item_bool_func(a, (Item *)b), cache(0) {} Item_bool_func(a, (Item *)b), cache(0) {}
// used by row in transformer
bool preallocate_row();
bool fix_fields(THD *, struct st_table_list *, Item **); bool fix_fields(THD *, struct st_table_list *, Item **);
bool fix_left(THD *thd, struct st_table_list *tables, Item **ref);
bool is_null(); bool is_null();
/* /*
Item_in_optimizer item is special boolean function. On value request Item_in_optimizer item is special boolean function. On value request
...@@ -103,7 +102,7 @@ class Item_in_optimizer: public Item_bool_func ...@@ -103,7 +102,7 @@ class Item_in_optimizer: public Item_bool_func
Item_in_optimizer return NULL, else it evaluate Item_in_subselect. Item_in_optimizer return NULL, else it evaluate Item_in_subselect.
*/ */
longlong val_int(); longlong val_int();
const char *func_name() const { return "IN_OPTIMIZER"; }
Item_cache **get_cache() { return &cache; } Item_cache **get_cache() { return &cache; }
}; };
......
...@@ -56,7 +56,6 @@ void Item_subselect::init(THD *thd, st_select_lex *select_lex, ...@@ -56,7 +56,6 @@ void Item_subselect::init(THD *thd, st_select_lex *select_lex,
DBUG_ENTER("Item_subselect::init"); DBUG_ENTER("Item_subselect::init");
DBUG_PRINT("subs", ("select_lex 0x%xl", (ulong) select_lex)); DBUG_PRINT("subs", ("select_lex 0x%xl", (ulong) select_lex));
select_transformer(thd, select_lex->master_unit());
if (select_lex->next_select()) if (select_lex->next_select())
engine= new subselect_union_engine(thd, select_lex->master_unit(), result, engine= new subselect_union_engine(thd, select_lex->master_unit(), result,
this); this);
...@@ -72,10 +71,12 @@ Item_subselect::~Item_subselect() ...@@ -72,10 +71,12 @@ Item_subselect::~Item_subselect()
delete engine; delete engine;
} }
void Item_subselect::select_transformer(THD *thd, st_select_lex_unit *unit) Item_subselect::trans_res
Item_subselect::select_transformer(THD *thd,
JOIN *join)
{ {
DBUG_ENTER("Item_subselect::select_transformer"); DBUG_ENTER("Item_subselect::select_transformer");
DBUG_VOID_RETURN; DBUG_RETURN(OK);
} }
...@@ -83,27 +84,28 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref) ...@@ -83,27 +84,28 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref)
{ {
thd= thd_param; thd= thd_param;
if (substitution)
{
(*ref)= substitution;
substitution->name= name;
if (have_to_be_excluded)
engine->exclude();
substitution= 0;
int ret= (*ref)->fix_fields(thd, tables, ref);
// We can't substitute aggregate functions (like (SELECT (max(i)))
if ((*ref)->with_sum_func)
{
my_error(ER_INVALID_GROUP_FUNC_USE, MYF(0));
return 1;
}
return ret;
}
char const *save_where= thd->where; char const *save_where= thd->where;
int res= engine->prepare(); int res= engine->prepare();
if (!res) if (!res)
{ {
if (substitution)
{
(*ref)= substitution;
substitution->name= name;
if (have_to_be_excluded)
engine->exclude();
substitution= 0;
fixed= 1;
thd->where= "checking transformed subquery";
int ret= (*ref)->fix_fields(thd, tables, ref);
// We can't substitute aggregate functions (like (SELECT (max(i)))
if ((*ref)->with_sum_func)
{
my_error(ER_INVALID_GROUP_FUNC_USE, MYF(0));
return 1;
}
return ret;
}
// Is it one field subselect? // Is it one field subselect?
if (engine->cols() > max_columns) if (engine->cols() > max_columns)
{ {
...@@ -166,12 +168,14 @@ void Item_singlerow_subselect::reset() ...@@ -166,12 +168,14 @@ void Item_singlerow_subselect::reset()
value->null_value= 1; value->null_value= 1;
} }
void Item_singlerow_subselect::select_transformer(THD *thd, Item_subselect::trans_res
st_select_lex_unit *unit) Item_singlerow_subselect::select_transformer(THD *thd,
JOIN *join)
{ {
SELECT_LEX *select_lex= unit->first_select(); SELECT_LEX *select_lex= join->select_lex;
if (!select_lex->next_select() && !select_lex->table_list.elements && if (!select_lex->master_unit()->first_select()->next_select() &&
!select_lex->table_list.elements &&
select_lex->item_list.elements == 1 && select_lex->item_list.elements == 1 &&
/* /*
We cant change name of Item_field or Item_ref, because it will We cant change name of Item_field or Item_ref, because it will
...@@ -199,18 +203,20 @@ void Item_singlerow_subselect::select_transformer(THD *thd, ...@@ -199,18 +203,20 @@ void Item_singlerow_subselect::select_transformer(THD *thd,
if (select_lex->where || select_lex->having) if (select_lex->where || select_lex->having)
{ {
Item *cond; Item *cond;
if (!select_lex->having) if (!join->having)
cond= select_lex->where; cond= join->conds;
else if (!select_lex->where) else if (!join->conds)
cond= select_lex->having; cond= join->having;
else else
if (!(cond= new Item_cond_and(select_lex->having, select_lex->where))) if (!(cond= new Item_cond_and(join->conds, join->having)))
return; return ERROR;
if (!(substitution= new Item_func_if(cond, substitution, if (!(substitution= new Item_func_if(cond, substitution,
new Item_null()))) new Item_null())))
return; return ERROR;
} }
return REDUCE;
} }
return OK;
} }
void Item_singlerow_subselect::store(uint i, Item *item) void Item_singlerow_subselect::store(uint i, Item *item)
...@@ -329,6 +335,37 @@ Item_exists_subselect::Item_exists_subselect(THD *thd, ...@@ -329,6 +335,37 @@ Item_exists_subselect::Item_exists_subselect(THD *thd,
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
bool Item_in_subselect::test_limit(SELECT_LEX_UNIT *unit)
{
SELECT_LEX_NODE *global= unit->global_parameters;
if (global->select_limit != HA_POS_ERROR)
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0),
"LIMIT & IN/ALL/ANY/SOME subquery");
return(1);
}
SELECT_LEX *sl= unit->first_select();
for (; sl; sl= sl->next_select())
{
if (sl->select_limit != HA_POS_ERROR)
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0),
"LIMIT & IN/ALL/ANY/SOME subquery");
return(1);
}
// We need only 1 row to determinate existence
sl->select_limit= 1;
// no sense in ORDER BY without LIMIT
sl->order_list.empty();
}
// no sense in ORDER BY without LIMIT
global->order_list.empty();
// We need only 1 row to determinate existence
global->select_limit= 1;
return(0);
}
Item_in_subselect::Item_in_subselect(THD *thd, Item * left_exp, Item_in_subselect::Item_in_subselect(THD *thd, Item * left_exp,
st_select_lex *select_lex): st_select_lex *select_lex):
Item_exists_subselect() Item_exists_subselect()
...@@ -338,25 +375,25 @@ Item_in_subselect::Item_in_subselect(THD *thd, Item * left_exp, ...@@ -338,25 +375,25 @@ Item_in_subselect::Item_in_subselect(THD *thd, Item * 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;
maybe_null= 1; maybe_null= 1;
abort_on_null= 0;
reset(); reset();
// We need only 1 row to determinate existence test_limit(select_lex->master_unit());
select_lex->master_unit()->global_parameters->select_limit= 1;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
Item_allany_subselect::Item_allany_subselect(THD *thd, Item * left_exp, Item_allany_subselect::Item_allany_subselect(THD *thd, Item * left_exp,
compare_func_creator f, compare_func_creator fn,
st_select_lex *select_lex): st_select_lex *select_lex):
Item_in_subselect() Item_in_subselect()
{ {
DBUG_ENTER("Item_in_subselect::Item_in_subselect"); DBUG_ENTER("Item_in_subselect::Item_in_subselect");
left_expr= left_exp; left_expr= left_exp;
func= f; func= fn;
init(thd, select_lex, new select_exists_subselect(this)); init(thd, select_lex, new select_exists_subselect(this));
max_columns= 1; max_columns= 1;
abort_on_null= 0;
reset(); reset();
// We need only 1 row to determinate existence test_limit(select_lex->master_unit());
select_lex->master_unit()->global_parameters->select_limit= 1;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -446,6 +483,7 @@ Item_in_subselect::Item_in_subselect(Item_in_subselect *item): ...@@ -446,6 +483,7 @@ Item_in_subselect::Item_in_subselect(Item_in_subselect *item):
Item_exists_subselect(item) Item_exists_subselect(item)
{ {
left_expr= item->left_expr; left_expr= item->left_expr;
abort_on_null= item->abort_on_null;
} }
Item_allany_subselect::Item_allany_subselect(Item_allany_subselect *item): Item_allany_subselect::Item_allany_subselect(Item_allany_subselect *item):
...@@ -454,227 +492,258 @@ Item_allany_subselect::Item_allany_subselect(Item_allany_subselect *item): ...@@ -454,227 +492,258 @@ Item_allany_subselect::Item_allany_subselect(Item_allany_subselect *item):
func= item->func; func= item->func;
} }
void Item_in_subselect::single_value_transformer(THD *thd, Item_subselect::trans_res
st_select_lex_unit *unit, Item_in_subselect::single_value_transformer(THD *thd,
Item *left_expr, JOIN *join,
compare_func_creator func) Item *left_expr,
compare_func_creator func)
{ {
DBUG_ENTER("Item_in_subselect::single_value_transformer"); DBUG_ENTER("Item_in_subselect::single_value_transformer");
if (unit->global_parameters->select_limit != HA_POS_ERROR) SELECT_LEX *select_lex= join->select_lex;
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0),
"LIMIT & IN/ALL/ANY/SOME subquery");
DBUG_VOID_RETURN;
}
// no sense in ORDER BY without LIMIT
unit->global_parameters->order_list.empty();
Item_in_optimizer *optimizer; thd->where= "scalar IN/ALL/ANY subquery";
substitution= optimizer= new Item_in_optimizer(left_expr, this);
if (!optimizer)
DBUG_VOID_RETURN;
/* if (!substitution)
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((Item**)optimizer->get_cache(),
(char *)"<no matter>",
(char*)"<left expr>");
unit->dependent= 1;
for (SELECT_LEX * sl= unit->first_select(); sl; sl= sl->next_select())
{ {
if (sl->select_limit != HA_POS_ERROR) //first call for this unit
SELECT_LEX_UNIT *unit= select_lex->master_unit();
substitution= optimizer= new Item_in_optimizer(left_expr, this);
SELECT_LEX_NODE *current= thd->lex.current_select, *up;
thd->lex.current_select= up= current->return_after_parsing();
//optimizer never use Item **ref => we can pass 0 as parameter
if (!optimizer || optimizer->fix_left(thd, up->get_table_list(), 0))
{ {
my_error(ER_NOT_SUPPORTED_YET, MYF(0), thd->lex.current_select= current;
"LIMIT & IN/ALL/ANY/SOME subquery"); DBUG_RETURN(ERROR);
DBUG_VOID_RETURN;
} }
thd->lex.current_select= current;
sl->dependent= 1; /*
Item *item; As far as Item_ref_in_optimizer do not substitude itself on fix_fields
if (sl->item_list.elements > 1) we can use same item for all selects.
{ */
my_error(ER_CARDINALITY_COL, MYF(0), 1); expr= new Item_ref((Item**)optimizer->get_cache(),
DBUG_VOID_RETURN; (char *)"<no matter>",
} (char *)"<left expr>");
else
item= (Item*) sl->item_list.pop();
sl->order_list.empty(); // no sense in ORDER BY without LIMIT unit->dependent= 1;
}
if (sl->having || sl->with_sum_func || sl->group_list.elements) select_lex->dependent= 1;
Item *item;
if (select_lex->item_list.elements > 1)
{
my_error(ER_CARDINALITY_COL, MYF(0), 1);
DBUG_RETURN(ERROR);
}
else
item= (Item*) select_lex->item_list.head();
if (join->having || select_lex->with_sum_func ||
select_lex->group_list.elements)
{
item= (*func)(expr,
new Item_ref_null_helper(this,
select_lex->ref_pointer_array,
(char *)"<ref>",
this->full_name()));
join->having= and_items(join->having, item);
select_lex->having_fix_field= 1;
if (join->having->fix_fields(thd, join->tables_list, &join->having))
{ {
sl->item_list.push_back(item); select_lex->having_fix_field= 0;
setup_ref_array(thd, &sl->ref_pointer_array, DBUG_RETURN(ERROR);
1 + sl->select_items +
sl->order_list.elements + sl->group_list.elements);
// To prevent crash on Item_ref_null_helper destruction in case of error
sl->ref_pointer_array[0]= 0;
item= (*func)(expr, new Item_ref_null_helper(this,
sl->ref_pointer_array,
(char *)"<ref>",
this->full_name()));
sl->having= and_items(sl->having, item);
} }
else select_lex->having_fix_field= 0;
}
else
{
select_lex->item_list.empty();
select_lex->item_list.push_back(new Item_int("Not_used",
(longlong) 1, 21));
select_lex->ref_pointer_array[0]= select_lex->item_list.head();
if (select_lex->table_list.elements)
{ {
sl->item_list.empty(); Item *having= item, *isnull= item;
sl->item_list.push_back(new Item_int("Not_used", (longlong) 1, 21)); if (item->type() == Item::FIELD_ITEM &&
if (sl->table_list.elements) ((Item_field*) item)->field_name[0] == '*')
{ {
Item *having= item, *isnull= item; Item_asterisk_remover *remover;
if (item->type() == Item::FIELD_ITEM && item= remover= new Item_asterisk_remover(this, item,
((Item_field*) item)->field_name[0] == '*') (char *)"<no matter>",
(char *)"<result>");
if (!abort_on_null)
{ {
Item_asterisk_remover *remover;
item= remover= new Item_asterisk_remover(this, item,
(char*)"<no matter>",
(char*)"<result>");
having= having=
new Item_is_not_null_test(this, new Item_is_not_null_test(this,
new Item_ref(remover->storage(), new Item_ref(remover->storage(),
(char*)"<no matter>", (char *)"<no matter>",
(char*)"<null test>")); (char *)"<null test>"));
isnull= isnull=
new Item_is_not_null_test(this, new Item_is_not_null_test(this,
new Item_ref(remover->storage(), new Item_ref(remover->storage(),
(char*)"<no matter>", (char *)"<no matter>",
(char*)"<null test>")); (char *)"<null test>"));
} }
having= new Item_is_not_null_test(this, having);
sl->having= (sl->having ?
new Item_cond_and(having, sl->having) :
having);
item= new Item_cond_or((*func)(expr, item),
new Item_func_isnull(isnull));
sl->where= and_items(sl->where, item);
} }
else item= (*func)(expr, item);
if (!abort_on_null)
{ {
if (item->type() == Item::FIELD_ITEM && having= new Item_is_not_null_test(this, having);
((Item_field*) item)->field_name[0] == '*') join->having= (join->having ?
new Item_cond_and(having, join->having) :
having);
select_lex->having_fix_field= 1;
if (join->having->fix_fields(thd, join->tables_list, &join->having))
{ {
my_error(ER_NO_TABLES_USED, MYF(0)); select_lex->having_fix_field= 0;
DBUG_VOID_RETURN; DBUG_RETURN(ERROR);
} }
if (unit->first_select()->next_select()) select_lex->having_fix_field= 0;
{ item= new Item_cond_or(item,
/* new Item_func_isnull(isnull));
It is in union => we should perform it. }
Item_asterisk_remover used only as wrapper to receine NULL value join->conds= and_items(join->conds, item);
*/ if (join->conds->fix_fields(thd, join->tables_list, &join->conds))
sl->having= (*func)(expr, DBUG_RETURN(ERROR);
}
else
{
if (item->type() == Item::FIELD_ITEM &&
((Item_field*) item)->field_name[0] == '*')
{
my_error(ER_NO_TABLES_USED, MYF(0));
DBUG_RETURN(ERROR);
}
if (select_lex->master_unit()->first_select()->next_select())
{
/*
It is in union => we should perform it.
Item_asterisk_remover used only as wrapper to receine NULL value
*/
join->having= (*func)(expr,
new Item_asterisk_remover(this, item, new Item_asterisk_remover(this, item,
(char *)"<no matter>", (char *)"<no matter>",
(char*)"<result>")); (char *)"<result>"));
select_lex->having_fix_field= 1;
if (join->having->fix_fields(thd, join->tables_list, &join->having))
{
select_lex->having_fix_field= 0;
DBUG_RETURN(ERROR);
} }
else select_lex->having_fix_field= 0;
}
else
{
// it is single select without tables => possible optimization
item= (*func)(left_expr, item);
// fix_field of item will be done in time of substituting
substitution= item;
have_to_be_excluded= 1;
if (thd->lex.describe)
{ {
// it is single select without tables => possible optimization char warn_buff[MYSQL_ERRMSG_SIZE];
item= (*func)(left_expr, item); sprintf(warn_buff, ER(ER_SELECT_REDUCED), select_lex->select_number);
substitution= item; push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
have_to_be_excluded= 1; ER_SELECT_REDUCED, warn_buff);
if (thd->lex.describe)
{
char warn_buff[MYSQL_ERRMSG_SIZE];
sprintf(warn_buff, ER(ER_SELECT_REDUCED), sl->select_number);
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_SELECT_REDUCED, warn_buff);
}
} }
DBUG_RETURN(REDUCE);
} }
} }
} }
DBUG_VOID_RETURN; DBUG_RETURN(OK);
} }
void Item_in_subselect::row_value_transformer(THD *thd, Item_subselect::trans_res
st_select_lex_unit *unit, Item_in_subselect::row_value_transformer(THD *thd,
JOIN *join,
Item *left_expr) Item *left_expr)
{ {
DBUG_ENTER("Item_in_subselect::row_value_transformer"); DBUG_ENTER("Item_in_subselect::row_value_transformer");
if (unit->global_parameters->select_limit !=
HA_POS_ERROR)
{
/*
Because we do the following (not exactly, following is just explenation)
transformation
SELECT * from t1 WHERE t1.a IN (SELECT t2.a FROM t2)
->
SELECT * from t1 WHERE EXISTS(SELECT 1 FROM t2 t1.a = t2.a LIMIT 1)
it's impossible to support limit in the sub select. thd->where= "row IN/ALL/ANY subquery";
*/
my_error(ER_NOT_SUPPORTED_YET, MYF(0),
"LIMIT & IN/ALL/ANY/SOME subquery");
DBUG_VOID_RETURN;
}
// no sense in ORDER BY without LIMIT
unit->global_parameters->order_list.empty();
Item_in_optimizer *optimizer; SELECT_LEX *select_lex= join->select_lex;
substitution= optimizer= new Item_in_optimizer(left_expr, this);
if (!optimizer)
DBUG_VOID_RETURN;
unit->dependent= 1; if (!substitution)
uint n= left_expr->cols();
if (optimizer->preallocate_row() || (*optimizer->get_cache())->allocate(n))
DBUG_VOID_RETURN;
for (SELECT_LEX * sl= unit->first_select(); sl; sl= sl->next_select())
{ {
if (sl->select_limit != HA_POS_ERROR) //first call for this unit
SELECT_LEX_UNIT *unit= select_lex->master_unit();
substitution= optimizer= new Item_in_optimizer(left_expr, this);
SELECT_LEX_NODE *current= thd->lex.current_select, *up;
thd->lex.current_select= up= current->return_after_parsing();
//optimizer never use Item **ref => we can pass 0 as parameter
if (!optimizer || optimizer->fix_left(thd, up->get_table_list(), 0))
{ {
my_error(ER_NOT_SUPPORTED_YET, MYF(0), thd->lex.current_select= current;
"LIMIT & IN/ALL/ANY/SOME subquery"); DBUG_RETURN(ERROR);
DBUG_VOID_RETURN;
} }
sl->order_list.empty(); // no sense in ORDER BY without LIMIT thd->lex.current_select= current;
unit->dependent= 1;
}
uint n= left_expr->cols();
sl->dependent= 1; select_lex->dependent= 1;
Item *item= 0; Item *item= 0;
List_iterator_fast<Item> li(sl->item_list); List_iterator_fast<Item> li(select_lex->item_list);
for (uint i= 0; i < n; i++) for (uint i= 0; i < n; i++)
{
Item *func=
new Item_ref_on_list_position(this, select_lex, i,
(char *) "<no matter>",
(char *) "<list ref>");
func=
Item_bool_func2::eq_creator(new Item_ref((*optimizer->get_cache())->
addr(i),
(char *)"<no matter>",
(char *)"<left expr>"),
func);
item= and_items(item, func);
}
if (join->having || select_lex->with_sum_func ||
select_lex->group_list.first ||
!select_lex->table_list.elements)
{
join->having= and_items(join->having, item);
select_lex->having_fix_field= 1;
if (join->having->fix_fields(thd, join->tables_list, &join->having))
{ {
Item *func= select_lex->having_fix_field= 0;
new Item_ref_on_list_position(this, sl, i, DBUG_RETURN(ERROR);
(char *) "<no matter>",
(char *) "<list ref>");
func=
Item_bool_func2::eq_creator(new Item_ref((*optimizer->get_cache())->
addr(i),
(char *)"<no matter>",
(char *)"<left expr>"),
func);
item= and_items(item, func);
} }
select_lex->having_fix_field= 0;
if (sl->having || sl->with_sum_func || sl->group_list.first ||
!sl->table_list.elements)
sl->having= and_items(sl->having, item);
else
sl->where= and_items(sl->where, item);
} }
DBUG_VOID_RETURN; else
{
join->conds= and_items(join->conds, item);
if (join->conds->fix_fields(thd, join->tables_list, &join->having))
DBUG_RETURN(ERROR);
}
DBUG_RETURN(OK);
} }
Item_subselect::trans_res
void Item_in_subselect::select_transformer(THD *thd, st_select_lex_unit *unit) Item_in_subselect::select_transformer(THD *thd, JOIN *join)
{ {
if (left_expr->cols() == 1) if (left_expr->cols() == 1)
single_value_transformer(thd, unit, left_expr, return single_value_transformer(thd, join, left_expr,
&Item_bool_func2::eq_creator); &Item_bool_func2::eq_creator);
else else
row_value_transformer(thd, unit, left_expr); return row_value_transformer(thd, join, left_expr);
} }
void Item_allany_subselect::select_transformer(THD *thd, Item_subselect::trans_res
st_select_lex_unit *unit) Item_allany_subselect::select_transformer(THD *thd,
JOIN *join)
{ {
single_value_transformer(thd, unit, left_expr, func); return single_value_transformer(thd, join, left_expr, func);
} }
subselect_single_select_engine::subselect_single_select_engine(THD *thd, subselect_single_select_engine::subselect_single_select_engine(THD *thd,
......
...@@ -48,6 +48,8 @@ class Item_subselect :public Item_result_field ...@@ -48,6 +48,8 @@ class Item_subselect :public Item_result_field
bool have_to_be_excluded; bool have_to_be_excluded;
public: public:
enum trans_res {OK, REDUCE, ERROR};
Item_subselect(); Item_subselect();
Item_subselect(Item_subselect *item) Item_subselect(Item_subselect *item)
{ {
...@@ -73,7 +75,7 @@ class Item_subselect :public Item_result_field ...@@ -73,7 +75,7 @@ class Item_subselect :public Item_result_field
{ {
null_value= 1; null_value= 1;
} }
virtual void select_transformer(THD *thd, st_select_lex_unit *unit); virtual trans_res select_transformer(THD *thd, JOIN *join);
bool assigned() { return value_assigned; } bool assigned() { return value_assigned; }
void assigned(bool a) { value_assigned= a; } void assigned(bool a) { value_assigned= a; }
enum Type type() const; enum Type type() const;
...@@ -86,6 +88,13 @@ class Item_subselect :public Item_result_field ...@@ -86,6 +88,13 @@ class Item_subselect :public Item_result_field
bool exec(); bool exec();
virtual void fix_length_and_dec(); virtual void fix_length_and_dec();
table_map used_tables() const; table_map used_tables() const;
void print(String *str)
{
if (name)
str->append(name);
else
str->append("-subselect-");
}
friend class select_subselect; friend class select_subselect;
friend class Item_in_optimizer; friend class Item_in_optimizer;
...@@ -108,7 +117,7 @@ class Item_singlerow_subselect :public Item_subselect ...@@ -108,7 +117,7 @@ class Item_singlerow_subselect :public Item_subselect
decimals= item->decimals; decimals= item->decimals;
} }
void reset(); void reset();
void select_transformer(THD *thd, st_select_lex_unit *unit); trans_res select_transformer(THD *thd, JOIN *join);
void store(uint i, Item* item); void store(uint i, Item* item);
double val(); double val();
longlong val_int (); longlong val_int ();
...@@ -164,25 +173,35 @@ class Item_in_subselect :public Item_exists_subselect ...@@ -164,25 +173,35 @@ class Item_in_subselect :public Item_exists_subselect
{ {
protected: protected:
Item * left_expr; Item * left_expr;
/*
expr & optinizer used in subselect rewriting to store Item for
all JOIN in UNION
*/
Item *expr;
Item_in_optimizer *optimizer;
bool was_null; bool was_null;
bool abort_on_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(), abort_on_null(0) {}
void reset() void reset()
{ {
value= 0; value= 0;
null_value= 0; null_value= 0;
was_null= 0; was_null= 0;
} }
virtual void select_transformer(THD *thd, st_select_lex_unit *unit); trans_res select_transformer(THD *thd, JOIN *join);
void single_value_transformer(THD *thd, st_select_lex_unit *unit, trans_res single_value_transformer(THD *thd, JOIN *join,
Item *left_expr, compare_func_creator func); Item *left_expr,
void row_value_transformer(THD *thd, st_select_lex_unit *unit, compare_func_creator func);
Item *left_expr); trans_res row_value_transformer(THD *thd, JOIN * join,
Item *left_expr);
longlong val_int(); longlong val_int();
double val(); double val();
String *val_str(String*); String *val_str(String*);
void top_level_item() { abort_on_null=1; }
bool test_limit(st_select_lex_unit *unit);
friend class Item_asterisk_remover; friend class Item_asterisk_remover;
friend class Item_ref_null_helper; friend class Item_ref_null_helper;
...@@ -199,7 +218,7 @@ class Item_allany_subselect :public Item_in_subselect ...@@ -199,7 +218,7 @@ class Item_allany_subselect :public Item_in_subselect
Item_allany_subselect(THD *thd, Item * left_expr, compare_func_creator f, Item_allany_subselect(THD *thd, Item * left_expr, compare_func_creator f,
st_select_lex *select_lex); st_select_lex *select_lex);
Item_allany_subselect(Item_allany_subselect *item); Item_allany_subselect(Item_allany_subselect *item);
virtual void select_transformer(THD *thd, st_select_lex_unit *unit); trans_res select_transformer(THD *thd, JOIN *join);
}; };
class subselect_engine: public Sql_alloc class subselect_engine: public Sql_alloc
......
...@@ -200,7 +200,8 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, ...@@ -200,7 +200,8 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
if (tables) if (tables)
{ {
for (TABLE_LIST *cursor= tables; cursor; cursor= cursor->next) for (TABLE_LIST *cursor= tables; cursor; cursor= cursor->next)
cursor->table_list->table=cursor->table; if (cursor->table_list)
cursor->table_list->table=cursor->table;
} }
} }
else else
......
...@@ -1310,11 +1310,13 @@ bool st_select_lex_unit::create_total_list_n_last_return(THD *thd, st_lex *lex, ...@@ -1310,11 +1310,13 @@ bool st_select_lex_unit::create_total_list_n_last_return(THD *thd, st_lex *lex,
return 1; return 1;
} }
*new_table_list= cursor; *new_table_list= cursor;
cursor->table_list= aux; //to be able mark this table as shared
new_table_list= &cursor->next; new_table_list= &cursor->next;
*new_table_list= 0; // end result list *new_table_list= 0; // end result list
} }
else else
aux->shared= 1; // Mark that it's used twice // Mark that it's used twice
cursor->table_list->shared= aux->shared= 1;
aux->table_list= cursor; aux->table_list= cursor;
} }
} }
...@@ -1411,6 +1413,7 @@ ulong st_select_lex::get_table_join_options() ...@@ -1411,6 +1413,7 @@ ulong st_select_lex::get_table_join_options()
} }
st_select_lex::st_select_lex(struct st_lex *lex) st_select_lex::st_select_lex(struct st_lex *lex)
:fake_select(0)
{ {
select_number= ++lex->thd->select_number; select_number= ++lex->thd->select_number;
init_query(); init_query();
......
...@@ -367,6 +367,8 @@ class st_select_lex: public st_select_lex_node ...@@ -367,6 +367,8 @@ class st_select_lex: public st_select_lex_node
before passing to handle_select) before passing to handle_select)
*/ */
bool insert_select; bool insert_select;
/* TRUE for fake select, which used in UNION processing */
bool fake_select;
void init_query(); void init_query();
void init_select(); void init_select();
...@@ -420,7 +422,7 @@ class st_select_lex: public st_select_lex_node ...@@ -420,7 +422,7 @@ class st_select_lex: public st_select_lex_node
friend void mysql_init_query(THD *thd); friend void mysql_init_query(THD *thd);
st_select_lex(struct st_lex *lex); st_select_lex(struct st_lex *lex);
st_select_lex() {} st_select_lex() :fake_select(0) {}
void make_empty_select(st_select_lex *last_select) void make_empty_select(st_select_lex *last_select)
{ {
select_number=INT_MAX; select_number=INT_MAX;
......
...@@ -150,7 +150,8 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex) ...@@ -150,7 +150,8 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex)
{ {
if (cursor->do_redirect) if (cursor->do_redirect)
{ {
cursor->table= ((TABLE_LIST*) cursor->table)->table; //Sinisa TODO: there are function for this purpose: fix_tables_pointers
cursor->table= cursor->table_list->table;
cursor->do_redirect= 0; cursor->do_redirect= 0;
} }
} }
......
...@@ -200,7 +200,8 @@ void relink_tables(SELECT_LEX *select_lex) ...@@ -200,7 +200,8 @@ void relink_tables(SELECT_LEX *select_lex)
for (TABLE_LIST *cursor= (TABLE_LIST *) select_lex->table_list.first; for (TABLE_LIST *cursor= (TABLE_LIST *) select_lex->table_list.first;
cursor; cursor;
cursor=cursor->next) cursor=cursor->next)
cursor->table= cursor->table_list->table; if (cursor->table_list)
cursor->table= cursor->table_list->table;
} }
...@@ -313,6 +314,19 @@ JOIN::prepare(Item ***rref_pointer_array, ...@@ -313,6 +314,19 @@ JOIN::prepare(Item ***rref_pointer_array,
having->split_sum_func(ref_pointer_array, all_fields); having->split_sum_func(ref_pointer_array, all_fields);
} }
// Is it subselect
{
Item_subselect *subselect;
if ((subselect= select_lex->master_unit()->item) &&
!select_lex->fake_select)
{
Item_subselect::trans_res res;
if ((res= subselect->select_transformer(thd, this)) !=
Item_subselect::OK)
DBUG_RETURN((res == Item_subselect::ERROR));
}
}
if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */ if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */
DBUG_RETURN(-1); DBUG_RETURN(-1);
......
...@@ -188,42 +188,33 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result, ...@@ -188,42 +188,33 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
union_result->not_describe=1; union_result->not_describe=1;
union_result->tmp_table_param=tmp_table_param; union_result->tmp_table_param=tmp_table_param;
/* for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
The following piece of code is placed here solely for the purpose of
getting correct results with EXPLAIN when UNION is withing a sub-select
or derived table ...
*/
if (thd->lex.describe)
{ {
for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select()) JOIN *join= new JOIN(thd, sl->item_list,
{ sl->options | thd->options | SELECT_NO_UNLOCK,
JOIN *join= new JOIN(thd, sl->item_list, union_result);
sl->options | thd->options | SELECT_NO_UNLOCK, thd->lex.current_select= sl;
union_result); offset_limit_cnt= sl->offset_limit;
thd->lex.current_select= sl; select_limit_cnt= sl->select_limit+sl->offset_limit;
offset_limit_cnt= sl->offset_limit; if (select_limit_cnt < sl->select_limit)
select_limit_cnt= sl->select_limit+sl->offset_limit; select_limit_cnt= HA_POS_ERROR; // no limit
if (select_limit_cnt < sl->select_limit) if (select_limit_cnt == HA_POS_ERROR)
select_limit_cnt= HA_POS_ERROR; // no limit sl->options&= ~OPTION_FOUND_ROWS;
if (select_limit_cnt == HA_POS_ERROR)
sl->options&= ~OPTION_FOUND_ROWS; res= join->prepare(&sl->ref_pointer_array,
(TABLE_LIST*) sl->table_list.first, sl->with_wild,
res= join->prepare(&sl->ref_pointer_array, sl->where,
(TABLE_LIST*) sl->table_list.first, sl->with_wild, ((sl->braces) ? sl->order_list.elements : 0) +
sl->where, sl->group_list.elements,
((sl->braces) ? sl->order_list.elements : 0) + (sl->braces) ?
sl->group_list.elements, (ORDER *)sl->order_list.first : (ORDER *) 0,
(sl->braces) ? (ORDER*) sl->group_list.first,
(ORDER *)sl->order_list.first : (ORDER *) 0, sl->having,
(ORDER*) sl->group_list.first, (ORDER*) NULL,
sl->having, sl, this, t_and_f);
(ORDER*) NULL, t_and_f= 0;
sl, this, t_and_f); if (res || thd->is_fatal_error)
t_and_f= 0; goto err;
if (res || thd->is_fatal_error)
goto err;
}
} }
item_list.empty(); item_list.empty();
...@@ -268,14 +259,12 @@ int st_select_lex_unit::exec() ...@@ -268,14 +259,12 @@ int st_select_lex_unit::exec()
} }
for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select()) for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
{ {
thd->lex.current_select= sl;
if (optimized) if (optimized)
res= sl->join->reinit(); res= sl->join->reinit();
else else
{ {
JOIN *join= new JOIN(thd, sl->item_list,
sl->options | thd->options | SELECT_NO_UNLOCK,
union_result);
thd->lex.current_select= sl;
offset_limit_cnt= sl->offset_limit; offset_limit_cnt= sl->offset_limit;
select_limit_cnt= sl->select_limit+sl->offset_limit; select_limit_cnt= sl->select_limit+sl->offset_limit;
if (select_limit_cnt < sl->select_limit) if (select_limit_cnt < sl->select_limit)
...@@ -283,22 +272,36 @@ int st_select_lex_unit::exec() ...@@ -283,22 +272,36 @@ int st_select_lex_unit::exec()
if (select_limit_cnt == HA_POS_ERROR) if (select_limit_cnt == HA_POS_ERROR)
sl->options&= ~OPTION_FOUND_ROWS; sl->options&= ~OPTION_FOUND_ROWS;
res= join->prepare(&sl->ref_pointer_array, /*
(TABLE_LIST*) sl->table_list.first, sl->with_wild, As far as union share table space we should reassign table map,
sl->where, which can be spoiled by 'prepare' of JOIN of other UNION parts
((sl->braces) ? sl->order_list.elements : 0) + if it use same tables
sl->group_list.elements, */
(sl->braces) ? uint tablenr=0;
(ORDER *)sl->order_list.first : (ORDER *) 0, for (TABLE_LIST *table_list= (TABLE_LIST*) sl->table_list.first;
(ORDER*) sl->group_list.first, table_list;
sl->having, table_list= table_list->next, tablenr++)
(ORDER*) NULL,
sl, this, t_and_f);
t_and_f=0;
if (res | thd->is_fatal_error)
{ {
thd->lex.current_select= lex_select_save; if (table_list->shared)
DBUG_RETURN(res); {
/*
review notes: Check it carefully. I still can't understand
why I should not touch table->used_keys. For my point of
view we should do here same procedura as it was done by
setup_table
*/
DBUG_PRINT("SUBS", ("shared %s", table_list->real_name));
TABLE *table= table_list->table;
table->used_fields=0;
table->const_table=0;
table->outer_join=table->null_row=0;
table->status=STATUS_NO_RECORD;
table->keys_in_use_for_query= table->keys_in_use;
table->maybe_null=test(table->outer_join=table_list->outer_join);
table->tablenr=tablenr;
table->map= (table_map) 1 << tablenr;
table->force_index= table_list->force_index;
}
} }
res= sl->join->optimize(); res= sl->join->optimize();
} }
...@@ -334,6 +337,7 @@ int st_select_lex_unit::exec() ...@@ -334,6 +337,7 @@ int st_select_lex_unit::exec()
if (!thd->is_fatal_error) // Check if EOM if (!thd->is_fatal_error) // Check if EOM
{ {
SELECT_LEX *fake_select = new SELECT_LEX(&thd->lex); SELECT_LEX *fake_select = new SELECT_LEX(&thd->lex);
fake_select->fake_select= 1;
offset_limit_cnt= (select_cursor->braces ? offset_limit_cnt= (select_cursor->braces ?
global_parameters->offset_limit : 0); global_parameters->offset_limit : 0);
select_limit_cnt= (select_cursor->braces ? select_limit_cnt= (select_cursor->braces ?
......
...@@ -5149,7 +5149,9 @@ subselect_start: ...@@ -5149,7 +5149,9 @@ subselect_start:
{ {
LEX *lex=Lex; LEX *lex=Lex;
if (((int)lex->sql_command >= (int)SQLCOM_HA_OPEN && if (((int)lex->sql_command >= (int)SQLCOM_HA_OPEN &&
lex->sql_command <= (int)SQLCOM_HA_READ) || lex->sql_command == (int)SQLCOM_KILL) { lex->sql_command <= (int)SQLCOM_HA_READ) ||
lex->sql_command == (int)SQLCOM_KILL)
{
send_error(lex->thd, ER_SYNTAX_ERROR); send_error(lex->thd, ER_SYNTAX_ERROR);
YYABORT; YYABORT;
} }
......
...@@ -163,15 +163,8 @@ typedef struct st_table_list ...@@ -163,15 +163,8 @@ typedef struct st_table_list
struct st_table_list *natural_join; /* natural join on this table*/ struct st_table_list *natural_join; /* natural join on this table*/
/* ... join ... USE INDEX ... IGNORE INDEX */ /* ... join ... USE INDEX ... IGNORE INDEX */
List<String> *use_index, *ignore_index; List<String> *use_index, *ignore_index;
/* TABLE *table; /* opened table */
Usually hold reference on opened table, but may hold reference st_table_list *table_list; /* pointer to node of list of all tables */
to node of complete list of tables used in UNION & subselect.
*/
union
{
TABLE *table; /* opened table */
st_table_list *table_list; /* pointer to node of list of all tables */
};
class st_select_lex_unit *derived; /* SELECT_LEX_UNIT of derived table */ class st_select_lex_unit *derived; /* SELECT_LEX_UNIT of derived table */
GRANT_INFO grant; GRANT_INFO grant;
thr_lock_type lock_type; thr_lock_type lock_type;
......
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