diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index f7bfd44421c..0087044c782 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -5294,4 +5294,115 @@ WHERE (col_varchar_nokey, 'x') IN col_int_nokey 1 DROP TABLE ot,it1,it2; +# +# MDEV-746 +# Bug#13651009 WRONG RESULT FROM DERIVED TABLE IF THE SUBQUERY +# HAS AN EMPTY RESULT +# +CREATE TABLE t1 ( +pk int NOT NULL, +col_int_nokey int NOT NULL, +col_int_key int NOT NULL, +col_time_key time NOT NULL, +col_varchar_key varchar(1) NOT NULL, +col_varchar_nokey varchar(1) NOT NULL, +PRIMARY KEY (pk), +KEY col_int_key (col_int_key), +KEY col_time_key (col_time_key), +KEY col_varchar_key (col_varchar_key,col_int_key) +) ENGINE=MyISAM; +CREATE TABLE t2 ( +pk int NOT NULL AUTO_INCREMENT, +col_int_nokey int NOT NULL, +col_int_key int NOT NULL, +col_time_key time NOT NULL, +col_varchar_key varchar(1) NOT NULL, +col_varchar_nokey varchar(1) NOT NULL, +PRIMARY KEY (pk), +KEY col_int_key (col_int_key), +KEY col_time_key (col_time_key), +KEY col_varchar_key (col_varchar_key,col_int_key) +) ENGINE=MyISAM; +INSERT INTO t2 VALUES (1,4,4,'00:00:00','b','b'); +SET @var2:=4, @var3:=8; + +Testcase without inner subquery +EXPLAIN SELECT @var3:=12, sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR +sq4_alias1.col_varchar_key = @var3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +SELECT @var3:=12, sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR +sq4_alias1.col_varchar_key = @var3; +@var3:=12 pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey +SELECT @var3; +@var3 +8 +EXPLAIN SELECT * FROM ( SELECT @var3:=12, sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR +sq4_alias1.col_varchar_key = @var3 ) AS alias3; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY system NULL NULL NULL NULL 0 const row not found +2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table +SELECT * FROM ( SELECT @var3:=12, sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR +sq4_alias1.col_varchar_key = @var3 ) AS alias3; +@var3:=12 pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey +SELECT @var3; +@var3 +8 + +Testcase with inner subquery; crashed WL#6095 +SET @var3=8; +EXPLAIN SELECT sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey) +NOT IN +(SELECT c_sq1_alias1.col_varchar_key AS c_sq1_field1, +c_sq1_alias1.col_varchar_nokey AS c_sq1_field2 +FROM t2 AS c_sq1_alias1 +WHERE (c_sq1_alias1.col_int_nokey != @var2 +OR c_sq1_alias1.pk != @var3)); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +2 DEPENDENT SUBQUERY c_sq1_alias1 system PRIMARY,col_varchar_key NULL NULL NULL 1 +SELECT sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey) +NOT IN +(SELECT c_sq1_alias1.col_varchar_key AS c_sq1_field1, +c_sq1_alias1.col_varchar_nokey AS c_sq1_field2 +FROM t2 AS c_sq1_alias1 +WHERE (c_sq1_alias1.col_int_nokey != @var2 +OR c_sq1_alias1.pk != @var3)); +pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey +EXPLAIN SELECT * FROM ( SELECT sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey) +NOT IN +(SELECT c_sq1_alias1.col_varchar_key AS c_sq1_field1, +c_sq1_alias1.col_varchar_nokey AS c_sq1_field2 +FROM t2 AS c_sq1_alias1 +WHERE (c_sq1_alias1.col_int_nokey != @var2 +OR c_sq1_alias1.pk != @var3)) ) AS alias3; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY system NULL NULL NULL NULL 0 const row not found +2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table +3 DEPENDENT SUBQUERY c_sq1_alias1 system PRIMARY,col_varchar_key NULL NULL NULL 1 +SELECT * FROM ( SELECT sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey) +NOT IN +(SELECT c_sq1_alias1.col_varchar_key AS c_sq1_field1, +c_sq1_alias1.col_varchar_nokey AS c_sq1_field2 +FROM t2 AS c_sq1_alias1 +WHERE (c_sq1_alias1.col_int_nokey != @var2 +OR c_sq1_alias1.pk != @var3)) ) AS alias3; +pk col_int_nokey col_int_key col_time_key col_varchar_key col_varchar_nokey +DROP TABLE t1,t2; End of 5.2 tests diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index def42b24c73..3be57e993d5 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -4144,4 +4144,81 @@ SELECT col_int_nokey FROM ot DROP TABLE ot,it1,it2; +--echo # +--echo # MDEV-746 +--echo # Bug#13651009 WRONG RESULT FROM DERIVED TABLE IF THE SUBQUERY +--echo # HAS AN EMPTY RESULT +--echo # + +CREATE TABLE t1 ( + pk int NOT NULL, + col_int_nokey int NOT NULL, + col_int_key int NOT NULL, + col_time_key time NOT NULL, + col_varchar_key varchar(1) NOT NULL, + col_varchar_nokey varchar(1) NOT NULL, + PRIMARY KEY (pk), + KEY col_int_key (col_int_key), + KEY col_time_key (col_time_key), + KEY col_varchar_key (col_varchar_key,col_int_key) +) ENGINE=MyISAM; + +CREATE TABLE t2 ( + pk int NOT NULL AUTO_INCREMENT, + col_int_nokey int NOT NULL, + col_int_key int NOT NULL, + col_time_key time NOT NULL, + col_varchar_key varchar(1) NOT NULL, + col_varchar_nokey varchar(1) NOT NULL, + PRIMARY KEY (pk), + KEY col_int_key (col_int_key), + KEY col_time_key (col_time_key), + KEY col_varchar_key (col_varchar_key,col_int_key) +) ENGINE=MyISAM; + +INSERT INTO t2 VALUES (1,4,4,'00:00:00','b','b'); + +SET @var2:=4, @var3:=8; + +--echo +--echo Testcase without inner subquery + +let $subq= +SELECT @var3:=12, sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key + NULL) IS NULL OR + sq4_alias1.col_varchar_key = @var3; + +eval EXPLAIN $subq; +eval $subq; +SELECT @var3; + +# Now as derived table: +eval EXPLAIN SELECT * FROM ( $subq ) AS alias3; +eval SELECT * FROM ( $subq ) AS alias3; +SELECT @var3; + +--echo +--echo Testcase with inner subquery; crashed WL#6095 +SET @var3=8; +let $subq= +SELECT sq4_alias1.* +FROM t1 AS sq4_alias1 +WHERE (sq4_alias1.col_varchar_key , sq4_alias1.col_varchar_nokey) + NOT IN + (SELECT c_sq1_alias1.col_varchar_key AS c_sq1_field1, + c_sq1_alias1.col_varchar_nokey AS c_sq1_field2 + FROM t2 AS c_sq1_alias1 + WHERE (c_sq1_alias1.col_int_nokey != @var2 + OR c_sq1_alias1.pk != @var3)); + +eval EXPLAIN $subq; +eval $subq; +# Now as derived table: +eval EXPLAIN SELECT * FROM ( $subq ) AS alias3; +eval SELECT * FROM ( $subq ) AS alias3; + +DROP TABLE t1,t2; + --echo End of 5.2 tests + diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c6bddbf9a28..2a6c60af85f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1065,11 +1065,9 @@ JOIN::optimize() DBUG_RETURN(1); // error == -1 } if (const_table_map != found_const_table_map && - !(select_options & SELECT_DESCRIBE) && - (!conds || - !(conds->used_tables() & RAND_TABLE_BIT) || - select_lex->master_unit() == &thd->lex->unit)) // upper level SELECT + !(select_options & SELECT_DESCRIBE)) { + // There is at least one empty const table zero_result_cause= "no matching row in const table"; DBUG_PRINT("error",("Error: %s", zero_result_cause)); error= 0; @@ -12204,6 +12202,17 @@ int safe_index_read(JOIN_TAB *tab) } +/** + Reads content of constant table + + @param tab table + @param pos position of table in query plan + + @retval 0 ok, one row was found or one NULL-complemented row was created + @retval -1 ok, no row was found and no NULL-complemented row was created + @retval 1 error +*/ + static int join_read_const_table(JOIN_TAB *tab, POSITION *pos) { @@ -12295,6 +12304,16 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos) } +/** + Read a constant table when there is at most one matching row, using a table + scan. + + @param tab Table to read + + @retval 0 Row was found + @retval -1 Row was not found + @retval 1 Got an error (other than row not found) during read +*/ static int join_read_system(JOIN_TAB *tab) { @@ -12326,12 +12345,9 @@ join_read_system(JOIN_TAB *tab) @param tab Table to read - @retval - 0 Row was found - @retval - -1 Row was not found - @retval - 1 Got an error (other than row not found) during read + @retval 0 Row was found + @retval -1 Row was not found + @retval 1 Got an error (other than row not found) during read */ static int