From b4712242dd6d2a50ebe3eb01d22a076820c6a65e Mon Sep 17 00:00:00 2001 From: Rex Date: Wed, 11 Oct 2023 15:05:58 +1200 Subject: [PATCH] MDEV-31279 Crash when lateral derived is guaranteed to return no rows Consider this query SELECT t1.* FROM t1, (SELECT t2.b FROM t2 WHERE NOT EXISTS (SELECT 1 FROM t3) GROUP BY b) sq where sq.b = t1.a; If SELECT 1 FROM t3 is expensive, for example t3 has > thd->variables.expensive_subquery_limit, first evaluation is deferred to mysql_derived_fill(). There it is noted that, in the above case NOT EXISTS (SELECT 1 FROM t3) is constant and false. This causes the join variable zero_result_cause to be set to "Impossible WHERE noticed after reading const tables" and the handler for this join is never "opened" via handler::ha_open. When mysql_derived_fill() is called for the next group of results, this unopened handler is not taken into account. reviewed by Igor Babaev (igor@mariadb.com) --- mysql-test/main/derived_split_innodb.result | 15 +++++++++++++++ mysql-test/main/derived_split_innodb.test | 18 ++++++++++++++++++ sql/sql_derived.cc | 3 +++ 3 files changed, 36 insertions(+) diff --git a/mysql-test/main/derived_split_innodb.result b/mysql-test/main/derived_split_innodb.result index 22974251c56..91241627b73 100644 --- a/mysql-test/main/derived_split_innodb.result +++ b/mysql-test/main/derived_split_innodb.result @@ -826,4 +826,19 @@ SELECT * FROM t1 JOIN t2 WHERE (t1.a, t2.b) IN (SELECT * FROM v); a b DROP VIEW v; DROP TABLE t1, t2, t3; +# +# MDEV-31279 Crash when lateral derived is guaranteed to return no rows +# +CREATE TABLE t1 (a CHAR(1)) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('1'),('2'); +CREATE TABLE t2 (b INT, KEY(b)) ENGINE=MyISAM; +ALTER TABLE t2 DISABLE KEYS; +INSERT INTO t2 VALUES (1),(2),(3); +ALTER TABLE t2 ENABLE KEYS; +CREATE TABLE t3 (c INT) ENGINE=MyISAM; +INSERT INTO t3 (c) SELECT seq FROM seq_1_to_101; +SELECT * FROM t1 WHERE t1.a IN (SELECT b FROM +(SELECT t2.b FROM t2 WHERE NOT EXISTS (SELECT 1 FROM t3) GROUP BY b) sq); +a +DROP TABLE t1, t2, t3; # End of 10.4 tests diff --git a/mysql-test/main/derived_split_innodb.test b/mysql-test/main/derived_split_innodb.test index 3c51f54fe02..e2f41a17994 100644 --- a/mysql-test/main/derived_split_innodb.test +++ b/mysql-test/main/derived_split_innodb.test @@ -483,4 +483,22 @@ SELECT * FROM t1 JOIN t2 WHERE (t1.a, t2.b) IN (SELECT * FROM v); DROP VIEW v; DROP TABLE t1, t2, t3; +--echo # +--echo # MDEV-31279 Crash when lateral derived is guaranteed to return no rows +--echo # + +CREATE TABLE t1 (a CHAR(1)) ENGINE=MyISAM; +INSERT INTO t1 VALUES ('1'),('2'); +CREATE TABLE t2 (b INT, KEY(b)) ENGINE=MyISAM; +ALTER TABLE t2 DISABLE KEYS; +INSERT INTO t2 VALUES (1),(2),(3); +ALTER TABLE t2 ENABLE KEYS; +CREATE TABLE t3 (c INT) ENGINE=MyISAM; +INSERT INTO t3 (c) SELECT seq FROM seq_1_to_101; + +SELECT * FROM t1 WHERE t1.a IN (SELECT b FROM + (SELECT t2.b FROM t2 WHERE NOT EXISTS (SELECT 1 FROM t3) GROUP BY b) sq); + +DROP TABLE t1, t2, t3; + --echo # End of 10.4 tests diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 54ef1c3a59f..782894444df 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -1227,6 +1227,9 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived) goto err; JOIN *join= unit->first_select()->join; join->first_record= false; + if (join->zero_result_cause) + goto err; + for (uint i= join->top_join_tab_count; i < join->top_join_tab_count + join->aggr_tables; i++)