From ff4d60489f07773fec58f8bbba09c1aedf1bc508 Mon Sep 17 00:00:00 2001 From: Rex Johnston Date: Tue, 22 Jul 2025 12:38:15 +1100 Subject: [PATCH] MDEV-29360 Crash when pushing condition with always false IS NULL into derived When a condition containing an always FALSE range part is pushed down into a derived table, an enclosed outer reference can cause a null pointer crash. An example SELECT * FROM (SELECT id FROM t1 GROUP BY id) dt1, (SELECT id FROM t2) dt2, t3 WHERE dt2.id = t3.id AND dt1.id BETWEEN 0 AND (dt2.id IS NULL); is considered as one that can be pushed into the derived table dt1 because the expression (dt2.id IS NULL) is identified as always false. On the on other hand the condition still contains a reference to a column of the table dt2. When pushing the condition to the where clause of the derived table dt1 a copy of it is created and this copy is transformed to be used in the new where clause. When the transformation procedure encounters a reference dt2.id it crashes the server as only the references to the columns used in the group by list of the specification of dt1 or those equal to them are expected in the condition that can be pushed into the where clause of the derived table. Based on patch by Igor Babaev. --- mysql-test/main/derived_cond_pushdown.result | 15 +++++++++++++++ mysql-test/main/derived_cond_pushdown.test | 15 +++++++++++++++ sql/item.cc | 7 ++++--- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/mysql-test/main/derived_cond_pushdown.result b/mysql-test/main/derived_cond_pushdown.result index 2824e3061d304..657245900622f 100644 --- a/mysql-test/main/derived_cond_pushdown.result +++ b/mysql-test/main/derived_cond_pushdown.result @@ -21784,4 +21784,19 @@ select * from v2 where greatest(a, default(a)); a count(*) drop view v2, v1; drop table t1; +# +# MDEV-29360 Crash when pushing condition with always false IS NULL +# into derived contains constant TRUE/FALSE as subformula +# +CREATE TABLE t1 (id int NOT NULL); +INSERT INTO t1 VALUES (0),(1),(3); +CREATE TABLE t2 SELECT * FROM t1; +CREATE TABLE t3 SELECT * FROM t1; +SELECT * FROM (SELECT id FROM t1 GROUP BY id) dt1, (SELECT id FROM t2) dt2, t3 +WHERE dt2.id = t3.id AND dt1.id BETWEEN 0 AND (dt2.id IS NULL); +id id id +0 0 0 +0 1 1 +0 3 3 +DROP TABLE t1,t2,t3; # End of 10.11 tests diff --git a/mysql-test/main/derived_cond_pushdown.test b/mysql-test/main/derived_cond_pushdown.test index f00cdde5df2c1..cea4e450492cf 100644 --- a/mysql-test/main/derived_cond_pushdown.test +++ b/mysql-test/main/derived_cond_pushdown.test @@ -4351,4 +4351,19 @@ select * from v2 where greatest(a, default(a)); drop view v2, v1; drop table t1; +--echo # +--echo # MDEV-29360 Crash when pushing condition with always false IS NULL +--echo # into derived contains constant TRUE/FALSE as subformula +--echo # + +CREATE TABLE t1 (id int NOT NULL); +INSERT INTO t1 VALUES (0),(1),(3); +CREATE TABLE t2 SELECT * FROM t1; +CREATE TABLE t3 SELECT * FROM t1; + +SELECT * FROM (SELECT id FROM t1 GROUP BY id) dt1, (SELECT id FROM t2) dt2, t3 + WHERE dt2.id = t3.id AND dt1.id BETWEEN 0 AND (dt2.id IS NULL); + +DROP TABLE t1,t2,t3; + --echo # End of 10.11 tests diff --git a/sql/item.cc b/sql/item.cc index a3ec31ceea8b0..3d8430258d1b9 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -8169,9 +8169,10 @@ Item_direct_view_ref::grouping_field_transformer_for_where(THD *thd, if (!item_equal) return this; st_select_lex *sel= (st_select_lex *)arg; - Field_pair *gr_field= find_matching_field_pair(this, - sel->grouping_tmp_fields); - return gr_field->corresponding_item->deep_copy_with_checks(thd); + if (Field_pair *gr_field= find_matching_field_pair(this, + sel->grouping_tmp_fields)) + return gr_field->corresponding_item->deep_copy_with_checks(thd); + return this; } void Item_field::print(String *str, enum_query_type query_type)