Skip to content
Permalink
Browse files

Fixed the bug mdev-10693.

The code that chooses between materialization of a non-correlated
IN subquery and its transformation into an EXISTS correlated
subquery assumes that the execution plan for the outer select
has been already built. However it was not always so if subqueries
occurred in the expressions used for ref access to tables of
the outer select. A call of the function create_ref_for_key() in
get_best_combination() could trigger a premature execution of
the above mentioned code when the execution plan structures for
the outer select were not fully built. This could cause a crash
of the server.

The fix postpones the calls of create_ref_for_key() until the
structures for the execution plan is fully built.
  • Loading branch information...
igorbabaev committed Apr 22, 2017
1 parent c6ee3fe commit 2e7ba70a94b5950a7d1d733c177d1b2a24916213
Showing with 51 additions and 6 deletions.
  1. +14 −0 mysql-test/r/subselect_innodb.result
  2. +22 −0 mysql-test/t/subselect_innodb.test
  3. +15 −6 sql/sql_select.cc
@@ -469,3 +469,17 @@ f1 f2
set join_cache_level = default;
drop view v1;
drop table t1,t2;
#
# MDEV-10693: cost-based choice between materialization and in-to-exists
# for a subquery from the expression used in ref access
#
CREATE TABLE t1 (i1 INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1),(2);
CREATE TABLE t2 (i2 INT) ENGINE=InnoDB;
CREATE TABLE t3 (i3 INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t3 VALUES (3);
SELECT * FROM t1
WHERE NULL IN ( SELECT i2 FROM t2
WHERE i1 IN ( i2 IN ( SELECT i3 FROM t3 ) ) AND i2 = 2 );
i1
DROP TABLE t1,t2,t3;
@@ -453,3 +453,25 @@ SELECT * FROM v1, t2 WHERE ( f1, f2 ) IN ( SELECT f1, f1 FROM t1 );
set join_cache_level = default;
drop view v1;
drop table t1,t2;

--echo #
--echo # MDEV-10693: cost-based choice between materialization and in-to-exists
--echo # for a subquery from the expression used in ref access
--echo #

--source include/have_innodb.inc

CREATE TABLE t1 (i1 INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1),(2);

CREATE TABLE t2 (i2 INT) ENGINE=InnoDB;

CREATE TABLE t3 (i3 INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t3 VALUES (3);

SELECT * FROM t1
WHERE NULL IN ( SELECT i2 FROM t2
WHERE i1 IN ( i2 IN ( SELECT i3 FROM t3 ) ) AND i2 = 2 );

DROP TABLE t1,t2,t3;

@@ -7728,8 +7728,6 @@ get_best_combination(JOIN *join)
join->full_join=0;
join->hash_join= FALSE;

used_tables= OUTER_REF_TABLE_BIT; // Outer row is already read

fix_semijoin_strategies_for_picked_join_order(join);

JOIN_TAB_RANGE *root_range;
@@ -7791,7 +7789,6 @@ get_best_combination(JOIN *join)
j->bush_root_tab= sjm_nest_root;

form=join->table[tablenr]=j->table;
used_tables|= form->map;
form->reginfo.join_tab=j;
DBUG_PRINT("info",("type: %d", j->type));
if (j->type == JT_CONST)
@@ -7818,9 +7815,6 @@ get_best_combination(JOIN *join)
join->best_positions[tablenr].loosescan_picker.loosescan_key);
j->index= join->best_positions[tablenr].loosescan_picker.loosescan_key;
}*/

if (keyuse && create_ref_for_key(join, j, keyuse, TRUE, used_tables))
DBUG_RETURN(TRUE); // Something went wrong

if ((j->type == JT_REF || j->type == JT_EQ_REF) &&
is_hash_join_key_no(j->ref.key))
@@ -7845,6 +7839,21 @@ get_best_combination(JOIN *join)
}
root_range->end= j;

used_tables= OUTER_REF_TABLE_BIT; // Outer row is already read
for (j=join_tab, tablenr=0 ; tablenr < table_count ; tablenr++,j++)
{
if (j->bush_children)
j= j->bush_children->start;

used_tables|= j->table->map;
if ((keyuse= join->best_positions[tablenr].key) &&
create_ref_for_key(join, j, keyuse, TRUE, used_tables))
DBUG_RETURN(TRUE); // Something went wrong

if (j->last_leaf_in_bush)
j= j->bush_root_tab;
}

join->top_join_tab_count= join->join_tab_ranges.head()->end -
join->join_tab_ranges.head()->start;
/*

0 comments on commit 2e7ba70

Please sign in to comment.
You can’t perform that action at this time.