diff --git a/mysql-test/main/having_cond_pushdown.result b/mysql-test/main/having_cond_pushdown.result index 6b488c2b78812..7afb7e7fbaffc 100644 --- a/mysql-test/main/having_cond_pushdown.result +++ b/mysql-test/main/having_cond_pushdown.result @@ -6090,4 +6090,16 @@ EXPLAIN } } drop table t1, t2; +# +# MDEV-39916: Crash when pushing "NOT col" from HAVING into WHERE +# +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (0), (1); +SELECT a +FROM t1 +GROUP BY a +HAVING (NOT a) AND TRUE; +a +0 +DROP TABLE t1; # End of 10.11 tests diff --git a/mysql-test/main/having_cond_pushdown.test b/mysql-test/main/having_cond_pushdown.test index 507c5f15bfbf2..9452c8cba94c8 100644 --- a/mysql-test/main/having_cond_pushdown.test +++ b/mysql-test/main/having_cond_pushdown.test @@ -1657,4 +1657,18 @@ execute stmt; drop table t1, t2; +--echo # +--echo # MDEV-39916: Crash when pushing "NOT col" from HAVING into WHERE +--echo # + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (0), (1); + +SELECT a +FROM t1 +GROUP BY a +HAVING (NOT a) AND TRUE; + +DROP TABLE t1; + --echo # End of 10.11 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 5f2c471de7fba..cb04be003b31f 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -6676,7 +6676,9 @@ Item *Item_func_not::neg_transformer(THD *thd) /* NOT(x) -> x */ bool Item_func_not::fix_fields(THD *thd, Item **ref) { args[0]->under_not(this); - if (args[0]->type() == FIELD_ITEM) + if (args[0]->fix_fields_if_needed(thd, &args[0])) + return true; + if (args[0]->real_item()->type() == FIELD_ITEM) { /* replace "NOT " with " == 0" */ Query_arena backup, *arena; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 8a5b1a14bcca7..b0db02ab63f80 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -11574,7 +11574,7 @@ Item *st_select_lex::pushdown_from_having_into_where(THD *thd, Item *having) list of all its conjuncts saved in attach_to_conds. Otherwise, the condition is put into attach_to_conds as the only its element. */ - List_iterator_fast it(attach_to_conds); + List_iterator it(attach_to_conds); Item *item; check_cond_extraction_for_grouping_fields(thd, having); if (build_pushable_cond_for_having_pushdown(thd, having)) @@ -11638,8 +11638,9 @@ Item *st_select_lex::pushdown_from_having_into_where(THD *thd, Item *having) &Item::field_transformer_for_having_pushdown, (uchar *)this); - if (item->walk(&Item::cleanup_excluding_immutables_processor, 0, STOP_PTR) - || item->fix_fields(thd, NULL)) + if (item->walk(&Item::cleanup_excluding_immutables_processor, 0, + STOP_PTR) || + item->fix_fields(thd, it.ref())) { attach_to_conds.empty(); goto exit; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 8f8d6ce092737..0eea5ae771245 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1180,7 +1180,13 @@ class st_select_lex: public st_select_lex_node /* List of references to fields referenced from inner selects */ List inner_refs_list; + + /* + Pushdown from HAVING into WHERE optimization: conditions from the HAVING + clause that should be added into the WHERE. + */ List attach_to_conds; + /* Saved values of the WHERE and HAVING clauses*/ Item::cond_result cond_value, having_value; /*