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);
insert into t1 values (2);
insert into t2 values (1,7),(2,7);
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 a from t1) a
2 1
......
......@@ -8,6 +8,8 @@ create table t4 (a int, b int);
insert into t1 values (2);
insert into t2 values (1,7),(2,7);
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 t3), a from t2;
select * from t2 where t2.a=(select a from t1);
......
......@@ -320,7 +320,34 @@ bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables)
{
Field *tmp;
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);
}
else if (thd && thd->set_query_id && field->query_id != thd->query_id)
......
......@@ -36,7 +36,7 @@ SUBSELECT TODO:
#include "sql_select.h"
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_PRINT("subs", ("select_lex 0x%xl", (long) 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
(i.e. some rows will be found returned)
*/
assign_null();
assign_null();
DBUG_VOID_RETURN;
}
......@@ -110,17 +110,31 @@ bool Item_subselect::fix_fields(THD *thd,TABLE_LIST *tables)
(ORDER*) 0, select_lex,
(SELECT_LEX_UNIT*) select_lex->master))
return 1;
if (join->optimize())
{
executed= 1;
return 1;
}
thd->lex.select= save_select;
return 0;
}
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)
{
SELECT_LEX *save_select= join->thd->lex.select;
......
......@@ -29,9 +29,11 @@ class select_subselect;
class Item_subselect :public Item
{
protected:
my_bool executed; /* simple subselect is executed */
longlong int_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;
int exec();
......@@ -62,6 +64,7 @@ class Item_subselect :public Item
join= item->join;
result= item->result;
name= item->name;
error= item->error;
}
enum Type type() const;
double val ();
......
......@@ -931,6 +931,7 @@ void st_select_lex::init_select()
use_index.empty();
ftfunc_list.empty();
linkage=UNSPECIFIED_TYPE;
depended= 0;
}
/*
......
......@@ -208,6 +208,7 @@ struct st_select_lex_node {
SELECT_LEXs
*/
struct st_lex;
struct st_select_lex;
struct st_select_lex_unit: public st_select_lex_node {
/*
Pointer to 'last' select or pointer to unit where stored
......@@ -218,6 +219,8 @@ struct st_select_lex_unit: public st_select_lex_node {
ha_rows select_limit_cnt, offset_limit_cnt;
void init_query();
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:
bool create_total_list_n_last_return(THD *thd, st_lex *lex,
TABLE_LIST ***result);
......@@ -240,9 +243,12 @@ struct st_select_lex: public st_select_lex_node {
List<Item_func_match> ftfunc_list;
uint in_sum_expr, sort_default;
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_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;
......
......@@ -213,7 +213,8 @@ JOIN::prepare(TABLE_LIST *tables_init,
proc_param= proc_param_init;
tables_list= tables_init;
select_lex= select;
union_part= (unit->first_select()->next_select() != 0);
/* Check that all tables, fields, conds and order are ok */
if (setup_tables(tables_list) ||
......@@ -334,7 +335,6 @@ int
JOIN::optimize()
{
DBUG_ENTER("JOIN::optimize");
SELECT_LEX *select_lex = &(thd->lex.select_lex);
#ifdef HAVE_REF_TO_FIELDS // Not done yet
/* Add HAVING to WHERE if possible */
......@@ -380,7 +380,7 @@ JOIN::optimize()
}
if (select_options & SELECT_DESCRIBE)
{
if (select_lex->next)
if (union_part)
select_describe(this, false, false, false,
"Select tables optimized away");
else
......@@ -406,6 +406,17 @@ JOIN::optimize()
if (make_join_statistics(this, tables_list, conds, &keyuse) ||
thd->fatal_error)
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";
result->initialize_tables(this);
if (const_table_map != found_const_table_map &&
......@@ -576,7 +587,7 @@ JOIN::optimize()
}
/*
global uptimisation (with subselect) must be here (TODO)
Global optimization (with subselect) must be here (TODO)
*/
int
......@@ -585,8 +596,25 @@ JOIN::global_optimize()
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
JOIN::exec()
......@@ -600,7 +628,7 @@ JOIN::exec()
error=0;
if (select_options & SELECT_DESCRIBE)
{
if (select_lex->next)
if (union_part)
select_describe(this, false, false, false, "No tables used");
else
describe_info(thd, "No tables used");
......@@ -627,7 +655,7 @@ JOIN::exec()
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);
else
error=return_zero_rows(result, tables_list, fields_list,
......
......@@ -196,6 +196,8 @@ class JOIN :public Sql_alloc{
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
my_bool union_part; // this subselect is part of union
JOIN(THD *thd, List<Item> &fields,
ulong select_options, select_result *result):
......@@ -236,6 +238,7 @@ class JOIN :public Sql_alloc{
ORDER *proc_param, SELECT_LEX *select, SELECT_LEX_UNIT *unit);
int optimize();
int global_optimize();
int reinit();
void exec();
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