mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
Post review changes for the optimization of IN predicates into IN subqueries.
This commit is contained in:
@ -6,29 +6,26 @@ create table t2 (a int, b int, c int);
|
||||
insert into t2
|
||||
values (1,2,3), (5,1,2), (4,3,7),
|
||||
(8,9,0), (10,7,1), (5,5,1);
|
||||
create table t3 (a int, b varchar(16), index idx(a));
|
||||
insert into t3 values
|
||||
(1, "abc"), (3, "egh"), (8, "axxx"), (10, "abc"),
|
||||
(2, "ccw"), (8, "wqqe"), (7, "au"), (9, "waa"),
|
||||
(3, "rass"), (9, "ert"), (9, "lok"), (8, "aww"),
|
||||
(1, "todd"), (3, "rew"), (8, "aww"), (3, "sw"),
|
||||
(11, "llk"), (7, "rbw"), (1, "sm"), (2, "jyp"),
|
||||
(4, "yq"), (5, "pled"), (12, "ligin"), (12, "toww"),
|
||||
(6, "mxm"), (15, "wanone"), (9, "sunqq"), (2, "abe");
|
||||
# optimization is not used
|
||||
select * from t1 where a in (1,2);
|
||||
a b
|
||||
1 2
|
||||
1 1
|
||||
2 5
|
||||
explain select * from t1 where a in (1,2);
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 6 Using where
|
||||
explain format=json select * from t1 where a in (1,2);
|
||||
EXPLAIN
|
||||
{
|
||||
"query_block": {
|
||||
"select_id": 1,
|
||||
"table": {
|
||||
"table_name": "t1",
|
||||
"access_type": "ALL",
|
||||
"rows": 6,
|
||||
"filtered": 100,
|
||||
"attached_condition": "t1.a in (1,2)"
|
||||
}
|
||||
}
|
||||
}
|
||||
explain extended select * from t1 where a in (1,2);
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 6 100.00 Using where
|
||||
Warnings:
|
||||
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where `test`.`t1`.`a` in (1,2)
|
||||
# set minimum number of values in VALUEs list when optimization works to 2
|
||||
set @@in_subquery_conversion_threshold= 2;
|
||||
# single IN-predicate in WHERE-part
|
||||
@ -481,5 +478,68 @@ a b
|
||||
1 1
|
||||
2 5
|
||||
deallocate prepare stmt;
|
||||
drop table t1, t2;
|
||||
# use inside out access from tvc rows
|
||||
set @@in_subquery_conversion_threshold= default;
|
||||
select * from t3 where a in (1,4,10);
|
||||
a b
|
||||
1 abc
|
||||
1 todd
|
||||
1 sm
|
||||
4 yq
|
||||
10 abc
|
||||
explain extended select * from t3 where a in (1,4,10);
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 SIMPLE t3 range idx idx 5 NULL 5 100.00 Using index condition
|
||||
Warnings:
|
||||
Note 1003 select `test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t3` where `test`.`t3`.`a` in (1,4,10)
|
||||
set @@in_subquery_conversion_threshold= 2;
|
||||
select * from t3 where a in (1,4,10);
|
||||
a b
|
||||
1 abc
|
||||
1 todd
|
||||
1 sm
|
||||
4 yq
|
||||
10 abc
|
||||
explain extended select * from t3 where a in (1,4,10);
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 2 100.00
|
||||
1 PRIMARY t3 ref idx idx 5 tvc_0.1 3 100.00
|
||||
2 MATERIALIZED <derived3> ALL NULL NULL NULL NULL 2 100.00
|
||||
3 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
|
||||
Warnings:
|
||||
Note 1003 /* select#1 */ select `test`.`t3`.`a` AS `a`,`test`.`t3`.`b` AS `b` from `test`.`t3` semi join ((values (1),(4),(10)) `tvc_0`) where `test`.`t3`.`a` = `tvc_0`.`1`
|
||||
# use vectors in IN predeicate
|
||||
set @@in_subquery_conversion_threshold= 4;
|
||||
select * from t1 where (a,b) in ((1,2),(3,4));
|
||||
a b
|
||||
1 2
|
||||
explain extended select * from t1 where (a,b) in ((1,2),(3,4));
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 2 100.00
|
||||
1 PRIMARY t1 ALL NULL NULL NULL NULL 6 100.00 Using where; Using join buffer (flat, BNL join)
|
||||
2 MATERIALIZED <derived3> ALL NULL NULL NULL NULL 2 100.00
|
||||
3 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
|
||||
Warnings:
|
||||
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` semi join ((values (1,2),(3,4)) `tvc_0`) where `test`.`t1`.`a` = `tvc_0`.`1` and `test`.`t1`.`b` = `tvc_0`.`2`
|
||||
set @@in_subquery_conversion_threshold= 2;
|
||||
# trasformation works for the one IN predicate and doesn't work for the other
|
||||
set @@in_subquery_conversion_threshold= 5;
|
||||
select * from t2
|
||||
where (a,b) in ((1,2),(8,9)) and
|
||||
(a,c) in ((1,3),(8,0),(5,1));
|
||||
a b c
|
||||
1 2 3
|
||||
8 9 0
|
||||
explain extended select * from t2
|
||||
where (a,b) in ((1,2),(8,9)) and
|
||||
(a,c) in ((1,3),(8,0),(5,1));
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 PRIMARY <subquery2> ALL distinct_key NULL NULL NULL 2 100.00
|
||||
1 PRIMARY t2 ALL NULL NULL NULL NULL 6 100.00 Using where; Using join buffer (flat, BNL join)
|
||||
2 MATERIALIZED <derived3> ALL NULL NULL NULL NULL 2 100.00
|
||||
3 DERIVED NULL NULL NULL NULL NULL NULL NULL NULL No tables used
|
||||
Warnings:
|
||||
Note 1003 /* select#1 */ select `test`.`t2`.`a` AS `a`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` semi join ((values (1,3),(8,0),(5,1)) `tvc_0`) where `test`.`t2`.`a` = `tvc_0`.`1` and `test`.`t2`.`c` = `tvc_0`.`3` and (`tvc_0`.`1`,`test`.`t2`.`b`) in (<cache>((1,2)),<cache>((8,9)))
|
||||
set @@in_subquery_conversion_threshold= 2;
|
||||
drop table t1, t2, t3;
|
||||
set @@in_subquery_conversion_threshold= default;
|
||||
|
@ -10,12 +10,21 @@ insert into t2
|
||||
values (1,2,3), (5,1,2), (4,3,7),
|
||||
(8,9,0), (10,7,1), (5,5,1);
|
||||
|
||||
create table t3 (a int, b varchar(16), index idx(a));
|
||||
insert into t3 values
|
||||
(1, "abc"), (3, "egh"), (8, "axxx"), (10, "abc"),
|
||||
(2, "ccw"), (8, "wqqe"), (7, "au"), (9, "waa"),
|
||||
(3, "rass"), (9, "ert"), (9, "lok"), (8, "aww"),
|
||||
(1, "todd"), (3, "rew"), (8, "aww"), (3, "sw"),
|
||||
(11, "llk"), (7, "rbw"), (1, "sm"), (2, "jyp"),
|
||||
(4, "yq"), (5, "pled"), (12, "ligin"), (12, "toww"),
|
||||
(6, "mxm"), (15, "wanone"), (9, "sunqq"), (2, "abe");
|
||||
|
||||
--echo # optimization is not used
|
||||
|
||||
let $query= select * from t1 where a in (1,2);
|
||||
eval $query;
|
||||
eval explain $query;
|
||||
eval explain format=json $query;
|
||||
eval explain extended $query;
|
||||
|
||||
--echo # set minimum number of values in VALUEs list when optimization works to 2
|
||||
|
||||
@ -239,5 +248,39 @@ execute stmt;
|
||||
execute stmt;
|
||||
deallocate prepare stmt;
|
||||
|
||||
drop table t1, t2;
|
||||
--echo # use inside out access from tvc rows
|
||||
|
||||
let $query= select * from t3 where a in (1,4,10);
|
||||
set @@in_subquery_conversion_threshold= default;
|
||||
eval $query;
|
||||
eval explain extended $query;
|
||||
set @@in_subquery_conversion_threshold= 2;
|
||||
eval $query;
|
||||
eval explain extended $query;
|
||||
|
||||
--echo # use vectors in IN predeicate
|
||||
|
||||
set @@in_subquery_conversion_threshold= 4;
|
||||
|
||||
let $query=
|
||||
select * from t1 where (a,b) in ((1,2),(3,4));
|
||||
|
||||
eval $query;
|
||||
eval explain extended $query;
|
||||
set @@in_subquery_conversion_threshold= 2;
|
||||
|
||||
--echo # trasformation works for the one IN predicate and doesn't work for the other
|
||||
|
||||
set @@in_subquery_conversion_threshold= 5;
|
||||
|
||||
let $query=
|
||||
select * from t2
|
||||
where (a,b) in ((1,2),(8,9)) and
|
||||
(a,c) in ((1,3),(8,0),(5,1));
|
||||
|
||||
eval $query;
|
||||
eval explain extended $query;
|
||||
set @@in_subquery_conversion_threshold= 2;
|
||||
|
||||
drop table t1, t2, t3;
|
||||
set @@in_subquery_conversion_threshold= default;
|
||||
|
@ -4334,8 +4334,11 @@ void Item_func_in::mark_as_condition_AND_part(TABLE_LIST *embedding)
|
||||
Query_arena *arena, backup;
|
||||
arena= thd->activate_stmt_arena_if_needed(&backup);
|
||||
|
||||
if (can_be_transformed_in_tvc(thd))
|
||||
if (to_be_transformed_into_in_subq(thd))
|
||||
{
|
||||
transform_into_subq= true;
|
||||
thd->lex->current_select->in_funcs.push_back(this, thd->mem_root);
|
||||
}
|
||||
|
||||
if (arena)
|
||||
thd->restore_active_arena(arena, &backup);
|
||||
|
@ -2128,6 +2128,7 @@ class Item_func_in :public Item_func_opt_neg,
|
||||
protected:
|
||||
SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param,
|
||||
Field *field, Item *value);
|
||||
bool transform_into_subq;
|
||||
public:
|
||||
/// An array of values, created when the bisection lookup method is used
|
||||
in_vector *array;
|
||||
@ -2244,7 +2245,8 @@ public:
|
||||
return clone;
|
||||
}
|
||||
void mark_as_condition_AND_part(TABLE_LIST *embedding);
|
||||
bool can_be_transformed_in_tvc(THD *thd);
|
||||
bool to_be_transformed_into_in_subq(THD *thd);
|
||||
bool create_value_list_for_tvc(THD *thd, List< List<Item> > *values);
|
||||
Item *in_predicate_to_in_subs_transformer(THD *thd, uchar *arg);
|
||||
};
|
||||
|
||||
|
@ -1047,7 +1047,7 @@ bool convert_join_subqueries_to_semijoins(JOIN *join)
|
||||
DBUG_RETURN(1);
|
||||
if (subq_sel->handle_derived(thd->lex, DT_MERGE))
|
||||
DBUG_RETURN(TRUE);
|
||||
if (subq_sel->join->transform_in_predicate_into_tvc(thd))
|
||||
if (subq_sel->join->transform_in_predicates_into_in_subq(thd))
|
||||
DBUG_RETURN(TRUE);
|
||||
subq_sel->update_used_tables();
|
||||
}
|
||||
|
@ -2265,7 +2265,7 @@ void st_select_lex::init_select()
|
||||
lock_type= TL_READ_DEFAULT;
|
||||
tvc= 0;
|
||||
in_funcs.empty();
|
||||
cur_tvc= 0;
|
||||
curr_tvc_name= 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -874,7 +874,7 @@ public:
|
||||
transformation of IN-predicate into IN-subquery for this
|
||||
st_select_lex.
|
||||
*/
|
||||
uint cur_tvc;
|
||||
uint curr_tvc_name;
|
||||
|
||||
/*
|
||||
Needed to correctly generate 'PRIMARY' or 'SIMPLE' for select_type column
|
||||
|
@ -1189,7 +1189,7 @@ JOIN::optimize_inner()
|
||||
}
|
||||
|
||||
if (select_lex->first_cond_optimization &&
|
||||
transform_in_predicate_into_tvc(thd))
|
||||
transform_in_predicates_into_in_subq(thd))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
// Update used tables after all handling derived table procedures
|
||||
|
@ -1648,7 +1648,7 @@ public:
|
||||
bool need_order, bool distinct,
|
||||
const char *message);
|
||||
JOIN_TAB *first_breadth_first_tab() { return join_tab; }
|
||||
bool transform_in_predicate_into_tvc(THD *thd_arg);
|
||||
bool transform_in_predicates_into_in_subq(THD *thd);
|
||||
private:
|
||||
/**
|
||||
Create a temporary table to be used for processing DISTINCT/ORDER
|
||||
|
297
sql/sql_tvc.cc
297
sql/sql_tvc.cc
@ -374,164 +374,211 @@ void table_value_constr::print(THD *thd_arg, String *str,
|
||||
|
||||
/**
|
||||
@brief
|
||||
Transforms IN-predicate in IN-subselect
|
||||
Create list of lists for TVC from the list of this IN predicate
|
||||
|
||||
@param thd_arg The context of the statement
|
||||
@param arg Argument is 0 in this context
|
||||
@param thd The context of the statement
|
||||
@param values TVC list of values
|
||||
|
||||
@details
|
||||
The method creates this SELECT statement:
|
||||
The method uses the list of values of this IN predicate to build
|
||||
an equivalent list of values that can be used in TVC.
|
||||
|
||||
SELECT * FROM (VALUES values) AS new_tvc
|
||||
E.g.:
|
||||
|
||||
If during creation of SELECT statement some action is
|
||||
unsuccesfull backup is made to the state in which system
|
||||
was at the beginning of the procedure.
|
||||
<value_list> = 5,2,7
|
||||
<transformed_value_list> = (5),(2),(7)
|
||||
|
||||
<value_list> = (5,2),(7,1)
|
||||
<transformed_value_list> = (5,2),(7,1)
|
||||
|
||||
@retval
|
||||
pointer to the created SELECT statement
|
||||
NULL - if creation was unsuccesfull
|
||||
false if the method succeeds
|
||||
true otherwise
|
||||
*/
|
||||
|
||||
bool Item_func_in::create_value_list_for_tvc(THD *thd,
|
||||
List< List<Item> > *values)
|
||||
{
|
||||
bool is_list_of_rows= args[1]->type() == Item::ROW_ITEM;
|
||||
|
||||
for (uint i=1; i < arg_count; i++)
|
||||
{
|
||||
List<Item> *tvc_value;
|
||||
if (!(tvc_value= new (thd->mem_root) List<Item>()))
|
||||
return true;
|
||||
|
||||
if (is_list_of_rows)
|
||||
{
|
||||
Item_row *row_list= (Item_row *)(args[i]);
|
||||
|
||||
for (uint j=0; j < row_list->cols(); j++)
|
||||
{
|
||||
if (tvc_value->push_back(row_list->element_index(j),
|
||||
thd->mem_root))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (tvc_value->push_back(args[i]))
|
||||
return true;
|
||||
|
||||
if (values->push_back(tvc_value, thd->mem_root))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static bool create_tvc_name(THD *thd, st_select_lex *parent_select,
|
||||
LEX_CSTRING *alias)
|
||||
{
|
||||
char buff[6];
|
||||
|
||||
alias->length= my_snprintf(buff, sizeof(buff),
|
||||
"tvc_%u", parent_select->curr_tvc_name);
|
||||
alias->str= thd->strmake(buff, alias->length);
|
||||
if (!alias->str)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief
|
||||
Transform IN predicate into IN subquery
|
||||
|
||||
@param thd The context of the statement
|
||||
@param arg Not used
|
||||
|
||||
@details
|
||||
The method transforms this IN predicate into in equivalent IN subquery:
|
||||
|
||||
<left_expr> IN (<value_list>)
|
||||
=>
|
||||
<left_expr> IN (SELECT * FROM (VALUES <transformed_value_list>) AS tvc_#)
|
||||
|
||||
E.g.:
|
||||
|
||||
<value_list> = 5,2,7
|
||||
<transformed_value_list> = (5),(2),(7)
|
||||
|
||||
<value_list> = (5,2),(7,1)
|
||||
<transformed_value_list> = (5,2),(7,1)
|
||||
|
||||
If the transformation succeeds the method returns the result IN subquery,
|
||||
otherwise this IN predicate is returned.
|
||||
|
||||
@retval
|
||||
pointer to the result of transformation if succeeded
|
||||
pointer to this IN predicate otherwise
|
||||
*/
|
||||
|
||||
Item *Item_func_in::in_predicate_to_in_subs_transformer(THD *thd,
|
||||
uchar *arg)
|
||||
{
|
||||
SELECT_LEX *old_select= thd->lex->current_select;
|
||||
if (!transform_into_subq)
|
||||
return this;
|
||||
|
||||
transform_into_subq= false;
|
||||
|
||||
List<List_item> values;
|
||||
Item *item;
|
||||
SELECT_LEX *sel;
|
||||
SELECT_LEX_UNIT *unit;
|
||||
TABLE_LIST *new_tab;
|
||||
Table_ident *ti;
|
||||
Item_in_subselect *in_subs;
|
||||
|
||||
LEX *lex= thd->lex;
|
||||
/* SELECT_LEX object where the transformation is performed */
|
||||
SELECT_LEX *parent_select= lex->current_select;
|
||||
uint8 save_derived_tables= lex->derived_tables;
|
||||
|
||||
Query_arena backup;
|
||||
Query_arena *arena= thd->activate_stmt_arena_if_needed(&backup);
|
||||
LEX *lex= thd->lex;
|
||||
|
||||
char buff[6];
|
||||
LEX_CSTRING alias;
|
||||
|
||||
/*
|
||||
Creation of values list of lists
|
||||
Create SELECT_LEX of the subquery SQ used in the result of transformation
|
||||
*/
|
||||
bool list_of_lists= false;
|
||||
|
||||
if (args[1]->type() == Item::ROW_ITEM)
|
||||
list_of_lists= true;
|
||||
|
||||
for (uint i=1; i < arg_count; i++)
|
||||
{
|
||||
List<Item> *new_value= new (thd->mem_root) List<Item>();
|
||||
|
||||
if (list_of_lists)
|
||||
{
|
||||
Item_row *in_list= (Item_row *)(args[i]);
|
||||
|
||||
for (uint j=0; j < in_list->cols(); i++)
|
||||
new_value->push_back(in_list->element_index(j), thd->mem_root);
|
||||
}
|
||||
else
|
||||
new_value->push_back(args[i]);
|
||||
|
||||
values.push_back(new_value, thd->mem_root);
|
||||
}
|
||||
|
||||
/*
|
||||
Creation of TVC name
|
||||
*/
|
||||
alias.length= my_snprintf(buff, sizeof(buff),
|
||||
"tvc_%u", old_select->cur_tvc);
|
||||
alias.str= thd->strmake(buff, alias.length);
|
||||
if (!alias.str)
|
||||
goto err;
|
||||
|
||||
/*
|
||||
Creation of SELECT statement: SELECT * FROM ...
|
||||
*/
|
||||
|
||||
if (mysql_new_select(lex, 1, NULL))
|
||||
goto err;
|
||||
|
||||
mysql_init_select(lex);
|
||||
lex->current_select->parsing_place= SELECT_LIST;
|
||||
|
||||
item= new (thd->mem_root) Item_field(thd, &lex->current_select->context,
|
||||
/* Create item list as '*' for the subquery SQ */
|
||||
Item *item;
|
||||
SELECT_LEX *sq_select; // select for IN subquery;
|
||||
sq_select= lex->current_select;
|
||||
sq_select->parsing_place= SELECT_LIST;
|
||||
item= new (thd->mem_root) Item_field(thd, &sq_select->context,
|
||||
NULL, NULL, &star_clex_str);
|
||||
if (item == NULL)
|
||||
if (item == NULL || add_item_to_list(thd, item))
|
||||
goto err;
|
||||
if (add_item_to_list(thd, item))
|
||||
goto err;
|
||||
(lex->current_select->with_wild)++;
|
||||
|
||||
(sq_select->with_wild)++;
|
||||
/*
|
||||
Creation of TVC as derived table
|
||||
Create derived table DT that will wrap TVC in the result of transformation
|
||||
*/
|
||||
|
||||
lex->derived_tables|= DERIVED_SUBQUERY;
|
||||
SELECT_LEX *tvc_select; // select for tvc
|
||||
SELECT_LEX_UNIT *derived_unit; // unit for tvc_select
|
||||
if (mysql_new_select(lex, 1, NULL))
|
||||
goto err;
|
||||
|
||||
mysql_init_select(lex);
|
||||
tvc_select= lex->current_select;
|
||||
derived_unit= tvc_select->master_unit();
|
||||
tvc_select->linkage= DERIVED_TABLE_TYPE;
|
||||
|
||||
sel= lex->current_select;
|
||||
unit= sel->master_unit();
|
||||
sel->linkage= DERIVED_TABLE_TYPE;
|
||||
|
||||
if (!(sel->tvc=
|
||||
/* Create TVC used in the transformation */
|
||||
if (create_value_list_for_tvc(thd, &values))
|
||||
goto err;
|
||||
if (!(tvc_select->tvc=
|
||||
new (thd->mem_root)
|
||||
table_value_constr(values,
|
||||
sel,
|
||||
sel->options)))
|
||||
tvc_select,
|
||||
tvc_select->options)))
|
||||
goto err;
|
||||
|
||||
lex->check_automatic_up(UNSPECIFIED_TYPE);
|
||||
lex->current_select= sel= unit->outer_select();
|
||||
lex->current_select= sq_select;
|
||||
|
||||
ti= new (thd->mem_root) Table_ident(unit);
|
||||
if (ti == NULL)
|
||||
/*
|
||||
Create the name of the wrapping derived table and
|
||||
add it to the FROM list of the subquery SQ
|
||||
*/
|
||||
Table_ident *ti;
|
||||
LEX_CSTRING alias;
|
||||
TABLE_LIST *derived_tab;
|
||||
if (!(ti= new (thd->mem_root) Table_ident(derived_unit)) ||
|
||||
create_tvc_name(thd, parent_select, &alias))
|
||||
goto err;
|
||||
|
||||
if (!(new_tab= sel->add_table_to_list(thd,
|
||||
ti, &alias, 0,
|
||||
TL_READ, MDL_SHARED_READ)))
|
||||
if (!(derived_tab=
|
||||
sq_select->add_table_to_list(thd,
|
||||
ti, &alias, 0,
|
||||
TL_READ, MDL_SHARED_READ)))
|
||||
goto err;
|
||||
sq_select->add_joined_table(derived_tab);
|
||||
sq_select->add_where_field(derived_unit->first_select());
|
||||
sq_select->context.table_list= sq_select->table_list.first;
|
||||
sq_select->context.first_name_resolution_table= sq_select->table_list.first;
|
||||
sq_select->table_list.first->derived_type= DTYPE_TABLE | DTYPE_MATERIALIZE;
|
||||
lex->derived_tables|= DERIVED_SUBQUERY;
|
||||
|
||||
sel->add_joined_table(new_tab);
|
||||
sq_select->where= 0;
|
||||
sq_select->set_braces(false);
|
||||
derived_unit->set_with_clause(0);
|
||||
|
||||
new_tab->select_lex->add_where_field(new_tab->derived->first_select());
|
||||
|
||||
sel->context.table_list=
|
||||
sel->context.first_name_resolution_table=
|
||||
sel->table_list.first;
|
||||
|
||||
sel->where= 0;
|
||||
sel->set_braces(false);
|
||||
unit->with_clause= 0;
|
||||
|
||||
if (!sel)
|
||||
/* Create IN subquery predicate */
|
||||
sq_select->parsing_place= parent_select->parsing_place;
|
||||
Item_in_subselect *in_subs;
|
||||
if (!(in_subs=
|
||||
new (thd->mem_root) Item_in_subselect(thd, args[0], sq_select)))
|
||||
goto err;
|
||||
|
||||
sel->parsing_place= old_select->parsing_place;
|
||||
sel->table_list.first->derived_type= 10;
|
||||
|
||||
in_subs= new (thd->mem_root) Item_in_subselect(thd, args[0], sel);
|
||||
thd->lex->derived_tables |= DERIVED_SUBQUERY;
|
||||
in_subs->emb_on_expr_nest= emb_on_expr_nest;
|
||||
|
||||
old_select->cur_tvc++;
|
||||
thd->lex->current_select= old_select;
|
||||
|
||||
if (arena)
|
||||
thd->restore_active_arena(arena, &backup);
|
||||
thd->lex->current_select= parent_select;
|
||||
|
||||
in_subs->fix_fields(thd, (Item **)&in_subs);
|
||||
if (in_subs->fix_fields(thd, (Item **)&in_subs))
|
||||
goto err;
|
||||
|
||||
parent_select->curr_tvc_name++;
|
||||
return in_subs;
|
||||
|
||||
err:
|
||||
if (arena)
|
||||
thd->restore_active_arena(arena, &backup);
|
||||
lex->derived_tables= save_derived_tables;
|
||||
thd->lex->current_select= parent_select;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -552,9 +599,9 @@ err:
|
||||
false otherwise
|
||||
*/
|
||||
|
||||
bool Item_func_in::can_be_transformed_in_tvc(THD *thd)
|
||||
bool Item_func_in::to_be_transformed_into_in_subq(THD *thd)
|
||||
{
|
||||
uint opt_can_be_used= arg_count;
|
||||
uint opt_can_be_used= arg_count-1;
|
||||
|
||||
if (args[1]->type() == Item::ROW_ITEM)
|
||||
opt_can_be_used*= ((Item_row *)(args[1]))->cols();
|
||||
@ -567,32 +614,35 @@ bool Item_func_in::can_be_transformed_in_tvc(THD *thd)
|
||||
|
||||
/**
|
||||
@brief
|
||||
Calls transformer that transforms IN-predicate into IN-subquery
|
||||
for this select
|
||||
Transform IN predicates into IN subqueries in WHERE and ON expressions
|
||||
|
||||
@param thd_arg The context of the statement
|
||||
@param thd The context of the statement
|
||||
|
||||
@details
|
||||
Calls in_predicate_to_in_subs_transformer
|
||||
for WHERE-part and each table from join list of this SELECT
|
||||
For each IN predicate from AND parts of the WHERE condition and/or
|
||||
ON expressions of the SELECT for this join the method performs
|
||||
the intransformation into an equivalent IN sunquery if it's needed.
|
||||
|
||||
@retval
|
||||
false always
|
||||
*/
|
||||
|
||||
bool JOIN::transform_in_predicate_into_tvc(THD *thd_arg)
|
||||
bool JOIN::transform_in_predicates_into_in_subq(THD *thd)
|
||||
{
|
||||
if (!select_lex->in_funcs.elements)
|
||||
return false;
|
||||
|
||||
SELECT_LEX *old_select= thd_arg->lex->current_select;
|
||||
enum_parsing_place old_parsing_place= select_lex->parsing_place;
|
||||
|
||||
thd_arg->lex->current_select= select_lex;
|
||||
SELECT_LEX *save_current_select= thd->lex->current_select;
|
||||
enum_parsing_place save_parsing_place= select_lex->parsing_place;
|
||||
thd->lex->current_select= select_lex;
|
||||
if (conds)
|
||||
{
|
||||
select_lex->parsing_place= IN_WHERE;
|
||||
conds=
|
||||
conds->transform(thd_arg,
|
||||
conds->transform(thd,
|
||||
&Item::in_predicate_to_in_subs_transformer,
|
||||
(uchar*) 0);
|
||||
select_lex->prep_where= conds ? conds->copy_andor_structure(thd) : 0;
|
||||
select_lex->where= conds;
|
||||
}
|
||||
|
||||
@ -607,7 +657,7 @@ bool JOIN::transform_in_predicate_into_tvc(THD *thd_arg)
|
||||
if (table->on_expr)
|
||||
{
|
||||
table->on_expr=
|
||||
table->on_expr->transform(thd_arg,
|
||||
table->on_expr->transform(thd,
|
||||
&Item::in_predicate_to_in_subs_transformer,
|
||||
(uchar*) 0);
|
||||
table->prep_on_expr= table->on_expr ?
|
||||
@ -615,8 +665,9 @@ bool JOIN::transform_in_predicate_into_tvc(THD *thd_arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
select_lex->in_funcs.empty();
|
||||
select_lex->parsing_place= old_parsing_place;
|
||||
thd_arg->lex->current_select= old_select;
|
||||
select_lex->parsing_place= save_parsing_place;
|
||||
thd->lex->current_select= save_current_select;
|
||||
return false;
|
||||
}
|
Reference in New Issue
Block a user