Commit d17cfa9c authored by unknown's avatar unknown

removing additional IN subquery condition

fixed IN optimisation bug


mysql-test/r/subselect.result:
  test of IN optimisation bug
mysql-test/t/subselect.test:
  test of IN optimisation bug
sql/item_subselect.cc:
  fixed IN optimisation bug
sql/mysql_priv.h:
  constant for additional IN subquery condition detecting
sql/mysqld.cc:
  constant for additional IN subquery condition detecting
sql/sql_select.cc:
  removing additional IN subquery condition
parent b036ffec
...@@ -829,7 +829,7 @@ a t1.a in (select t2.a from t2) ...@@ -829,7 +829,7 @@ a t1.a in (select t2.a from t2)
explain SELECT t1.a, t1.a in (select t2.a from t2) FROM t1; explain SELECT t1.a, t1.a in (select t2.a from t2) FROM t1;
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 t1 index NULL PRIMARY 4 NULL 4 Using index 1 PRIMARY t1 index NULL PRIMARY 4 NULL 4 Using index
2 DEPENDENT SUBQUERY t2 index_in a a 5 func 2 Using where; Using index 2 DEPENDENT SUBQUERY t2 index_in a a 5 func 2 Using index
CREATE TABLE t3 (a int(11) default '0'); CREATE TABLE t3 (a int(11) default '0');
INSERT INTO t3 VALUES (1),(2),(3); INSERT INTO t3 VALUES (1),(2),(3);
SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1; SELECT t1.a, t1.a in (select t2.a from t2,t3 where t3.a=t2.a) FROM t1;
...@@ -1369,3 +1369,26 @@ select * from t1 where ('a','b')=(select 'a','b' from t1 union select 'a','b' fr ...@@ -1369,3 +1369,26 @@ select * from t1 where ('a','b')=(select 'a','b' from t1 union select 'a','b' fr
s1 s1
tttt tttt
drop table t1; drop table t1;
create table t1 (s1 char(5), index s1(s1));
create table t2 (s1 char(5), index s1(s1));
insert into t1 values ('a1'),('a2'),('a3');
insert into t2 values ('a1'),('a2');
select s1, s1 NOT IN (SELECT s1 FROM t2) from t1;
s1 s1 NOT IN (SELECT s1 FROM t2)
a1 0
a2 0
a3 1
select s1, s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2') from t1;
s1 s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2')
a1 0
a2 1
a3 1
explain select s1, s1 NOT IN (SELECT s1 FROM t2) from t1;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 index NULL s1 6 NULL 3 Using index
2 DEPENDENT SUBQUERY t2 index_in s1 s1 6 func 2 Using index
explain select s1, s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2') from t1;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 index NULL s1 6 NULL 3 Using index
2 DEPENDENT SUBQUERY t2 index_in s1 s1 6 func 1 Using index; Using where
drop table t1,t2;
...@@ -932,3 +932,16 @@ select (select 'a','b' from t1 union select 'a','b' from t1) from t1; ...@@ -932,3 +932,16 @@ select (select 'a','b' from t1 union select 'a','b' from t1) from t1;
insert into t1 values ('tttt'); insert into t1 values ('tttt');
select * from t1 where ('a','b')=(select 'a','b' from t1 union select 'a','b' from t1); select * from t1 where ('a','b')=(select 'a','b' from t1 union select 'a','b' from t1);
drop table t1; drop table t1;
#
# IN optimisation test results
#
create table t1 (s1 char(5), index s1(s1));
create table t2 (s1 char(5), index s1(s1));
insert into t1 values ('a1'),('a2'),('a3');
insert into t2 values ('a1'),('a2');
select s1, s1 NOT IN (SELECT s1 FROM t2) from t1;
select s1, s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2') from t1;
explain select s1, s1 NOT IN (SELECT s1 FROM t2) from t1;
explain select s1, s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2') from t1;
drop table t1,t2;
...@@ -576,6 +576,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, ...@@ -576,6 +576,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
item= new Item_cond_or(item, item= new Item_cond_or(item,
new Item_func_isnull(isnull)); new Item_func_isnull(isnull));
} }
item->name= (char *)in_additional_cond;
join->conds= and_items(join->conds, item); join->conds= and_items(join->conds, item);
if (join->conds->fix_fields(thd, join->tables_list, &join->conds)) if (join->conds->fix_fields(thd, join->tables_list, &join->conds))
DBUG_RETURN(RES_ERROR); DBUG_RETURN(RES_ERROR);
...@@ -971,6 +972,7 @@ int subselect_indexin_engine::exec() ...@@ -971,6 +972,7 @@ int subselect_indexin_engine::exec()
{ {
DBUG_ENTER("subselect_indexin_engine::exec"); DBUG_ENTER("subselect_indexin_engine::exec");
int error; int error;
bool null_finding= 0;
TABLE *table= tab->table; TABLE *table= tab->table;
((Item_in_subselect *) item)->value= 0; ((Item_in_subselect *) item)->value= 0;
...@@ -1002,29 +1004,30 @@ int subselect_indexin_engine::exec() ...@@ -1002,29 +1004,30 @@ int subselect_indexin_engine::exec()
{ {
if (!cond || cond->val_int()) if (!cond || cond->val_int())
{ {
if (check_null && *tab->null_ref_key) if (null_finding)
((Item_in_subselect *) item)->was_null= 1; ((Item_in_subselect *) item)->was_null= 1;
else else
((Item_in_subselect *) item)->value= 1; ((Item_in_subselect *) item)->value= 1;
goto finish; goto finish;
} }
error= table->file->index_next_same(table->record[0],
tab->ref.key_buff,
tab->ref.key_length);
if (error && error != HA_ERR_END_OF_FILE)
{
error= report_error(table, error);
goto finish;
}
} }
else else
{ {
if (!check_null || *tab->null_ref_key) if (!check_null || null_finding)
goto finish; goto finish;
*tab->null_ref_key= 1; *tab->null_ref_key= 1;
null_finding= 1;
if (safe_index_read(tab)) if (safe_index_read(tab))
goto finish; goto finish;
} }
error= table->file->index_next_same(table->record[0],
tab->ref.key_buff,
tab->ref.key_length);
if (error && error != HA_ERR_KEY_NOT_FOUND)
{
error= report_error(table, error);
goto finish;
}
} }
} }
} }
......
...@@ -716,7 +716,7 @@ extern const char *command_name[]; ...@@ -716,7 +716,7 @@ extern const char *command_name[];
extern const char *first_keyword, *localhost, *delayed_user, *binary_keyword; extern const char *first_keyword, *localhost, *delayed_user, *binary_keyword;
extern const char **errmesg; /* Error messages */ extern const char **errmesg; /* Error messages */
extern const char *myisam_recover_options_str; extern const char *myisam_recover_options_str;
extern const char *in_left_expr_name; extern const char *in_left_expr_name, *in_additional_cond;
extern uchar *days_in_month; extern uchar *days_in_month;
extern char language[LIBLEN],reg_ext[FN_EXTLEN]; extern char language[LIBLEN],reg_ext[FN_EXTLEN];
extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN]; extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN];
......
...@@ -320,6 +320,8 @@ const char *myisam_recover_options_str="OFF"; ...@@ -320,6 +320,8 @@ const char *myisam_recover_options_str="OFF";
const char *sql_mode_str="OFF"; const char *sql_mode_str="OFF";
/* name of reference on left espression in rewritten IN subquery */ /* name of reference on left espression in rewritten IN subquery */
const char *in_left_expr_name= "<left expr>"; const char *in_left_expr_name= "<left expr>";
/* name of additional condition */
const char *in_additional_cond= "<IN COND>";
FILE *bootstrap_file; FILE *bootstrap_file;
......
...@@ -160,6 +160,7 @@ static bool init_sum_functions(Item_sum **func, Item_sum **end); ...@@ -160,6 +160,7 @@ static bool init_sum_functions(Item_sum **func, Item_sum **end);
static bool update_sum_func(Item_sum **func); static bool update_sum_func(Item_sum **func);
static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
bool distinct, const char *message=NullS); bool distinct, const char *message=NullS);
static Item *remove_additional_cond(Item* conds);
/* /*
...@@ -464,8 +465,10 @@ bool JOIN::test_in_subselect(Item **where) ...@@ -464,8 +465,10 @@ bool JOIN::test_in_subselect(Item **where)
((class Item_func *)this->conds)->functype() == ((class Item_func *)this->conds)->functype() ==
Item_func::COND_AND_FUNC) Item_func::COND_AND_FUNC)
{ {
*where= conds; if ((*where= remove_additional_cond(conds)))
join_tab->info= "Using index; Using where"; join_tab->info= "Using index; Using where";
else
join_tab->info= "Using index";
return 1; return 1;
} }
return 0; return 0;
...@@ -806,6 +809,12 @@ JOIN::optimize() ...@@ -806,6 +809,12 @@ JOIN::optimize()
{ {
join_tab[0].type= JT_INDEX_IN; join_tab[0].type= JT_INDEX_IN;
error= 0; error= 0;
if ((conds= remove_additional_cond(conds)))
join_tab->info= "Using index; Using where";
else
join_tab->info= "Using index";
DBUG_RETURN(unit->item-> DBUG_RETURN(unit->item->
change_engine(new subselect_indexin_engine(thd, change_engine(new subselect_indexin_engine(thd,
join_tab, join_tab,
...@@ -3990,6 +3999,39 @@ change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father, ...@@ -3990,6 +3999,39 @@ change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
} }
} }
/*
Remove additional condition inserted by IN/ALL/ANY transformation
SYNOPSIS
remove_additional_cond()
conds - condition for processing
RETURN VALUES
new conditions
*/
static Item *remove_additional_cond(Item* conds)
{
if (conds->name == in_additional_cond)
return 0;
if (conds->type() == Item::COND_ITEM)
{
Item_cond *cnd= (Item_cond*) conds;
List_iterator<Item> li(*(cnd->argument_list()));
Item *item;
while ((item= li++))
{
if (item->name == in_additional_cond)
{
li.remove();
if (cnd->argument_list()->elements == 1)
return cnd->argument_list()->head();
return conds;
}
}
}
return conds;
}
static void static void
propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_level, propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_level,
......
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