added depended subselect processing
This commit is contained in:
parent
17e839d453
commit
35faf872aa
@ -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);
|
|||||||
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);
|
||||||
|
29
sql/item.cc
29
sql/item.cc
@ -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:
|
|||||||
#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):
|
|||||||
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)
|
|||||||
(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;
|
|||||||
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 @@ public:
|
|||||||
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()
|
|||||||
use_index.empty();
|
use_index.empty();
|
||||||
ftfunc_list.empty();
|
ftfunc_list.empty();
|
||||||
linkage=UNSPECIFIED_TYPE;
|
linkage=UNSPECIFIED_TYPE;
|
||||||
|
depended= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -208,6 +208,7 @@ private:
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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,
|
|||||||
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
|
|||||||
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()
|
|||||||
}
|
}
|
||||||
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()
|
|||||||
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()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
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()
|
|||||||
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()
|
|||||||
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()
|
|||||||
|
|
||||||
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{
|
|||||||
|
|
||||||
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{
|
|||||||
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);
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user