Commit cfff9277 authored by unknown's avatar unknown

MWL#89: Address review feedback (by Sergey Petrunia)

mysql-test/r/subselect4.result:
  Moved test case for LP BUG#718593 into the correct test file subselect_mat_cost_bugs.test.
mysql-test/t/subselect4.test:
  Moved test case for LP BUG#718593 into the correct test file subselect_mat_cost_bugs.test.
parent 74093e9f
...@@ -1655,52 +1655,6 @@ f1b f2b f3b ...@@ -1655,52 +1655,6 @@ f1b f2b f3b
set @@optimizer_switch=@save_optimizer_switch; set @@optimizer_switch=@save_optimizer_switch;
drop table t0,t1,t2; drop table t0,t1,t2;
# #
# LP BUG#718593 Crash in substitute_for_best_equal_field -> eliminate_item_equal ->
# Item_field::find_item_equal -> Item_equal::contains
#
set @save_optimizer_switch=@@optimizer_switch;
SET @@optimizer_switch = 'semijoin=off';
CREATE TABLE t1 ( f3 int(11), f10 varchar(1), f11 varchar(1)) ;
INSERT IGNORE INTO t1 VALUES (6,'f','f'),(2,'d','d');
CREATE TABLE t2 ( f12 int(11), f13 int(11)) ;
insert into t2 values (1,2), (3,4);
EXPLAIN
SELECT * FROM t2
WHERE ( f12 ) IN (
SELECT alias2.f3
FROM t1 AS alias1 JOIN t1 AS alias2 ON alias2.f10 = alias1.f11
WHERE alias1.f11 OR alias1.f3 = 50 AND alias1.f10
);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where
2 DEPENDENT SUBQUERY alias1 ALL NULL NULL NULL NULL 2 Using where
2 DEPENDENT SUBQUERY alias2 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join)
SELECT * FROM t2
WHERE ( f12 ) IN (
SELECT alias2.f3
FROM t1 AS alias1 JOIN t1 AS alias2 ON alias2.f10 = alias1.f11
WHERE alias1.f11 OR alias1.f3 = 50 AND alias1.f10
);
f12 f13
EXPLAIN
SELECT * FROM t2
WHERE ( f12 ) IN (
SELECT alias2.f3
FROM t1 AS alias1, t1 AS alias2
WHERE (alias2.f10 = alias1.f11) AND (alias1.f11 OR alias1.f3 = 50 AND alias1.f10));
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where
2 DEPENDENT SUBQUERY alias1 ALL NULL NULL NULL NULL 2 Using where
2 DEPENDENT SUBQUERY alias2 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join)
SELECT * FROM t2
WHERE ( f12 ) IN (
SELECT alias2.f3
FROM t1 AS alias1, t1 AS alias2
WHERE (alias2.f10 = alias1.f11) AND (alias1.f11 OR alias1.f3 = 50 AND alias1.f10));
f12 f13
set @@optimizer_switch=@save_optimizer_switch;
drop table t1, t2;
#
# LP BUG#715759 Wrong result with in_to_exists=on in maria-5.3-mwl89 # LP BUG#715759 Wrong result with in_to_exists=on in maria-5.3-mwl89
# #
set @save_optimizer_switch=@@optimizer_switch; set @save_optimizer_switch=@@optimizer_switch;
......
...@@ -229,6 +229,72 @@ FROM t1 STRAIGHT_JOIN t2 ON t2.f3 = t1.f3 ...@@ -229,6 +229,72 @@ FROM t1 STRAIGHT_JOIN t2 ON t2.f3 = t1.f3
WHERE t2.f3 = 'c'); WHERE t2.f3 = 'c');
f2 f3 f2 f3
drop table t1,t2,t3; drop table t1,t2,t3;
#
# LP BUG#718593 Crash in substitute_for_best_equal_field -> eliminate_item_equal ->
# Item_field::find_item_equal -> Item_equal::contains
# #
# LP BUG#718593 Crash in substitute_for_best_equal_field -> set @save_optimizer_switch=@@optimizer_switch;
# eliminate_item_equal -> Item_field::find_item_equal -> Item_equal::contains SET @@optimizer_switch = 'semijoin=off';
CREATE TABLE t1 ( f3 int(11), f10 varchar(1), f11 varchar(1)) ;
INSERT IGNORE INTO t1 VALUES (6,'f','f'),(2,'d','d');
CREATE TABLE t2 ( f12 int(11), f13 int(11)) ;
insert into t2 values (1,2), (3,4);
EXPLAIN
SELECT * FROM t2
WHERE ( f12 ) IN (
SELECT alias2.f3
FROM t1 AS alias1 JOIN t1 AS alias2 ON alias2.f10 = alias1.f11
WHERE alias1.f11 OR alias1.f3 = 50 AND alias1.f10
);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where
2 SUBQUERY alias1 ALL NULL NULL NULL NULL 2 Using where
2 SUBQUERY alias2 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join)
SELECT * FROM t2
WHERE ( f12 ) IN (
SELECT alias2.f3
FROM t1 AS alias1 JOIN t1 AS alias2 ON alias2.f10 = alias1.f11
WHERE alias1.f11 OR alias1.f3 = 50 AND alias1.f10
);
f12 f13
EXPLAIN
SELECT * FROM t2
WHERE ( f12 ) IN (
SELECT alias2.f3
FROM t1 AS alias1, t1 AS alias2
WHERE (alias2.f10 = alias1.f11) AND (alias1.f11 OR alias1.f3 = 50 AND alias1.f10));
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where
2 SUBQUERY alias1 ALL NULL NULL NULL NULL 2 Using where
2 SUBQUERY alias2 ALL NULL NULL NULL NULL 2 Using where; Using join buffer (flat, BNL join)
SELECT * FROM t2
WHERE ( f12 ) IN (
SELECT alias2.f3
FROM t1 AS alias1, t1 AS alias2
WHERE (alias2.f10 = alias1.f11) AND (alias1.f11 OR alias1.f3 = 50 AND alias1.f10));
f12 f13
set @@optimizer_switch=@save_optimizer_switch;
drop table t1, t2;
#
# MWL#89: test introduced after Sergey Petrunia's review - test that
# keyparts wihtout index prefix are used with the IN-EXISTS strategy.
#
create table t1 (c1 int);
insert into t1 values (1), (2), (3);
create table t2 (kp1 int, kp2 int, c2 int, filler char(100));
insert into t2 values (0,0,0,'filler'),(0,1,1,'filler'),(0,2,2,'filler'),(0,3,3,'filler');
create index key1 on t2 (kp1, kp2);
create index key2 on t2 (kp1);
create index key3 on t2 (kp2);
set session optimizer_switch='default';
analyze table t2;
Table Op Msg_type Msg_text
test.t2 analyze status OK
explain
select c1 from t1 where c1 in (select kp1 from t2 where kp2 = 10 and c2 = 4) or c1 > 7;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where
2 DEPENDENT SUBQUERY t2 index_subquery key1,key2,key3 key1 10 func,const 1 Using where
select c1 from t1 where c1 in (select kp1 from t2 where kp2 = 10 and c2 = 4) or c1 > 7;
c1
drop table t1, t2;
...@@ -1328,48 +1328,6 @@ set @@optimizer_switch=@save_optimizer_switch; ...@@ -1328,48 +1328,6 @@ set @@optimizer_switch=@save_optimizer_switch;
drop table t0,t1,t2; drop table t0,t1,t2;
--echo #
--echo # LP BUG#718593 Crash in substitute_for_best_equal_field -> eliminate_item_equal ->
--echo # Item_field::find_item_equal -> Item_equal::contains
--echo #
set @save_optimizer_switch=@@optimizer_switch;
SET @@optimizer_switch = 'semijoin=off';
CREATE TABLE t1 ( f3 int(11), f10 varchar(1), f11 varchar(1)) ;
INSERT IGNORE INTO t1 VALUES (6,'f','f'),(2,'d','d');
CREATE TABLE t2 ( f12 int(11), f13 int(11)) ;
insert into t2 values (1,2), (3,4);
EXPLAIN
SELECT * FROM t2
WHERE ( f12 ) IN (
SELECT alias2.f3
FROM t1 AS alias1 JOIN t1 AS alias2 ON alias2.f10 = alias1.f11
WHERE alias1.f11 OR alias1.f3 = 50 AND alias1.f10
);
SELECT * FROM t2
WHERE ( f12 ) IN (
SELECT alias2.f3
FROM t1 AS alias1 JOIN t1 AS alias2 ON alias2.f10 = alias1.f11
WHERE alias1.f11 OR alias1.f3 = 50 AND alias1.f10
);
EXPLAIN
SELECT * FROM t2
WHERE ( f12 ) IN (
SELECT alias2.f3
FROM t1 AS alias1, t1 AS alias2
WHERE (alias2.f10 = alias1.f11) AND (alias1.f11 OR alias1.f3 = 50 AND alias1.f10));
SELECT * FROM t2
WHERE ( f12 ) IN (
SELECT alias2.f3
FROM t1 AS alias1, t1 AS alias2
WHERE (alias2.f10 = alias1.f11) AND (alias1.f11 OR alias1.f3 = 50 AND alias1.f10));
set @@optimizer_switch=@save_optimizer_switch;
drop table t1, t2;
--echo # --echo #
--echo # LP BUG#715759 Wrong result with in_to_exists=on in maria-5.3-mwl89 --echo # LP BUG#715759 Wrong result with in_to_exists=on in maria-5.3-mwl89
......
...@@ -258,54 +258,71 @@ WHERE ( f2 ) IN (SELECT t1.f1 ...@@ -258,54 +258,71 @@ WHERE ( f2 ) IN (SELECT t1.f1
drop table t1,t2,t3; drop table t1,t2,t3;
--echo #
--echo # LP BUG#718593 Crash in substitute_for_best_equal_field -> eliminate_item_equal ->
--echo # Item_field::find_item_equal -> Item_equal::contains
--echo # --echo #
--echo # LP BUG#718593 Crash in substitute_for_best_equal_field ->
--echo # eliminate_item_equal -> Item_field::find_item_equal -> Item_equal::contains
--disable_parsing # not yet fixed set @save_optimizer_switch=@@optimizer_switch;
SET @@optimizer_switch = 'semijoin=off';
CREATE TABLE t1 ( f3 int(11), f10 varchar(1), f11 varchar(1)) ; CREATE TABLE t1 ( f3 int(11), f10 varchar(1), f11 varchar(1)) ;
INSERT IGNORE INTO t1 VALUES (6,'f','f'),(2,'d','d'); INSERT IGNORE INTO t1 VALUES (6,'f','f'),(2,'d','d');
CREATE TABLE t2 ( f12 int(11), f13 int(11)) ; CREATE TABLE t2 ( f12 int(11), f13 int(11)) ;
insert into t2 values (1,2), (3,4);
set @save_optimizer_switch=@@optimizer_switch;
set @@optimizer_switch='materialization=off,in_to_exists=on,semijoin=off';
EXPLAIN EXPLAIN
SELECT * FROM t2 SELECT * FROM t2
WHERE (f12) IN ( WHERE ( f12 ) IN (
SELECT alias2.f3 SELECT alias2.f3
FROM t1 AS alias1, t1 AS alias2 FROM t1 AS alias1 JOIN t1 AS alias2 ON alias2.f10 = alias1.f11
WHERE (alias2.f10 = alias1.f11) AND WHERE alias1.f11 OR alias1.f3 = 50 AND alias1.f10
(alias1.f11 OR alias1.f3 = 50 AND alias1.f10)); );
SELECT * FROM t2 SELECT * FROM t2
WHERE (f12) IN ( WHERE ( f12 ) IN (
SELECT alias2.f3 SELECT alias2.f3
FROM t1 AS alias1, t1 AS alias2 FROM t1 AS alias1 JOIN t1 AS alias2 ON alias2.f10 = alias1.f11
WHERE (alias2.f10 = alias1.f11) AND WHERE alias1.f11 OR alias1.f3 = 50 AND alias1.f10
(alias1.f11 OR alias1.f3 = 50 AND alias1.f10)); );
insert into t2 values (1,2), (3,4);
EXPLAIN EXPLAIN
SELECT * FROM t2 SELECT * FROM t2
WHERE (f12) IN ( WHERE ( f12 ) IN (
SELECT alias2.f3 SELECT alias2.f3
FROM t1 AS alias1, t1 AS alias2 FROM t1 AS alias1, t1 AS alias2
WHERE (alias2.f10 = alias1.f11) AND WHERE (alias2.f10 = alias1.f11) AND (alias1.f11 OR alias1.f3 = 50 AND alias1.f10));
(alias1.f11 OR alias1.f3 = 50 AND alias1.f10));
SELECT * FROM t2 SELECT * FROM t2
WHERE (f12) IN ( WHERE ( f12 ) IN (
SELECT alias2.f3 SELECT alias2.f3
FROM t1 AS alias1, t1 AS alias2 FROM t1 AS alias1, t1 AS alias2
WHERE (alias2.f10 = alias1.f11) AND WHERE (alias2.f10 = alias1.f11) AND (alias1.f11 OR alias1.f3 = 50 AND alias1.f10));
(alias1.f11 OR alias1.f3 = 50 AND alias1.f10));
set session optimizer_switch=@save_optimizer_switch;
set @@optimizer_switch=@save_optimizer_switch;
drop table t1, t2; drop table t1, t2;
--enable_parsing
--echo #
--echo # MWL#89: test introduced after Sergey Petrunia's review - test that
--echo # keyparts wihtout index prefix are used with the IN-EXISTS strategy.
--echo #
create table t1 (c1 int);
insert into t1 values (1), (2), (3);
create table t2 (kp1 int, kp2 int, c2 int, filler char(100));
insert into t2 values (0,0,0,'filler'),(0,1,1,'filler'),(0,2,2,'filler'),(0,3,3,'filler');
create index key1 on t2 (kp1, kp2);
create index key2 on t2 (kp1);
create index key3 on t2 (kp2);
set session optimizer_switch='default';
analyze table t2;
explain
select c1 from t1 where c1 in (select kp1 from t2 where kp2 = 10 and c2 = 4) or c1 > 7;
select c1 from t1 where c1 in (select kp1 from t2 where kp2 = 10 and c2 = 4) or c1 > 7;
drop table t1, t2;
...@@ -2096,13 +2096,14 @@ Item *Item_in_optimizer::transform(Item_transformer transformer, uchar *argument ...@@ -2096,13 +2096,14 @@ Item *Item_in_optimizer::transform(Item_transformer transformer, uchar *argument
bool Item_in_optimizer::is_expensive_processor(uchar *arg) bool Item_in_optimizer::is_expensive_processor(uchar *arg)
{ {
return args[1]->is_expensive_processor(arg); return args[0]->is_expensive_processor(arg) ||
args[1]->is_expensive_processor(arg);
} }
bool Item_in_optimizer::is_expensive() bool Item_in_optimizer::is_expensive()
{ {
return args[1]->is_expensive(); return args[0]->is_expensive() || args[1]->is_expensive();
} }
......
...@@ -464,7 +464,7 @@ class Item_in_subselect :public Item_exists_subselect ...@@ -464,7 +464,7 @@ class Item_in_subselect :public Item_exists_subselect
Item_in_subselect() Item_in_subselect()
:Item_exists_subselect(), left_expr_cache(0), first_execution(TRUE), :Item_exists_subselect(), left_expr_cache(0), first_execution(TRUE),
optimizer(0), abort_on_null(0), optimizer(0), abort_on_null(0),
pushed_cond_guards(NULL), func(NULL), in_strategy(0), pushed_cond_guards(NULL), func(NULL), in_strategy(SUBS_NOT_TRANSFORMED),
upper_item(0) upper_item(0)
{} {}
void cleanup(); void cleanup();
......
...@@ -205,18 +205,19 @@ int check_and_do_in_subquery_rewrites(JOIN *join) ...@@ -205,18 +205,19 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
!optimizer_flag(thd, OPTIMIZER_SWITCH_MATERIALIZATION)) !optimizer_flag(thd, OPTIMIZER_SWITCH_MATERIALIZATION))
my_error(ER_ILLEGAL_SUBQUERY_OPTIMIZER_SWITCHES, MYF(0)); my_error(ER_ILLEGAL_SUBQUERY_OPTIMIZER_SWITCHES, MYF(0));
/*
If the subquery predicate is IN/=ANY, analyse and set all possible
subquery execution strategies based on optimizer switches and syntactic
properties.
*/
if (in_subs) if (in_subs)
{ {
/* Subquery predicate is an IN/=ANY predicate. */
if (optimizer_flag(thd, OPTIMIZER_SWITCH_IN_TO_EXISTS))
in_subs->in_strategy|= SUBS_IN_TO_EXISTS;
if (optimizer_flag(thd, OPTIMIZER_SWITCH_MATERIALIZATION))
in_subs->in_strategy|= SUBS_MATERIALIZATION;
/* /*
Check if the subquery predicate can be executed via materialization. Check if the subquery predicate can be executed via materialization.
The required conditions are: The required conditions are:
1. Subquery is a single SELECT (not a UNION) 0. The materialization optimizer switch was set.
1. Subquery is a single SELECT (not a UNION).
TODO: this is a limitation that can be fixed
2. Subquery is not a table-less query. In this case there is no 2. Subquery is not a table-less query. In this case there is no
point in materializing. point in materializing.
2A The upper query is not a table-less SELECT ... FROM DUAL. We 2A The upper query is not a table-less SELECT ... FROM DUAL. We
...@@ -230,7 +231,7 @@ int check_and_do_in_subquery_rewrites(JOIN *join) ...@@ -230,7 +231,7 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
non-top-level queries because it cannot handle NULLs correctly. non-top-level queries because it cannot handle NULLs correctly.
4. Subquery is non-correlated 4. Subquery is non-correlated
TODO: TODO:
This is an overly restrictive condition. It can be extended to: This condition is too restrictive (limitation). It can be extended to:
(Subquery is non-correlated || (Subquery is non-correlated ||
Subquery is correlated to any query outer to IN predicate || Subquery is correlated to any query outer to IN predicate ||
(Subquery is correlated to the immediate outer query && (Subquery is correlated to the immediate outer query &&
...@@ -240,30 +241,30 @@ int check_and_do_in_subquery_rewrites(JOIN *join) ...@@ -240,30 +241,30 @@ int check_and_do_in_subquery_rewrites(JOIN *join)
(*) The subquery must be part of a SELECT statement. The current (*) The subquery must be part of a SELECT statement. The current
condition also excludes multi-table update statements. condition also excludes multi-table update statements.
*/ */
if (!(in_subs->in_strategy & SUBS_MATERIALIZATION && if (optimizer_flag(thd, OPTIMIZER_SWITCH_MATERIALIZATION) && // 0
!select_lex->is_part_of_union() && // 1 !select_lex->is_part_of_union() && // 1
parent_unit->first_select()->leaf_tables && // 2 parent_unit->first_select()->leaf_tables && // 2
thd->lex->sql_command == SQLCOM_SELECT && // * thd->lex->sql_command == SQLCOM_SELECT && // *
select_lex->outer_select()->leaf_tables && // 2A select_lex->outer_select()->leaf_tables && // 2A
subquery_types_allow_materialization(in_subs) && subquery_types_allow_materialization(in_subs) &&
// psergey-todo: duplicated_subselect_card_check: where it's done? (in_subs->is_top_level_item() || //3
(in_subs->is_top_level_item() || //3 optimizer_flag(thd,
optimizer_flag(thd, OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE) || //3
OPTIMIZER_SWITCH_PARTIAL_MATCH_ROWID_MERGE) || //3 optimizer_flag(thd,
optimizer_flag(thd, OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN)) && //3
OPTIMIZER_SWITCH_PARTIAL_MATCH_TABLE_SCAN)) && //3 !in_subs->is_correlated) //4
!in_subs->is_correlated)) //4
{ {
/* Materialization is not possible based on syntactic properties. */ in_subs->in_strategy|= SUBS_MATERIALIZATION;
in_subs->in_strategy&= ~SUBS_MATERIALIZATION;
} }
if (!in_subs->in_strategy) /*
IN-TO-EXISTS is the only universal strategy. Choose it if the user
allowed it via an optimizer switch, or if materialization is not
possible.
*/
if (optimizer_flag(thd, OPTIMIZER_SWITCH_IN_TO_EXISTS) ||
!in_subs->in_strategy)
{ {
/*
If neither materialization is possible, nor the user chose
IN-TO-EXISTS, choose IN-TO-EXISTS as the only universal strategy.
*/
in_subs->in_strategy|= SUBS_IN_TO_EXISTS; in_subs->in_strategy|= SUBS_IN_TO_EXISTS;
} }
} }
...@@ -3703,10 +3704,9 @@ bool JOIN::choose_subquery_plan(table_map join_tables) ...@@ -3703,10 +3704,9 @@ bool JOIN::choose_subquery_plan(table_map join_tables)
enum_reopt_result reopt_result= REOPT_NONE; enum_reopt_result reopt_result= REOPT_NONE;
Item_in_subselect *in_subs; Item_in_subselect *in_subs;
if (select_lex->master_unit()->item && if (is_in_subquery())
select_lex->master_unit()->item->is_in_predicate())
{ {
in_subs= (Item_in_subselect*) select_lex->master_unit()->item; in_subs= (Item_in_subselect*) unit->item;
if (in_subs->create_in_to_exists_cond(this)) if (in_subs->create_in_to_exists_cond(this))
return true; return true;
} }
...@@ -3943,11 +3943,10 @@ bool JOIN::choose_subquery_plan(table_map join_tables) ...@@ -3943,11 +3943,10 @@ bool JOIN::choose_subquery_plan(table_map join_tables)
bool JOIN::choose_tableless_subquery_plan() bool JOIN::choose_tableless_subquery_plan()
{ {
DBUG_ASSERT(!tables_list || !tables); DBUG_ASSERT(!tables_list || !tables);
if (select_lex->master_unit()->item) if (unit->item)
{ {
DBUG_ASSERT(select_lex->master_unit()->item->type() == DBUG_ASSERT(unit->item->type() == Item::SUBSELECT_ITEM);
Item::SUBSELECT_ITEM); Item_subselect *subs_predicate= unit->item;
Item_subselect *subs_predicate= select_lex->master_unit()->item;
/* /*
If the optimizer determined that his query has an empty result, If the optimizer determined that his query has an empty result,
...@@ -3990,4 +3989,3 @@ bool JOIN::choose_tableless_subquery_plan() ...@@ -3990,4 +3989,3 @@ bool JOIN::choose_tableless_subquery_plan()
} }
return FALSE; return FALSE;
} }
...@@ -3123,7 +3123,7 @@ bool st_select_lex::optimize_unflattened_subqueries() ...@@ -3123,7 +3123,7 @@ bool st_select_lex::optimize_unflattened_subqueries()
un->set_limit(un->global_parameters); un->set_limit(un->global_parameters);
un->thd->lex->current_select= sl; un->thd->lex->current_select= sl;
save_options= inner_join->select_options; save_options= inner_join->select_options;
if (un->outer_select()->options & SELECT_DESCRIBE) if (options & SELECT_DESCRIBE)
{ {
/* Optimize the subquery in the context of EXPLAIN. */ /* Optimize the subquery in the context of EXPLAIN. */
sl->set_explain_type(); sl->set_explain_type();
......
...@@ -260,7 +260,7 @@ class base_list :public Sql_alloc ...@@ -260,7 +260,7 @@ class base_list :public Sql_alloc
list_node *node= first; list_node *node= first;
list_node *list_first= list->first; list_node *list_first= list->first;
elements=0; elements=0;
while (node->info && node != list_first) while (node != &end_of_list && node != list_first)
{ {
prev= &node->next; prev= &node->next;
node= node->next; node= node->next;
......
...@@ -57,7 +57,8 @@ static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse, ...@@ -57,7 +57,8 @@ static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,
uint tables, COND *conds, uint tables, COND *conds,
table_map table_map, SELECT_LEX *select_lex, table_map table_map, SELECT_LEX *select_lex,
st_sargable_param **sargables); st_sargable_param **sargables);
static bool sort_and_filter_keyuse(DYNAMIC_ARRAY *keyuse); static bool sort_and_filter_keyuse(DYNAMIC_ARRAY *keyuse,
bool skip_unprefixed_keyparts);
static int sort_keyuse(KEYUSE *a,KEYUSE *b); static int sort_keyuse(KEYUSE *a,KEYUSE *b);
static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse, static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
table_map used_tables); table_map used_tables);
...@@ -914,7 +915,6 @@ JOIN::optimize() ...@@ -914,7 +915,6 @@ JOIN::optimize()
"Impossible HAVING" : "Impossible WHERE"; "Impossible HAVING" : "Impossible WHERE";
tables= 0; tables= 0;
error= 0; error= 0;
choose_tableless_subquery_plan();
goto setup_subq_exit; goto setup_subq_exit;
} }
} }
...@@ -966,7 +966,6 @@ JOIN::optimize() ...@@ -966,7 +966,6 @@ JOIN::optimize()
zero_result_cause= "No matching min/max row"; zero_result_cause= "No matching min/max row";
tables= 0; tables= 0;
error=0; error=0;
choose_tableless_subquery_plan();
goto setup_subq_exit; goto setup_subq_exit;
} }
if (res > 1) if (res > 1)
...@@ -1007,7 +1006,6 @@ JOIN::optimize() ...@@ -1007,7 +1006,6 @@ JOIN::optimize()
{ {
DBUG_PRINT("info",("No tables")); DBUG_PRINT("info",("No tables"));
error= 0; error= 0;
choose_tableless_subquery_plan();
goto setup_subq_exit; goto setup_subq_exit;
} }
error= -1; // Error is sent to client error= -1; // Error is sent to client
...@@ -1508,6 +1506,9 @@ JOIN::optimize() ...@@ -1508,6 +1506,9 @@ JOIN::optimize()
DBUG_RETURN(0); DBUG_RETURN(0);
setup_subq_exit: setup_subq_exit:
/* Choose an execution strategy for this JOIN. */
if (!tables_list || !tables)
choose_tableless_subquery_plan();
/* /*
Even with zero matching rows, subqueries in the HAVING clause may Even with zero matching rows, subqueries in the HAVING clause may
need to be evaluated if there are aggregate functions in the query. need to be evaluated if there are aggregate functions in the query.
...@@ -3036,7 +3037,16 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds, ...@@ -3036,7 +3037,16 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds,
if (update_ref_and_keys(join->thd, keyuse_array, stat, join->tables, if (update_ref_and_keys(join->thd, keyuse_array, stat, join->tables,
conds, ~outer_join, join->select_lex, &sargables)) conds, ~outer_join, join->select_lex, &sargables))
goto error; goto error;
if (keyuse_array->elements && sort_and_filter_keyuse(keyuse_array)) /*
Keyparts without prefixes may be useful if this JOIN is a subquery, and
if the subquery may be executed via the IN-EXISTS strategy.
*/
bool skip_unprefixed_keyparts=
!(join->is_in_subquery() &&
((Item_in_subselect*)join->unit->item)->in_strategy & SUBS_IN_TO_EXISTS);
if (keyuse_array->elements &&
sort_and_filter_keyuse(keyuse_array, skip_unprefixed_keyparts))
goto error; goto error;
DBUG_EXECUTE("opt", print_keyuse_array(keyuse_array);); DBUG_EXECUTE("opt", print_keyuse_array(keyuse_array););
} }
...@@ -4505,7 +4515,8 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, ...@@ -4505,7 +4515,8 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
Special treatment for ft-keys. Special treatment for ft-keys.
*/ */
static bool sort_and_filter_keyuse(DYNAMIC_ARRAY *keyuse) static bool sort_and_filter_keyuse(DYNAMIC_ARRAY *keyuse,
bool skip_unprefixed_keyparts)
{ {
KEYUSE key_end, *prev, *save_pos, *use; KEYUSE key_end, *prev, *save_pos, *use;
uint found_eq_constant, i; uint found_eq_constant, i;
...@@ -4532,12 +4543,12 @@ static bool sort_and_filter_keyuse(DYNAMIC_ARRAY *keyuse) ...@@ -4532,12 +4543,12 @@ static bool sort_and_filter_keyuse(DYNAMIC_ARRAY *keyuse)
{ {
if (use->key == prev->key && use->table == prev->table) if (use->key == prev->key && use->table == prev->table)
{ {
if (prev->keypart+1 < use->keypart || if ((prev->keypart+1 < use->keypart && skip_unprefixed_keyparts) ||
(prev->keypart == use->keypart && found_eq_constant)) (prev->keypart == use->keypart && found_eq_constant))
continue; /* remove */ continue; /* remove */
} }
else if (use->keypart != 0) // First found must be 0 else if (use->keypart != 0 && skip_unprefixed_keyparts)
continue; continue; /* remove - first found must be 0 */
} }
prev= use; prev= use;
...@@ -16938,8 +16949,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, ...@@ -16938,8 +16949,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
select= tab->select; select= tab->select;
/* Currently ORDER BY ... LIMIT is not supported in subqueries. */ /* Currently ORDER BY ... LIMIT is not supported in subqueries. */
DBUG_ASSERT(join->group_list || DBUG_ASSERT(join->group_list || !join->is_in_subquery());
!(join->unit->item && join->unit->item->is_in_predicate()));
/* /*
When there is SQL_BIG_RESULT do not sort using index for GROUP BY, When there is SQL_BIG_RESULT do not sort using index for GROUP BY,
...@@ -20659,7 +20669,7 @@ JOIN::reoptimize(Item *added_where, table_map join_tables, ...@@ -20659,7 +20669,7 @@ JOIN::reoptimize(Item *added_where, table_map join_tables,
/* added_keyuse contents is copied, and it is no longer needed. */ /* added_keyuse contents is copied, and it is no longer needed. */
delete_dynamic(&added_keyuse); delete_dynamic(&added_keyuse);
if (sort_and_filter_keyuse(&keyuse)) if (sort_and_filter_keyuse(&keyuse, true))
return REOPT_ERROR; return REOPT_ERROR;
optimize_keyuse(this, &keyuse); optimize_keyuse(this, &keyuse);
......
...@@ -1083,6 +1083,11 @@ class JOIN :public Sql_alloc ...@@ -1083,6 +1083,11 @@ class JOIN :public Sql_alloc
double *read_time_arg, double *record_count_arg); double *read_time_arg, double *record_count_arg);
/* defined in opt_subselect.cc */ /* defined in opt_subselect.cc */
bool transform_max_min_subquery(); bool transform_max_min_subquery();
/* True if this JOIN is a subquery under an IN predicate. */
bool is_in_subquery()
{
return (unit->item && unit->item->is_in_predicate());
}
private: private:
/** /**
......
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