Skip to content

Commit 2e7ba70

Browse files
committed
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.
1 parent c6ee3fe commit 2e7ba70

File tree

3 files changed

+51
-6
lines changed

3 files changed

+51
-6
lines changed

mysql-test/r/subselect_innodb.result

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,3 +469,17 @@ f1 f2
469469
set join_cache_level = default;
470470
drop view v1;
471471
drop table t1,t2;
472+
#
473+
# MDEV-10693: cost-based choice between materialization and in-to-exists
474+
# for a subquery from the expression used in ref access
475+
#
476+
CREATE TABLE t1 (i1 INT PRIMARY KEY) ENGINE=InnoDB;
477+
INSERT INTO t1 VALUES (1),(2);
478+
CREATE TABLE t2 (i2 INT) ENGINE=InnoDB;
479+
CREATE TABLE t3 (i3 INT PRIMARY KEY) ENGINE=InnoDB;
480+
INSERT INTO t3 VALUES (3);
481+
SELECT * FROM t1
482+
WHERE NULL IN ( SELECT i2 FROM t2
483+
WHERE i1 IN ( i2 IN ( SELECT i3 FROM t3 ) ) AND i2 = 2 );
484+
i1
485+
DROP TABLE t1,t2,t3;

mysql-test/t/subselect_innodb.test

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,3 +453,25 @@ SELECT * FROM v1, t2 WHERE ( f1, f2 ) IN ( SELECT f1, f1 FROM t1 );
453453
set join_cache_level = default;
454454
drop view v1;
455455
drop table t1,t2;
456+
457+
--echo #
458+
--echo # MDEV-10693: cost-based choice between materialization and in-to-exists
459+
--echo # for a subquery from the expression used in ref access
460+
--echo #
461+
462+
--source include/have_innodb.inc
463+
464+
CREATE TABLE t1 (i1 INT PRIMARY KEY) ENGINE=InnoDB;
465+
INSERT INTO t1 VALUES (1),(2);
466+
467+
CREATE TABLE t2 (i2 INT) ENGINE=InnoDB;
468+
469+
CREATE TABLE t3 (i3 INT PRIMARY KEY) ENGINE=InnoDB;
470+
INSERT INTO t3 VALUES (3);
471+
472+
SELECT * FROM t1
473+
WHERE NULL IN ( SELECT i2 FROM t2
474+
WHERE i1 IN ( i2 IN ( SELECT i3 FROM t3 ) ) AND i2 = 2 );
475+
476+
DROP TABLE t1,t2,t3;
477+

sql/sql_select.cc

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7728,8 +7728,6 @@ get_best_combination(JOIN *join)
77287728
join->full_join=0;
77297729
join->hash_join= FALSE;
77307730

7731-
used_tables= OUTER_REF_TABLE_BIT; // Outer row is already read
7732-
77337731
fix_semijoin_strategies_for_picked_join_order(join);
77347732

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

77937791
form=join->table[tablenr]=j->table;
7794-
used_tables|= form->map;
77957792
form->reginfo.join_tab=j;
77967793
DBUG_PRINT("info",("type: %d", j->type));
77977794
if (j->type == JT_CONST)
@@ -7818,9 +7815,6 @@ get_best_combination(JOIN *join)
78187815
join->best_positions[tablenr].loosescan_picker.loosescan_key);
78197816
j->index= join->best_positions[tablenr].loosescan_picker.loosescan_key;
78207817
}*/
7821-
7822-
if (keyuse && create_ref_for_key(join, j, keyuse, TRUE, used_tables))
7823-
DBUG_RETURN(TRUE); // Something went wrong
78247818

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

7842+
used_tables= OUTER_REF_TABLE_BIT; // Outer row is already read
7843+
for (j=join_tab, tablenr=0 ; tablenr < table_count ; tablenr++,j++)
7844+
{
7845+
if (j->bush_children)
7846+
j= j->bush_children->start;
7847+
7848+
used_tables|= j->table->map;
7849+
if ((keyuse= join->best_positions[tablenr].key) &&
7850+
create_ref_for_key(join, j, keyuse, TRUE, used_tables))
7851+
DBUG_RETURN(TRUE); // Something went wrong
7852+
7853+
if (j->last_leaf_in_bush)
7854+
j= j->bush_root_tab;
7855+
}
7856+
78487857
join->top_join_tab_count= join->join_tab_ranges.head()->end -
78497858
join->join_tab_ranges.head()->start;
78507859
/*

0 commit comments

Comments
 (0)