Commit 35faf872 authored by bell@sanja.is.com.ua's avatar bell@sanja.is.com.ua

added depended subselect processing

parent 17e839d4
...@@ -6,6 +6,14 @@ create table t4 (a int, b int); ...@@ -6,6 +6,14 @@ create table t4 (a int, b int);
insert into t1 values (2); insert into t1 values (2);
insert into t2 values (1,7),(2,7); insert into t2 values (1,7),(2,7);
insert into t4 values (4,8),(3,8),(5,9); insert into t4 values (4,8),(3,8),(5,9);
select (select a from t1 where t1.a=t2.a), a from t2;
(select a from t1 where t1.a=t2.a) a
NULL 1
2 2
select (select a from t1 where t1.a=t2.b), a from t2;
(select a from t1 where t1.a=t2.b) a
NULL 1
NULL 2
select (select a from t1), a from t2; select (select a from t1), a from t2;
(select a from t1) a (select a from t1) a
2 1 2 1
......
...@@ -8,6 +8,8 @@ create table t4 (a int, b int); ...@@ -8,6 +8,8 @@ create table t4 (a int, b int);
insert into t1 values (2); insert into t1 values (2);
insert into t2 values (1,7),(2,7); insert into t2 values (1,7),(2,7);
insert into t4 values (4,8),(3,8),(5,9); insert into t4 values (4,8),(3,8),(5,9);
select (select a from t1 where t1.a=t2.a), a from t2;
select (select a from t1 where t1.a=t2.b), a from t2;
select (select a from t1), a from t2; select (select a from t1), a from t2;
select (select a from t3), a from t2; select (select a from t3), a from t2;
select * from t2 where t2.a=(select a from t1); select * from t2 where t2.a=(select a from t1);
......
...@@ -320,7 +320,34 @@ bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables) ...@@ -320,7 +320,34 @@ bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables)
{ {
Field *tmp; Field *tmp;
if (!(tmp=find_field_in_tables(thd,this,tables))) if (!(tmp=find_field_in_tables(thd,this,tables)))
return 1; {
/*
We can't find table field in table list of current select,
consequently we have to find it in outer subselect(s).
We can't join lists of outer & current select, because of scope
of view rules. For example if both tables (outer & current) have
field 'field' it is not mistake to refer to this field without
mention of table name, but if we join tables in one list it will
cause error ER_NON_UNIQ_ERROR in find_field_in_tables.
*/
for (SELECT_LEX *sl= thd->lex.select->outer_select();
sl && !tmp;
sl= sl->outer_select())
tmp=find_field_in_tables(thd, this,
(TABLE_LIST*)sl->table_list.first);
if (!tmp)
return 1;
else
if( !thd->lex.select->depended )
{
thd->lex.select->depended= 1; //Select is depended of outer select(s)
//Tables will be reopened many times
for (TABLE_LIST *tbl= (TABLE_LIST*)thd->lex.select->table_list.first;
tbl;
tbl= tbl->next)
tbl->shared= 1;
}
}
set_field(tmp); set_field(tmp);
} }
else if (thd && thd->set_query_id && field->query_id != thd->query_id) else if (thd && thd->set_query_id && field->query_id != thd->query_id)
......
...@@ -36,7 +36,7 @@ SUBSELECT TODO: ...@@ -36,7 +36,7 @@ SUBSELECT TODO:
#include "sql_select.h" #include "sql_select.h"
Item_subselect::Item_subselect(THD *thd, st_select_lex *select_lex): Item_subselect::Item_subselect(THD *thd, st_select_lex *select_lex):
executed(0) executed(0), optimized(0), error(0)
{ {
DBUG_ENTER("Item_subselect::Item_subselect"); DBUG_ENTER("Item_subselect::Item_subselect");
DBUG_PRINT("subs", ("select_lex 0x%xl", (long) select_lex)); DBUG_PRINT("subs", ("select_lex 0x%xl", (long) select_lex));
...@@ -48,7 +48,7 @@ Item_subselect::Item_subselect(THD *thd, st_select_lex *select_lex): ...@@ -48,7 +48,7 @@ Item_subselect::Item_subselect(THD *thd, st_select_lex *select_lex):
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)
*/ */
assign_null(); assign_null();
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -110,17 +110,31 @@ bool Item_subselect::fix_fields(THD *thd,TABLE_LIST *tables) ...@@ -110,17 +110,31 @@ bool Item_subselect::fix_fields(THD *thd,TABLE_LIST *tables)
(ORDER*) 0, select_lex, (ORDER*) 0, select_lex,
(SELECT_LEX_UNIT*) select_lex->master)) (SELECT_LEX_UNIT*) select_lex->master))
return 1; return 1;
if (join->optimize())
{
executed= 1;
return 1;
}
thd->lex.select= save_select; thd->lex.select= save_select;
return 0; return 0;
} }
int Item_subselect::exec() int Item_subselect::exec()
{ {
if (!optimized)
{
optimized=1;
if (join->optimize())
{
executed= 1;
return (join->error?join->error:1);
}
}
if (join->select_lex->depended && executed)
{
if (join->reinit())
{
error= 1;
return 1;
}
assign_null();
executed= 0;
}
if (!executed) if (!executed)
{ {
SELECT_LEX *save_select= join->thd->lex.select; SELECT_LEX *save_select= join->thd->lex.select;
......
...@@ -29,9 +29,11 @@ class select_subselect; ...@@ -29,9 +29,11 @@ class select_subselect;
class Item_subselect :public Item class Item_subselect :public Item
{ {
protected: protected:
my_bool executed; /* simple subselect is executed */
longlong int_value; longlong int_value;
double real_value; double real_value;
my_bool executed; /* simple subselect is executed */
my_bool optimized; /* simple subselect is optimized */
my_bool error; /* error in query */
enum Item_result res_type; enum Item_result res_type;
int exec(); int exec();
...@@ -62,6 +64,7 @@ class Item_subselect :public Item ...@@ -62,6 +64,7 @@ class Item_subselect :public Item
join= item->join; join= item->join;
result= item->result; result= item->result;
name= item->name; name= item->name;
error= item->error;
} }
enum Type type() const; enum Type type() const;
double val (); double val ();
......
...@@ -931,6 +931,7 @@ void st_select_lex::init_select() ...@@ -931,6 +931,7 @@ void st_select_lex::init_select()
use_index.empty(); use_index.empty();
ftfunc_list.empty(); ftfunc_list.empty();
linkage=UNSPECIFIED_TYPE; linkage=UNSPECIFIED_TYPE;
depended= 0;
} }
/* /*
......
...@@ -208,6 +208,7 @@ struct st_select_lex_node { ...@@ -208,6 +208,7 @@ struct st_select_lex_node {
SELECT_LEXs SELECT_LEXs
*/ */
struct st_lex; struct st_lex;
struct st_select_lex;
struct st_select_lex_unit: public st_select_lex_node { struct st_select_lex_unit: public st_select_lex_node {
/* /*
Pointer to 'last' select or pointer to unit where stored Pointer to 'last' select or pointer to unit where stored
...@@ -218,6 +219,8 @@ struct st_select_lex_unit: public st_select_lex_node { ...@@ -218,6 +219,8 @@ struct st_select_lex_unit: public st_select_lex_node {
ha_rows select_limit_cnt, offset_limit_cnt; ha_rows select_limit_cnt, offset_limit_cnt;
void init_query(); void init_query();
bool create_total_list(THD *thd, st_lex *lex, TABLE_LIST **result); bool create_total_list(THD *thd, st_lex *lex, TABLE_LIST **result);
st_select_lex* first_select() { return (st_select_lex*) slave; }
st_select_lex_unit* next_unit() { return (st_select_lex_unit*) next; }
private: private:
bool create_total_list_n_last_return(THD *thd, st_lex *lex, bool create_total_list_n_last_return(THD *thd, st_lex *lex,
TABLE_LIST ***result); TABLE_LIST ***result);
...@@ -240,9 +243,12 @@ struct st_select_lex: public st_select_lex_node { ...@@ -240,9 +243,12 @@ struct st_select_lex: public st_select_lex_node {
List<Item_func_match> ftfunc_list; List<Item_func_match> ftfunc_list;
uint in_sum_expr, sort_default; uint in_sum_expr, sort_default;
bool create_refs, bool create_refs,
braces; /* SELECT ... UNION (SELECT ... ) <- this braces */ braces, /* SELECT ... UNION (SELECT ... ) <- this braces */
depended; /* depended from outer select subselect */
void init_query(); void init_query();
void init_select(); void init_select();
st_select_lex* outer_select() { return (st_select_lex*) master->master; }
st_select_lex* next_select() { return (st_select_lex*) next; }
}; };
typedef struct st_select_lex SELECT_LEX; typedef struct st_select_lex SELECT_LEX;
......
...@@ -213,7 +213,8 @@ JOIN::prepare(TABLE_LIST *tables_init, ...@@ -213,7 +213,8 @@ JOIN::prepare(TABLE_LIST *tables_init,
proc_param= proc_param_init; proc_param= proc_param_init;
tables_list= tables_init; tables_list= tables_init;
select_lex= select; select_lex= select;
union_part= (unit->first_select()->next_select() != 0);
/* Check that all tables, fields, conds and order are ok */ /* Check that all tables, fields, conds and order are ok */
if (setup_tables(tables_list) || if (setup_tables(tables_list) ||
...@@ -334,7 +335,6 @@ int ...@@ -334,7 +335,6 @@ int
JOIN::optimize() JOIN::optimize()
{ {
DBUG_ENTER("JOIN::optimize"); DBUG_ENTER("JOIN::optimize");
SELECT_LEX *select_lex = &(thd->lex.select_lex);
#ifdef HAVE_REF_TO_FIELDS // Not done yet #ifdef HAVE_REF_TO_FIELDS // Not done yet
/* Add HAVING to WHERE if possible */ /* Add HAVING to WHERE if possible */
...@@ -380,7 +380,7 @@ JOIN::optimize() ...@@ -380,7 +380,7 @@ JOIN::optimize()
} }
if (select_options & SELECT_DESCRIBE) if (select_options & SELECT_DESCRIBE)
{ {
if (select_lex->next) if (union_part)
select_describe(this, false, false, false, select_describe(this, false, false, false,
"Select tables optimized away"); "Select tables optimized away");
else else
...@@ -406,6 +406,17 @@ JOIN::optimize() ...@@ -406,6 +406,17 @@ JOIN::optimize()
if (make_join_statistics(this, tables_list, conds, &keyuse) || if (make_join_statistics(this, tables_list, conds, &keyuse) ||
thd->fatal_error) thd->fatal_error)
DBUG_RETURN(-1); DBUG_RETURN(-1);
if (select_lex->depended)
{
/*
Just remove all const-table optimization in case of depended query
TODO: optimize
*/
const_table_map= 0;
const_tables= 0;
found_const_table_map= 0;
}
thd->proc_info= "preparing"; thd->proc_info= "preparing";
result->initialize_tables(this); result->initialize_tables(this);
if (const_table_map != found_const_table_map && if (const_table_map != found_const_table_map &&
...@@ -576,7 +587,7 @@ JOIN::optimize() ...@@ -576,7 +587,7 @@ JOIN::optimize()
} }
/* /*
global uptimisation (with subselect) must be here (TODO) Global optimization (with subselect) must be here (TODO)
*/ */
int int
...@@ -585,8 +596,25 @@ JOIN::global_optimize() ...@@ -585,8 +596,25 @@ JOIN::global_optimize()
return 0; return 0;
} }
int
JOIN::reinit()
{
DBUG_ENTER("JOIN::reinit");
//TODO move to unit reinit
unit->offset_limit_cnt =select_lex->offset_limit;
unit->select_limit_cnt =select_lex->select_limit+select_lex->offset_limit;
if (unit->select_limit_cnt < select_lex->select_limit)
unit->select_limit_cnt= HA_POS_ERROR; // no limit
if (unit->select_limit_cnt == HA_POS_ERROR)
select_lex->options&= ~OPTION_FOUND_ROWS;
if (setup_tables(tables_list))
DBUG_RETURN(1);
DBUG_RETURN(0);
}
/* /*
exec select Exec select
*/ */
void void
JOIN::exec() JOIN::exec()
...@@ -600,7 +628,7 @@ JOIN::exec() ...@@ -600,7 +628,7 @@ JOIN::exec()
error=0; error=0;
if (select_options & SELECT_DESCRIBE) if (select_options & SELECT_DESCRIBE)
{ {
if (select_lex->next) if (union_part)
select_describe(this, false, false, false, "No tables used"); select_describe(this, false, false, false, "No tables used");
else else
describe_info(thd, "No tables used"); describe_info(thd, "No tables used");
...@@ -627,7 +655,7 @@ JOIN::exec() ...@@ -627,7 +655,7 @@ JOIN::exec()
if (zero_result_cause) if (zero_result_cause)
{ {
if (select_options & SELECT_DESCRIBE && select_lex->next) if (select_options & SELECT_DESCRIBE && union_part)
select_describe(this, false, false, false, zero_result_cause); select_describe(this, false, false, false, zero_result_cause);
else else
error=return_zero_rows(result, tables_list, fields_list, error=return_zero_rows(result, tables_list, fields_list,
......
...@@ -196,6 +196,8 @@ class JOIN :public Sql_alloc{ ...@@ -196,6 +196,8 @@ class JOIN :public Sql_alloc{
my_bool test_function_query; // need to return select items 1 row my_bool test_function_query; // need to return select items 1 row
const char *zero_result_cause; // not 0 if exec must return zero result const char *zero_result_cause; // not 0 if exec must return zero result
my_bool union_part; // this subselect is part of union
JOIN(THD *thd, List<Item> &fields, JOIN(THD *thd, List<Item> &fields,
ulong select_options, select_result *result): ulong select_options, select_result *result):
...@@ -236,6 +238,7 @@ class JOIN :public Sql_alloc{ ...@@ -236,6 +238,7 @@ class JOIN :public Sql_alloc{
ORDER *proc_param, SELECT_LEX *select, SELECT_LEX_UNIT *unit); ORDER *proc_param, SELECT_LEX *select, SELECT_LEX_UNIT *unit);
int optimize(); int optimize();
int global_optimize(); int global_optimize();
int reinit();
void exec(); void exec();
int cleanup(THD *thd); int cleanup(THD *thd);
}; };
......
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