diff --git a/mysql-test/main/derived_cond_pushdown.result b/mysql-test/main/derived_cond_pushdown.result index a13ce8575de..54068c4d6dd 100644 --- a/mysql-test/main/derived_cond_pushdown.result +++ b/mysql-test/main/derived_cond_pushdown.result @@ -8218,12 +8218,10 @@ EXPLAIN "query_block": { "select_id": 1, "table": { - "table_name": "", - "access_type": "system", - "rows": 1, - "filtered": 100, - "materialized": { - "unique": 1, + "message": "Impossible WHERE" + }, + "subqueries": [ + { "query_block": { "select_id": 2, "table": { @@ -8231,26 +8229,7 @@ EXPLAIN } } } - }, - "table": { - "table_name": "", - "access_type": "ALL", - "rows": 2, - "filtered": 100, - "attached_condition": "v1.c = NULL", - "materialized": { - "query_block": { - "select_id": 3, - "table": { - "table_name": "t1", - "access_type": "ALL", - "rows": 2, - "filtered": 100, - "attached_condition": "t1.c = NULL" - } - } - } - } + ] } } DROP VIEW v1; diff --git a/mysql-test/main/having.result b/mysql-test/main/having.result index dd710db715a..837940a55ef 100644 --- a/mysql-test/main/having.result +++ b/mysql-test/main/having.result @@ -483,7 +483,7 @@ HAVING (table2.f2 = 8); id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables Warnings: -Note 1003 select `test`.`table1`.`f1` AS `f1`,7 AS `f2` from `test`.`t1` `table1` join `test`.`t1` `table2` where 0 group by `test`.`table1`.`f1`,7 having multiple equal(8, 7) +Note 1003 select `test`.`table1`.`f1` AS `f1`,7 AS `f2` from `test`.`t1` `table1` join `test`.`t1` `table2` where 0 group by `test`.`table1`.`f1`,7 having 1 DROP TABLE t1; # # Bug#52336 Segfault / crash in 5.1 copy_fields (param=0x9872980) at sql_select.cc:15355 diff --git a/mysql-test/main/having_cond_pushdown.result b/mysql-test/main/having_cond_pushdown.result index ef7368bd1fb..bec2a937e38 100644 --- a/mysql-test/main/having_cond_pushdown.result +++ b/mysql-test/main/having_cond_pushdown.result @@ -1596,7 +1596,7 @@ EXPLAIN "access_type": "ALL", "rows": 5, "filtered": 100, - "attached_condition": "t1.a > 1 and t1.c = t1.a or t1.a < 3" + "attached_condition": "t1.c = t1.a and t1.a > 1 or t1.a < 3" } } } @@ -1918,3 +1918,2710 @@ SELECT a FROM t1 WHERE b = 1 AND b = 2 GROUP BY a HAVING a <= 3; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE DROP TABLE t1; +# +# MDEV-18769: unfixed OR condition pushed from HAVING into WHERE +# +CREATE TABLE t1(a INT, b INT, c INT); +CREATE TABLE t3(a INT, b INT, c INT, d INT); +INSERT INTO t1 VALUES (1,14,3), (2,13,2), (1,22,1), (3,13,4), (3,14,2); +INSERT INTO t3 VALUES (1,2,16,1), (1,3,11,2), (2,3,10,2); +# nothing to push +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a +HAVING t1.b = 13 AND MAX(t1.c) > 2; +a b MAX(t1.c) +3 13 4 +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a +HAVING t1.b = 13 AND MAX(t1.c) > 2; +a b MAX(t1.c) +3 13 4 +explain SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a +HAVING t1.b = 13 AND MAX(t1.c) > 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using temporary; Using filesort +explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a +HAVING t1.b = 13 AND MAX(t1.c) > 2; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "having_condition": "t1.b = 13 and max(t1.c) > 2", + "filesort": { + "sort_key": "t1.a", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100 + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a +HAVING t1.b = 13 AND MAX(t1.c) > 2; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "having_condition": "t1.b = 13 and max(t1.c) > 2", + "filesort": { + "sort_key": "t1.a", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100 + } + } + } + } +} +# extracted AND formula +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a = 1 OR t1.b > 10) AND (t1.b < 14); +a b MAX(t1.c) +2 13 2 +3 13 4 +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a = 1 OR t1.b > 10) AND (t1.b < 14); +a b MAX(t1.c) +2 13 2 +3 13 4 +explain SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a = 1 OR t1.b > 10) AND (t1.b < 14); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort +explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a = 1 OR t1.b > 10) AND (t1.b < 14); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a, t1.b", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "(t1.a = 1 or t1.b > 10) and t1.b < 14" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.a = 1 OR t1.b > 10) AND (t1.b < 14) +GROUP BY t1.a,t1.b; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a, t1.b", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "(t1.a = 1 or t1.b > 10) and t1.b < 14" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a = 1 OR t1.b > 10) AND (t1.b < 14 OR t1.b > 15); +a b MAX(t1.c) +1 22 1 +2 13 2 +3 13 4 +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a = 1 OR t1.b > 10) AND (t1.b < 14 OR t1.b > 15); +a b MAX(t1.c) +1 22 1 +2 13 2 +3 13 4 +explain SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a = 1 OR t1.b > 10) AND (t1.b < 14 OR t1.b > 15); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort +explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a = 1 OR t1.b > 10) AND (t1.b < 14 OR t1.b > 15); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a, t1.b", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "(t1.a = 1 or t1.b > 10) and (t1.b < 14 or t1.b > 15)" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.a = 1 OR t1.b > 10) AND (t1.b < 14 OR t1.b > 15) +GROUP BY t1.a,t1.b; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a, t1.b", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "(t1.a = 1 or t1.b > 10) and (t1.b < 14 or t1.b > 15)" + } + } + } + } +} +# extracted AND formula : equality in the inner AND formula +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a = 1 OR t1.b > 10) AND (t1.b < 14 OR (t1.b > 15 AND t1.a = 2)); +a b MAX(t1.c) +2 13 2 +3 13 4 +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a = 1 OR t1.b > 10) AND (t1.b < 14 OR (t1.b > 15 AND t1.a = 2)); +a b MAX(t1.c) +2 13 2 +3 13 4 +explain SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a = 1 OR t1.b > 10) AND (t1.b < 14 OR (t1.b > 15 AND t1.a = 2)); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort +explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a = 1 OR t1.b > 10) AND (t1.b < 14 OR (t1.b > 15 AND t1.a = 2)); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a, t1.b", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "(t1.a = 1 or t1.b > 10) and (t1.b < 14 or t1.a = 2 and t1.b > 15)" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.a = 1 OR t1.b > 10) AND (t1.b < 14 OR (t1.b > 15 AND t1.a = 2)) +GROUP BY t1.a,t1.b; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a, t1.b", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "(t1.a = 1 or t1.b > 10) and (t1.b < 14 or t1.a = 2 and t1.b > 15)" + } + } + } + } +} +# extracted OR formula +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a < 2) OR (t1.b = 13 AND t1.a > 2); +a b MAX(t1.c) +1 14 3 +1 22 1 +3 13 4 +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a < 2) OR (t1.b = 13 AND t1.a > 2); +a b MAX(t1.c) +1 14 3 +1 22 1 +3 13 4 +explain SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a < 2) OR (t1.b = 13 AND t1.a > 2); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort +explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a < 2) OR (t1.b = 13 AND t1.a > 2); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a, t1.b", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a < 2 or t1.b = 13 and t1.a > 2" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.a < 2) OR (t1.b = 13 AND t1.a > 2) +GROUP BY t1.a,t1.b; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a, t1.b", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a < 2 or t1.b = 13 and t1.a > 2" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a < 2 AND t1.b = 14) OR (t1.a > 2 AND t1.b = 13); +a b MAX(t1.c) +1 14 3 +3 13 4 +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a < 2 AND t1.b = 14) OR (t1.a > 2 AND t1.b = 13); +a b MAX(t1.c) +1 14 3 +3 13 4 +explain SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a < 2 AND t1.b = 14) OR (t1.a > 2 AND t1.b = 13); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort +explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a < 2 AND t1.b = 14) OR (t1.a > 2 AND t1.b = 13); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a, t1.b", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.b = 14 and t1.a < 2 or t1.b = 13 and t1.a > 2" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.a < 2 AND t1.b = 14) OR (t1.a > 2 AND t1.b = 13) +GROUP BY t1.a,t1.b; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a, t1.b", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.b = 14 and t1.a < 2 or t1.b = 13 and t1.a > 2" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a < 2 AND t1.b = 14) OR (t1.a > 2 AND (t1.b = 13 OR t1.b = 14)); +a b MAX(t1.c) +1 14 3 +3 13 4 +3 14 2 +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a < 2 AND t1.b = 14) OR (t1.a > 2 AND (t1.b = 13 OR t1.b = 14)); +a b MAX(t1.c) +1 14 3 +3 13 4 +3 14 2 +explain SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a < 2 AND t1.b = 14) OR (t1.a > 2 AND (t1.b = 13 OR t1.b = 14)); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort +explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a < 2 AND t1.b = 14) OR (t1.a > 2 AND (t1.b = 13 OR t1.b = 14)); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a, t1.b", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.b = 14 and t1.a < 2 or t1.a > 2 and (t1.b = 13 or t1.b = 14)" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.a < 2 AND t1.b = 14) OR (t1.a > 2 AND (t1.b = 13 OR t1.b = 14)) +GROUP BY t1.a,t1.b; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a, t1.b", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.b = 14 and t1.a < 2 or t1.a > 2 and (t1.b = 13 or t1.b = 14)" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a +HAVING (t1.a < 2 AND MAX(t1.c) = 2) OR (MAX(t1.c) > 2 AND (t1.a = 1 OR t1.a = 2)); +a b MAX(t1.c) +1 14 3 +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a +HAVING (t1.a < 2 AND MAX(t1.c) = 2) OR (MAX(t1.c) > 2 AND (t1.a = 1 OR t1.a = 2)); +a b MAX(t1.c) +1 14 3 +explain SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a +HAVING (t1.a < 2 AND MAX(t1.c) = 2) OR (MAX(t1.c) > 2 AND (t1.a = 1 OR t1.a = 2)); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort +explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a +HAVING (t1.a < 2 AND MAX(t1.c) = 2) OR (MAX(t1.c) > 2 AND (t1.a = 1 OR t1.a = 2)); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "having_condition": "t1.a < 2 and max(t1.c) = 2 or max(t1.c) > 2 and (t1.a = 1 or t1.a = 2)", + "filesort": { + "sort_key": "t1.a", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a < 2 or t1.a = 1 or t1.a = 2" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.a < 2) OR (t1.a = 1 OR t1.a = 2) +GROUP BY t1.a +HAVING (t1.a < 2 AND MAX(t1.c) = 2) OR (MAX(t1.c) > 2 AND (t1.a = 1 OR t1.a = 2)); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "having_condition": "t1.a < 2 and max(t1.c) = 2 or max(t1.c) > 2 and (t1.a = 1 or t1.a = 2)", + "filesort": { + "sort_key": "t1.a", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a < 2 or t1.a = 1 or t1.a = 2" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a +HAVING (t1.a = 2 AND MAX(t1.c) = 2) OR (MAX(t1.c) > 2 AND (t1.a = 1 OR t1.a = 2)); +a b MAX(t1.c) +1 14 3 +2 13 2 +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a +HAVING (t1.a = 2 AND MAX(t1.c) = 2) OR (MAX(t1.c) > 2 AND (t1.a = 1 OR t1.a = 2)); +a b MAX(t1.c) +1 14 3 +2 13 2 +explain SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a +HAVING (t1.a = 2 AND MAX(t1.c) = 2) OR (MAX(t1.c) > 2 AND (t1.a = 1 OR t1.a = 2)); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort +explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a +HAVING (t1.a = 2 AND MAX(t1.c) = 2) OR (MAX(t1.c) > 2 AND (t1.a = 1 OR t1.a = 2)); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "having_condition": "t1.a = 2 and max(t1.c) = 2 or max(t1.c) > 2 and (t1.a = 1 or t1.a = 2)", + "filesort": { + "sort_key": "t1.a", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 2 or t1.a = 1 or t1.a = 2" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.a = 2) OR (t1.a = 1 OR t1.a = 2) +GROUP BY t1.a +HAVING (t1.a = 2 AND MAX(t1.c) = 2) OR (MAX(t1.c) > 2 AND (t1.a = 1 OR t1.a = 2)); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "having_condition": "t1.a = 2 and max(t1.c) = 2 or max(t1.c) > 2 and (t1.a = 1 or t1.a = 2)", + "filesort": { + "sort_key": "t1.a", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 2 or t1.a = 1 or t1.a = 2" + } + } + } + } +} +# conjunctive subformula : equality pushdown +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a +HAVING (t1.a = 1) AND (MAX(t1.c) = 3); +a b MAX(t1.c) +1 14 3 +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a +HAVING (t1.a = 1) AND (MAX(t1.c) = 3); +a b MAX(t1.c) +1 14 3 +explain SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a +HAVING (t1.a = 1) AND (MAX(t1.c) = 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where +explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a +HAVING (t1.a = 1) AND (MAX(t1.c) = 3); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "having_condition": "max(t1.c) = 3", + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 1" + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.a = 1) +GROUP BY t1.a +HAVING (MAX(t1.c) = 3); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "having_condition": "max(t1.c) = 3", + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 1" + } + } +} +# conjunctive subformula : equalities pushdown +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.c +HAVING (t1.a = 1) AND (t1.c = 3) AND MAX(t1.b = 14); +a b MAX(t1.c) +1 14 3 +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.c +HAVING (t1.a = 1) AND (t1.c = 3) AND MAX(t1.b = 14); +a b MAX(t1.c) +1 14 3 +explain SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.c +HAVING (t1.a = 1) AND (t1.c = 3) AND MAX(t1.b = 14); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where +explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.c +HAVING (t1.a = 1) AND (t1.c = 3) AND MAX(t1.b = 14); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "having_condition": "max(t1.b = 14)", + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 1 and t1.c = 3" + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.a = 1) AND (t1.c = 3) +GROUP BY t1.a,t1.c +HAVING (MAX(t1.b) = 14); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "having_condition": "max(t1.b) = 14", + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 1 and t1.c = 3" + } + } +} +# conjunctive subformula : multiple equality consists of +two equalities pushdown +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.c +HAVING (t1.a = 1) AND (t1.c = 1) AND MAX(t1.b = 14); +a b MAX(t1.c) +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.c +HAVING (t1.a = 1) AND (t1.c = 1) AND MAX(t1.b = 14); +a b MAX(t1.c) +explain SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.c +HAVING (t1.a = 1) AND (t1.c = 1) AND MAX(t1.b = 14); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where +explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.c +HAVING (t1.a = 1) AND (t1.c = 1) AND MAX(t1.b = 14); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "having_condition": "max(t1.b = 14)", + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 1 and t1.c = 1" + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.a = 1) AND (t1.c = 1) +GROUP BY t1.a,t1.c +HAVING (MAX(t1.b) = 14); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "having_condition": "max(t1.b) = 14", + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 1 and t1.c = 1" + } + } +} +# +# Pushdown from HAVING into non-empty WHERE +# +# inequality : inequality in WHERE +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b > 2) +GROUP BY t1.a +HAVING (t1.a < 3); +a b MAX(t1.c) +1 14 3 +2 13 2 +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b > 2) +GROUP BY t1.a +HAVING (t1.a < 3); +a b MAX(t1.c) +1 14 3 +2 13 2 +explain SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b > 2) +GROUP BY t1.a +HAVING (t1.a < 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort +explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b > 2) +GROUP BY t1.a +HAVING (t1.a < 3); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.b > 2 and t1.a < 3" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b > 2) AND (t1.a < 3) +GROUP BY t1.a; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.b > 2 and t1.a < 3" + } + } + } + } +} +# equality : inequality in WHERE +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b > 2) +GROUP BY t1.a +HAVING (t1.a = 3); +a b MAX(t1.c) +3 13 4 +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b > 2) +GROUP BY t1.a +HAVING (t1.a = 3); +a b MAX(t1.c) +3 13 4 +explain SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b > 2) +GROUP BY t1.a +HAVING (t1.a = 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where +explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b > 2) +GROUP BY t1.a +HAVING (t1.a = 3); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 3 and t1.b > 2" + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b > 2) AND (t1.a = 3) +GROUP BY t1.a; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 3 and t1.b > 2" + } + } +} +# inequality : equality in WHERE +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b = 14) +GROUP BY t1.a +HAVING (t1.a < 3); +a b MAX(t1.c) +1 14 3 +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b = 14) +GROUP BY t1.a +HAVING (t1.a < 3); +a b MAX(t1.c) +1 14 3 +explain SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b = 14) +GROUP BY t1.a +HAVING (t1.a < 3); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort +explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b = 14) +GROUP BY t1.a +HAVING (t1.a < 3); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.b = 14 and t1.a < 3" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b = 14) AND (t1.a < 3) +GROUP BY t1.a; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.b = 14 and t1.a < 3" + } + } + } + } +} +# equality : equality in WHERE +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b = 14) +GROUP BY t1.a +HAVING (t1.a = 1); +a b MAX(t1.c) +1 14 3 +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b = 14) +GROUP BY t1.a +HAVING (t1.a = 1); +a b MAX(t1.c) +1 14 3 +explain SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b = 14) +GROUP BY t1.a +HAVING (t1.a = 1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where +explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b = 14) +GROUP BY t1.a +HAVING (t1.a = 1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 1 and t1.b = 14" + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b = 14) AND (t1.a = 1) +GROUP BY t1.a; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.b = 14 and t1.a = 1" + } + } +} +# equality : equality in WHERE, impossible WHERE +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,MAX(t1.c) +FROM t1 +WHERE (t1.a = 3) +GROUP BY t1.a +HAVING (t1.a = 1); +a MAX(t1.c) +SELECT t1.a,MAX(t1.c) +FROM t1 +WHERE (t1.a = 3) +GROUP BY t1.a +HAVING (t1.a = 1); +a MAX(t1.c) +explain SELECT t1.a,MAX(t1.c) +FROM t1 +WHERE (t1.a = 3) +GROUP BY t1.a +HAVING (t1.a = 1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +explain format=json SELECT t1.a,MAX(t1.c) +FROM t1 +WHERE (t1.a = 3) +GROUP BY t1.a +HAVING (t1.a = 1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "message": "Impossible WHERE" + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,MAX(t1.c) +FROM t1 +WHERE (t1.a = 3) AND (t1.a = 1) +GROUP BY t1.a; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "message": "Impossible WHERE" + } + } +} +# equality : equality in WHERE (equal through constant) +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.c = 1) +GROUP BY t1.a +HAVING (t1.a = 1); +a MAX(t1.b) c +1 22 1 +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.c = 1) +GROUP BY t1.a +HAVING (t1.a = 1); +a MAX(t1.b) c +1 22 1 +explain SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.c = 1) +GROUP BY t1.a +HAVING (t1.a = 1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where +explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.c = 1) +GROUP BY t1.a +HAVING (t1.a = 1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 1 and t1.c = 1" + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.c = 1) AND (t1.a = 1) +GROUP BY t1.a; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.c = 1 and t1.a = 1" + } + } +} +# inequality : AND formula in WHERE +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.c > 0) AND (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a > 1); +a MAX(t1.b) c +2 13 2 +3 14 2 +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.c > 0) AND (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a > 1); +a MAX(t1.b) c +2 13 2 +3 14 2 +explain SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.c > 0) AND (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a > 1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort +explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.c > 0) AND (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a > 1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.c > 0 and t1.c < 3 and t1.a > 1" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.c > 0) AND (t1.c < 3) AND (t1.a > 1) +GROUP BY t1.a; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.c > 0 and t1.c < 3 and t1.a > 1" + } + } + } + } +} +# equality : AND formula in WHERE +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.c > 0) AND (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a = 1); +a MAX(t1.b) c +1 22 1 +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.c > 0) AND (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a = 1); +a MAX(t1.b) c +1 22 1 +explain SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.c > 0) AND (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a = 1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where +explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.c > 0) AND (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a = 1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 1 and t1.c > 0 and t1.c < 3" + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.c > 0) AND (t1.c < 3) AND (t1.a = 1) +GROUP BY t1.a; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 1 and t1.c > 0 and t1.c < 3" + } + } +} +# equality : AND formula in WHERE, impossible WHERE +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 0) AND (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a = 1); +a MAX(t1.b) c +1 22 1 +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 0) AND (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a = 1); +a MAX(t1.b) c +1 22 1 +explain SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 0) AND (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a = 1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where +explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 0) AND (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a = 1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "const_condition": "1", + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 1 and t1.c < 3" + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 0) AND (t1.c < 3) AND (t1.a = 1) +GROUP BY t1.a; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 1 and t1.c < 3" + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,MAX(t1.b) +FROM t1 +WHERE (t1.a = 0) AND (t1.a = 3) +GROUP BY t1.a +HAVING (t1.a = 1); +a MAX(t1.b) +SELECT t1.a,MAX(t1.b) +FROM t1 +WHERE (t1.a = 0) AND (t1.a = 3) +GROUP BY t1.a +HAVING (t1.a = 1); +a MAX(t1.b) +explain SELECT t1.a,MAX(t1.b) +FROM t1 +WHERE (t1.a = 0) AND (t1.a = 3) +GROUP BY t1.a +HAVING (t1.a = 1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +explain format=json SELECT t1.a,MAX(t1.b) +FROM t1 +WHERE (t1.a = 0) AND (t1.a = 3) +GROUP BY t1.a +HAVING (t1.a = 1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "message": "Impossible WHERE" + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,MAX(t1.b) +FROM t1 +WHERE (t1.a = 0) AND (t1.a = 3) AND (t1.a = 1) +GROUP BY t1.a; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "message": "Impossible WHERE" + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t3.a,t3.b,MAX(t3.c),t3.d +FROM t3 +WHERE (t3.b = 2) AND (t3.d = 1) +GROUP BY t3.a,t3.b,t3.d +HAVING (t3.a = 1); +a b MAX(t3.c) d +1 2 16 1 +SELECT t3.a,t3.b,MAX(t3.c),t3.d +FROM t3 +WHERE (t3.b = 2) AND (t3.d = 1) +GROUP BY t3.a,t3.b,t3.d +HAVING (t3.a = 1); +a b MAX(t3.c) d +1 2 16 1 +explain SELECT t3.a,t3.b,MAX(t3.c),t3.d +FROM t3 +WHERE (t3.b = 2) AND (t3.d = 1) +GROUP BY t3.a,t3.b,t3.d +HAVING (t3.a = 1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 ALL NULL NULL NULL NULL 3 Using where +explain format=json SELECT t3.a,t3.b,MAX(t3.c),t3.d +FROM t3 +WHERE (t3.b = 2) AND (t3.d = 1) +GROUP BY t3.a,t3.b,t3.d +HAVING (t3.a = 1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t3", + "access_type": "ALL", + "rows": 3, + "filtered": 100, + "attached_condition": "t3.b = 2 and t3.d = 1 and t3.a = 1" + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t3.a,t3.b,MAX(t3.c),t3.d +FROM t3 +WHERE (t3.b = 2) AND (t3.d = 1) AND (t3.a = 1) +GROUP BY t3.a,t3.b,t3.d; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t3", + "access_type": "ALL", + "rows": 3, + "filtered": 100, + "attached_condition": "t3.b = 2 and t3.d = 1 and t3.a = 1" + } + } +} +# inequality : OR formula in WHERE +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) OR (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a < 2); +a MAX(t1.b) c +1 22 1 +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) OR (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a < 2); +a MAX(t1.b) c +1 22 1 +explain SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) OR (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a < 2); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort +explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) OR (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a < 2); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "(t1.a > 1 or t1.c < 3) and t1.a < 2" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE ((t1.a > 1) OR (t1.c < 3)) AND (t1.a < 2) +GROUP BY t1.a; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "(t1.a > 1 or t1.c < 3) and t1.a < 2" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,MAX(t1.b) +FROM t1 +WHERE (t1.a = 1) OR (t1.a = 3) +GROUP BY t1.a +HAVING (t1.a = 2); +a MAX(t1.b) +SELECT t1.a,MAX(t1.b) +FROM t1 +WHERE (t1.a = 1) OR (t1.a = 3) +GROUP BY t1.a +HAVING (t1.a = 2); +a MAX(t1.b) +explain SELECT t1.a,MAX(t1.b) +FROM t1 +WHERE (t1.a = 1) OR (t1.a = 3) +GROUP BY t1.a +HAVING (t1.a = 2); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +explain format=json SELECT t1.a,MAX(t1.b) +FROM t1 +WHERE (t1.a = 1) OR (t1.a = 3) +GROUP BY t1.a +HAVING (t1.a = 2); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "message": "Impossible WHERE" + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,MAX(t1.b) +FROM t1 +WHERE ((t1.a = 1) OR (t1.a = 3)) AND (t1.a = 2) +GROUP BY t1.a; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "message": "Impossible WHERE" + } + } +} +# AND formula : inequality in WHERE +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) +GROUP BY t1.a +HAVING (t1.a < 4) AND (t1.a > 0); +a MAX(t1.b) c +2 13 2 +3 14 4 +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) +GROUP BY t1.a +HAVING (t1.a < 4) AND (t1.a > 0); +a MAX(t1.b) c +2 13 2 +3 14 4 +explain SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) +GROUP BY t1.a +HAVING (t1.a < 4) AND (t1.a > 0); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort +explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) +GROUP BY t1.a +HAVING (t1.a < 4) AND (t1.a > 0); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a > 1 and t1.a < 4 and t1.a > 0" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) AND (t1.a < 4) AND (t1.a > 0) +GROUP BY t1.a; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a > 1 and t1.a < 4 and t1.a > 0" + } + } + } + } +} +# AND formula : equality in WHERE +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) +GROUP BY t1.a +HAVING (t1.a < 4) AND (t1.a > 0); +a MAX(t1.b) c +1 22 3 +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) +GROUP BY t1.a +HAVING (t1.a < 4) AND (t1.a > 0); +a MAX(t1.b) c +1 22 3 +explain SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) +GROUP BY t1.a +HAVING (t1.a < 4) AND (t1.a > 0); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where +explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) +GROUP BY t1.a +HAVING (t1.a < 4) AND (t1.a > 0); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "const_condition": "1 and 1", + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 1" + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.a < 4) AND (t1.a > 0) +GROUP BY t1.a; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 1" + } + } +} +# OR formula : inequality in WHERE +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) +GROUP BY t1.a +HAVING (t1.a < 4) OR (t1.a > 0); +a MAX(t1.b) c +2 13 2 +3 14 4 +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) +GROUP BY t1.a +HAVING (t1.a < 4) OR (t1.a > 0); +a MAX(t1.b) c +2 13 2 +3 14 4 +explain SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) +GROUP BY t1.a +HAVING (t1.a < 4) OR (t1.a > 0); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort +explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) +GROUP BY t1.a +HAVING (t1.a < 4) OR (t1.a > 0); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a > 1 and (t1.a < 4 or t1.a > 0)" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) AND ((t1.a < 4) OR (t1.a > 0)) +GROUP BY t1.a; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a > 1 and (t1.a < 4 or t1.a > 0)" + } + } + } + } +} +# OR formula : equality in WHERE +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) +GROUP BY t1.a +HAVING (t1.a < 4) OR (t1.a > 0); +a MAX(t1.b) c +1 22 3 +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) +GROUP BY t1.a +HAVING (t1.a < 4) OR (t1.a > 0); +a MAX(t1.b) c +1 22 3 +explain SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) +GROUP BY t1.a +HAVING (t1.a < 4) OR (t1.a > 0); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where +explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) +GROUP BY t1.a +HAVING (t1.a < 4) OR (t1.a > 0); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "const_condition": "1", + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 1" + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND ((t1.a < 4) OR (t1.a > 0)) +GROUP BY t1.a; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 1" + } + } +} +# AND formula : AND formula in WHERE +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) AND (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a < 4) AND (t1.c > 1); +a MAX(t1.b) c +2 13 2 +3 14 2 +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) AND (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a < 4) AND (t1.c > 1); +a MAX(t1.b) c +2 13 2 +3 14 2 +explain SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) AND (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a < 4) AND (t1.c > 1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort +explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) AND (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a < 4) AND (t1.c > 1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "having_condition": "t1.c > 1", + "filesort": { + "sort_key": "t1.a", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a > 1 and t1.c < 3 and t1.a < 4" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE ((t1.a > 1) AND (t1.c < 3)) AND +(t1.a < 4) +GROUP BY t1.a +HAVING (t1.c > 1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "having_condition": "t1.c > 1", + "filesort": { + "sort_key": "t1.a", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a > 1 and t1.c < 3 and t1.a < 4" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.c < 3) +GROUP BY t1.a,t1.c +HAVING (t1.a < 4) AND (t1.c > 1); +a MAX(t1.b) c +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.c < 3) +GROUP BY t1.a,t1.c +HAVING (t1.a < 4) AND (t1.c > 1); +a MAX(t1.b) c +explain SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.c < 3) +GROUP BY t1.a,t1.c +HAVING (t1.a < 4) AND (t1.c > 1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort +explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.c < 3) +GROUP BY t1.a,t1.c +HAVING (t1.a < 4) AND (t1.c > 1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "const_condition": "1", + "filesort": { + "sort_key": "t1.c", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 1 and t1.c < 3 and t1.c > 1" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE ((t1.a = 1) AND (t1.c < 3)) AND +((t1.a < 4) AND (t1.c > 1)) +GROUP BY t1.a,t1.c; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.c", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 1 and t1.c < 3 and t1.c > 1" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.c = 3) +GROUP BY t1.a,t1.c +HAVING (t1.a < 4) AND (t1.c > 1); +a MAX(t1.b) c +1 14 3 +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.c = 3) +GROUP BY t1.a,t1.c +HAVING (t1.a < 4) AND (t1.c > 1); +a MAX(t1.b) c +1 14 3 +explain SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.c = 3) +GROUP BY t1.a,t1.c +HAVING (t1.a < 4) AND (t1.c > 1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where +explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.c = 3) +GROUP BY t1.a,t1.c +HAVING (t1.a < 4) AND (t1.c > 1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "const_condition": "1 and 1", + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 1 and t1.c = 3" + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE ((t1.a = 1) AND (t1.c = 3)) AND +((t1.a < 4) AND (t1.c > 1)) +GROUP BY t1.a,t1.c; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 1 and t1.c = 3" + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t3.a,t3.b,MAX(t3.c),t3.d +FROM t3 +WHERE (t3.a = 1) AND (t3.d = 1) +GROUP BY t3.a,t3.b +HAVING (t3.b = 2) AND (t3.d > 0); +a b MAX(t3.c) d +1 2 16 1 +SELECT t3.a,t3.b,MAX(t3.c),t3.d +FROM t3 +WHERE (t3.a = 1) AND (t3.d = 1) +GROUP BY t3.a,t3.b +HAVING (t3.b = 2) AND (t3.d > 0); +a b MAX(t3.c) d +1 2 16 1 +explain SELECT t3.a,t3.b,MAX(t3.c),t3.d +FROM t3 +WHERE (t3.a = 1) AND (t3.d = 1) +GROUP BY t3.a,t3.b +HAVING (t3.b = 2) AND (t3.d > 0); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 ALL NULL NULL NULL NULL 3 Using where +explain format=json SELECT t3.a,t3.b,MAX(t3.c),t3.d +FROM t3 +WHERE (t3.a = 1) AND (t3.d = 1) +GROUP BY t3.a,t3.b +HAVING (t3.b = 2) AND (t3.d > 0); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "having_condition": "t3.d > 0", + "table": { + "table_name": "t3", + "access_type": "ALL", + "rows": 3, + "filtered": 100, + "attached_condition": "t3.a = 1 and t3.d = 1 and t3.b = 2" + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t3.a,t3.b,MAX(t3.c),t3.d +FROM t3 +WHERE (t3.a = 1) AND (t3.d = 1) AND +(t3.b = 2) +GROUP BY t3.a,t3.b +HAVING (t3.d > 0); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "having_condition": "t3.d > 0", + "table": { + "table_name": "t3", + "access_type": "ALL", + "rows": 3, + "filtered": 100, + "attached_condition": "t3.a = 1 and t3.d = 1 and t3.b = 2" + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t3.a,t3.b,MAX(t3.c),t3.d +FROM t3 +WHERE (t3.a = 1) AND (t3.d = 1) +GROUP BY t3.a,t3.b,t3.d +HAVING (t3.b = 2) AND (t3.d > 0); +a b MAX(t3.c) d +1 2 16 1 +SELECT t3.a,t3.b,MAX(t3.c),t3.d +FROM t3 +WHERE (t3.a = 1) AND (t3.d = 1) +GROUP BY t3.a,t3.b,t3.d +HAVING (t3.b = 2) AND (t3.d > 0); +a b MAX(t3.c) d +1 2 16 1 +explain SELECT t3.a,t3.b,MAX(t3.c),t3.d +FROM t3 +WHERE (t3.a = 1) AND (t3.d = 1) +GROUP BY t3.a,t3.b,t3.d +HAVING (t3.b = 2) AND (t3.d > 0); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 ALL NULL NULL NULL NULL 3 Using where +explain format=json SELECT t3.a,t3.b,MAX(t3.c),t3.d +FROM t3 +WHERE (t3.a = 1) AND (t3.d = 1) +GROUP BY t3.a,t3.b,t3.d +HAVING (t3.b = 2) AND (t3.d > 0); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "const_condition": "1", + "table": { + "table_name": "t3", + "access_type": "ALL", + "rows": 3, + "filtered": 100, + "attached_condition": "t3.a = 1 and t3.d = 1 and t3.b = 2" + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t3.a,t3.b,MAX(t3.c),t3.d +FROM t3 +WHERE (t3.a = 1) AND (t3.d = 1) AND +(t3.b = 2) AND (t3.d > 0) +GROUP BY t3.a,t3.b,t3.d; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t3", + "access_type": "ALL", + "rows": 3, + "filtered": 100, + "attached_condition": "t3.a = 1 and t3.d = 1 and t3.b = 2" + } + } +} +# AND formula : OR formula in WHERE +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) OR (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a < 4) AND (t1.c > 1); +a MAX(t1.b) c +2 13 2 +3 14 4 +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) OR (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a < 4) AND (t1.c > 1); +a MAX(t1.b) c +2 13 2 +3 14 4 +explain SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) OR (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a < 4) AND (t1.c > 1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort +explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) OR (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a < 4) AND (t1.c > 1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "having_condition": "t1.c > 1", + "filesort": { + "sort_key": "t1.a", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "(t1.a > 1 or t1.c < 3) and t1.a < 4" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE ((t1.a > 1) OR (t1.c < 3)) AND +(t1.a < 4) +GROUP BY t1.a +HAVING (t1.c > 1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "having_condition": "t1.c > 1", + "filesort": { + "sort_key": "t1.a", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "(t1.a > 1 or t1.c < 3) and t1.a < 4" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) OR (t1.c < 3) +GROUP BY t1.a,t1.c +HAVING (t1.a < 4) AND (t1.c > 1); +a MAX(t1.b) c +2 13 2 +3 14 2 +3 13 4 +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) OR (t1.c < 3) +GROUP BY t1.a,t1.c +HAVING (t1.a < 4) AND (t1.c > 1); +a MAX(t1.b) c +2 13 2 +3 14 2 +3 13 4 +explain SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) OR (t1.c < 3) +GROUP BY t1.a,t1.c +HAVING (t1.a < 4) AND (t1.c > 1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort +explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) OR (t1.c < 3) +GROUP BY t1.a,t1.c +HAVING (t1.a < 4) AND (t1.c > 1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a, t1.c", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "(t1.a > 1 or t1.c < 3) and t1.a < 4 and t1.c > 1" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE ((t1.a > 1) OR (t1.c < 3)) AND +(t1.a < 4) AND (t1.c > 1) +GROUP BY t1.a,t1.c; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a, t1.c", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "(t1.a > 1 or t1.c < 3) and t1.a < 4 and t1.c > 1" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) OR (t1.a = 3) +GROUP BY t1.a,t1.c +HAVING (t1.a = 4) OR (t1.c > 1); +a MAX(t1.b) c +1 14 3 +3 14 2 +3 13 4 +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) OR (t1.a = 3) +GROUP BY t1.a,t1.c +HAVING (t1.a = 4) OR (t1.c > 1); +a MAX(t1.b) c +1 14 3 +3 14 2 +3 13 4 +explain SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) OR (t1.a = 3) +GROUP BY t1.a,t1.c +HAVING (t1.a = 4) OR (t1.c > 1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where; Using temporary; Using filesort +explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) OR (t1.a = 3) +GROUP BY t1.a,t1.c +HAVING (t1.a = 4) OR (t1.c > 1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a, t1.c", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "(t1.a = 1 or t1.a = 3) and (t1.a = 4 or t1.c > 1)" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE ((t1.a = 1) OR (t1.a = 3)) AND +((t1.a = 4) OR (t1.c > 1)) +GROUP BY t1.a,t1.c; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t1.a, t1.c", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "(t1.a = 1 or t1.a = 3) and (t1.a = 4 or t1.c > 1)" + } + } + } + } +} +# equality : pushdown through equality in WHERE +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.a = t1.c) +GROUP BY t1.a +HAVING (t1.c = 1); +a MAX(t1.b) c +1 22 1 +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.a = t1.c) +GROUP BY t1.a +HAVING (t1.c = 1); +a MAX(t1.b) c +1 22 1 +explain SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.a = t1.c) +GROUP BY t1.a +HAVING (t1.c = 1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where +explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.a = t1.c) +GROUP BY t1.a +HAVING (t1.c = 1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 1 and t1.c = 1" + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.a = t1.c) AND (t1.c = 1) +GROUP BY t1.a; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 1 and t1.c = 1" + } + } +} +# OR formula : pushdown through equality +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.a = t1.c) +GROUP BY t1.a +HAVING (t1.c = 1) OR (t1.c = 2); +a MAX(t1.b) c +1 22 1 +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.a = t1.c) +GROUP BY t1.a +HAVING (t1.c = 1) OR (t1.c = 2); +a MAX(t1.b) c +1 22 1 +explain SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.a = t1.c) +GROUP BY t1.a +HAVING (t1.c = 1) OR (t1.c = 2); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using where +explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.a = t1.c) +GROUP BY t1.a +HAVING (t1.c = 1) OR (t1.c = 2); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 1 and t1.c = 1" + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.a = t1.c) AND +((t1.c = 1) OR (t1.c = 2)) +GROUP BY t1.a; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t1.a = 1 and t1.c = 1" + } + } +} +# OR formula : pushdown through equality, impossible WHERE +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.a = t1.c) +GROUP BY t1.a +HAVING (t1.c = 3) OR (t1.c = 2); +a MAX(t1.b) c +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.a = t1.c) +GROUP BY t1.a +HAVING (t1.c = 3) OR (t1.c = 2); +a MAX(t1.b) c +explain SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.a = t1.c) +GROUP BY t1.a +HAVING (t1.c = 3) OR (t1.c = 2); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.a = t1.c) +GROUP BY t1.a +HAVING (t1.c = 3) OR (t1.c = 2); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "message": "Impossible WHERE" + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.a = t1.c) AND +((t1.c = 3) OR (t1.c = 2)) +GROUP BY t1.a; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "message": "Impossible WHERE" + } + } +} +# AND formula : pushdown through equality, impossible WHERE +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) +GROUP BY t1.a,t1.c +HAVING (t1.c = 3) AND (t1.a > 2) AND (t1.a = t1.c); +a MAX(t1.b) c +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) +GROUP BY t1.a,t1.c +HAVING (t1.c = 3) AND (t1.a > 2) AND (t1.a = t1.c); +a MAX(t1.b) c +explain SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) +GROUP BY t1.a,t1.c +HAVING (t1.c = 3) AND (t1.a > 2) AND (t1.a = t1.c); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) +GROUP BY t1.a,t1.c +HAVING (t1.c = 3) AND (t1.a > 2) AND (t1.a = t1.c); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "message": "Impossible WHERE" + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.c = 3) AND +(t1.a > 2) AND (t1.a = t1.c) +GROUP BY t1.a,t1.c; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "message": "Impossible WHERE" + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) +GROUP BY t1.a +HAVING (t1.c = 3) AND (t1.a > 2) AND (t1.a = t1.c); +a MAX(t1.b) c +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) +GROUP BY t1.a +HAVING (t1.c = 3) AND (t1.a > 2) AND (t1.a = t1.c); +a MAX(t1.b) c +explain SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) +GROUP BY t1.a +HAVING (t1.c = 3) AND (t1.a > 2) AND (t1.a = t1.c); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) +GROUP BY t1.a +HAVING (t1.c = 3) AND (t1.a > 2) AND (t1.a = t1.c); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "message": "Impossible WHERE" + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.c = 3) AND +(t1.a > 2) AND (t1.a = t1.c) +GROUP BY t1.a; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "message": "Impossible WHERE" + } + } +} +# AND formula with OR subformula : AND condition in WHERE +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t3.a,MAX(t3.b),t3.c,t3.d +FROM t3 +WHERE (t3.a > 1) AND ((t3.c = 3) OR (t3.c < 2)) +GROUP BY t3.a +HAVING (t3.a = t3.d) AND ((t3.d = 1) OR (t3.d > 1)); +a MAX(t3.b) c d +SELECT t3.a,MAX(t3.b),t3.c,t3.d +FROM t3 +WHERE (t3.a > 1) AND ((t3.c = 3) OR (t3.c < 2)) +GROUP BY t3.a +HAVING (t3.a = t3.d) AND ((t3.d = 1) OR (t3.d > 1)); +a MAX(t3.b) c d +explain SELECT t3.a,MAX(t3.b),t3.c,t3.d +FROM t3 +WHERE (t3.a > 1) AND ((t3.c = 3) OR (t3.c < 2)) +GROUP BY t3.a +HAVING (t3.a = t3.d) AND ((t3.d = 1) OR (t3.d > 1)); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 ALL NULL NULL NULL NULL 3 Using where; Using temporary; Using filesort +explain format=json SELECT t3.a,MAX(t3.b),t3.c,t3.d +FROM t3 +WHERE (t3.a > 1) AND ((t3.c = 3) OR (t3.c < 2)) +GROUP BY t3.a +HAVING (t3.a = t3.d) AND ((t3.d = 1) OR (t3.d > 1)); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t3.a", + "temporary_table": { + "table": { + "table_name": "t3", + "access_type": "ALL", + "rows": 3, + "filtered": 100, + "attached_condition": "t3.d = t3.a and t3.a > 1 and (t3.c = 3 or t3.c < 2) and (t3.a = 1 or t3.a > 1)" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t3.a,MAX(t3.c),t3.d +FROM t3 +WHERE (t3.a > 1) AND ((t3.c = 3) OR (t3.c < 2)) AND +(t3.a = t3.d) AND ((t3.d = 1) OR (t3.d > 1)) +GROUP BY t3.a; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t3.a", + "temporary_table": { + "table": { + "table_name": "t3", + "access_type": "ALL", + "rows": 3, + "filtered": 100, + "attached_condition": "t3.d = t3.a and t3.a > 1 and (t3.c = 3 or t3.c < 2) and (t3.a = 1 or t3.a > 1)" + } + } + } + } +} +# AND formula with OR subformula : AND condition in WHERE +set statement optimizer_switch='condition_pushdown_from_having=off' for SELECT t3.a,MAX(t3.b),t3.c,t3.d +FROM t3 +WHERE (t3.a > 1) AND ((t3.c = 3) OR (t3.c < 2)) +GROUP BY t3.a +HAVING (t3.a = t3.d) AND (((t3.d = t3.c) AND (t3.c < 15)) OR (t3.d > 1)); +a MAX(t3.b) c d +SELECT t3.a,MAX(t3.b),t3.c,t3.d +FROM t3 +WHERE (t3.a > 1) AND ((t3.c = 3) OR (t3.c < 2)) +GROUP BY t3.a +HAVING (t3.a = t3.d) AND (((t3.d = t3.c) AND (t3.c < 15)) OR (t3.d > 1)); +a MAX(t3.b) c d +explain SELECT t3.a,MAX(t3.b),t3.c,t3.d +FROM t3 +WHERE (t3.a > 1) AND ((t3.c = 3) OR (t3.c < 2)) +GROUP BY t3.a +HAVING (t3.a = t3.d) AND (((t3.d = t3.c) AND (t3.c < 15)) OR (t3.d > 1)); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 ALL NULL NULL NULL NULL 3 Using where; Using temporary; Using filesort +explain format=json SELECT t3.a,MAX(t3.b),t3.c,t3.d +FROM t3 +WHERE (t3.a > 1) AND ((t3.c = 3) OR (t3.c < 2)) +GROUP BY t3.a +HAVING (t3.a = t3.d) AND (((t3.d = t3.c) AND (t3.c < 15)) OR (t3.d > 1)); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t3.a", + "temporary_table": { + "table": { + "table_name": "t3", + "access_type": "ALL", + "rows": 3, + "filtered": 100, + "attached_condition": "t3.d = t3.a and t3.a > 1 and (t3.c = 3 or t3.c < 2) and (t3.c = t3.a and t3.c < 15 or t3.a > 1)" + } + } + } + } +} +set statement optimizer_switch='condition_pushdown_from_having=off' for explain format=json SELECT t3.a,t3.b,MAX(t3.c),t3.d +FROM t3 +WHERE (t3.a > 1) AND ((t3.c = 3) OR (t3.c < 2)) AND +(t3.a = t3.d) AND (((t3.d = t3.c) AND (t3.c < 15)) OR (t3.d > 1)) +GROUP BY t3.a; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "filesort": { + "sort_key": "t3.a", + "temporary_table": { + "table": { + "table_name": "t3", + "access_type": "ALL", + "rows": 3, + "filtered": 100, + "attached_condition": "t3.d = t3.a and t3.a > 1 and (t3.c = 3 or t3.c < 2) and (t3.c = t3.a and t3.a < 15 or t3.a > 1)" + } + } + } + } +} +# prepare statement +PREPARE stmt1 from " +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +GROUP BY t1.a +HAVING (t1.a = 1) +"; +execute stmt1; +a MAX(t1.b) c +1 22 3 +execute stmt1; +a MAX(t1.b) c +1 22 3 +deallocate prepare stmt1; +DROP TABLE t1,t3; diff --git a/mysql-test/main/having_cond_pushdown.test b/mysql-test/main/having_cond_pushdown.test index 2fbb5708c50..1e5ad610e90 100644 --- a/mysql-test/main/having_cond_pushdown.test +++ b/mysql-test/main/having_cond_pushdown.test @@ -486,3 +486,818 @@ EXPLAIN SELECT a FROM t1 WHERE b = 1 AND b = 2 GROUP BY a HAVING a <= 3; DROP TABLE t1; + +--echo # +--echo # MDEV-18769: unfixed OR condition pushed from HAVING into WHERE +--echo # + +CREATE TABLE t1(a INT, b INT, c INT); +CREATE TABLE t3(a INT, b INT, c INT, d INT); + +INSERT INTO t1 VALUES (1,14,3), (2,13,2), (1,22,1), (3,13,4), (3,14,2); +INSERT INTO t3 VALUES (1,2,16,1), (1,3,11,2), (2,3,10,2); + +--echo # nothing to push +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a +HAVING t1.b = 13 AND MAX(t1.c) > 2; +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a +HAVING t1.b = 13 AND MAX(t1.c) > 2; +eval $no_pushdown explain format=json $query; + +--echo # extracted AND formula +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a = 1 OR t1.b > 10) AND (t1.b < 14); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.a = 1 OR t1.b > 10) AND (t1.b < 14) +GROUP BY t1.a,t1.b; +eval $no_pushdown explain format=json $query; + +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a = 1 OR t1.b > 10) AND (t1.b < 14 OR t1.b > 15); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.a = 1 OR t1.b > 10) AND (t1.b < 14 OR t1.b > 15) +GROUP BY t1.a,t1.b; +eval $no_pushdown explain format=json $query; + +--echo # extracted AND formula : equality in the inner AND formula +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a = 1 OR t1.b > 10) AND (t1.b < 14 OR (t1.b > 15 AND t1.a = 2)); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.a = 1 OR t1.b > 10) AND (t1.b < 14 OR (t1.b > 15 AND t1.a = 2)) +GROUP BY t1.a,t1.b; +eval $no_pushdown explain format=json $query; + +--echo # extracted OR formula +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a < 2) OR (t1.b = 13 AND t1.a > 2); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.a < 2) OR (t1.b = 13 AND t1.a > 2) +GROUP BY t1.a,t1.b; +eval $no_pushdown explain format=json $query; + +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a < 2 AND t1.b = 14) OR (t1.a > 2 AND t1.b = 13); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.a < 2 AND t1.b = 14) OR (t1.a > 2 AND t1.b = 13) +GROUP BY t1.a,t1.b; +eval $no_pushdown explain format=json $query; + +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.b +HAVING (t1.a < 2 AND t1.b = 14) OR (t1.a > 2 AND (t1.b = 13 OR t1.b = 14)); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.a < 2 AND t1.b = 14) OR (t1.a > 2 AND (t1.b = 13 OR t1.b = 14)) +GROUP BY t1.a,t1.b; +eval $no_pushdown explain format=json $query; + +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a +HAVING (t1.a < 2 AND MAX(t1.c) = 2) OR (MAX(t1.c) > 2 AND (t1.a = 1 OR t1.a = 2)); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.a < 2) OR (t1.a = 1 OR t1.a = 2) +GROUP BY t1.a +HAVING (t1.a < 2 AND MAX(t1.c) = 2) OR (MAX(t1.c) > 2 AND (t1.a = 1 OR t1.a = 2)); +eval $no_pushdown explain format=json $query; + +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a +HAVING (t1.a = 2 AND MAX(t1.c) = 2) OR (MAX(t1.c) > 2 AND (t1.a = 1 OR t1.a = 2)); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.a = 2) OR (t1.a = 1 OR t1.a = 2) +GROUP BY t1.a +HAVING (t1.a = 2 AND MAX(t1.c) = 2) OR (MAX(t1.c) > 2 AND (t1.a = 1 OR t1.a = 2)); +eval $no_pushdown explain format=json $query; + +--echo # conjunctive subformula : equality pushdown +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a +HAVING (t1.a = 1) AND (MAX(t1.c) = 3); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.a = 1) +GROUP BY t1.a +HAVING (MAX(t1.c) = 3); +eval $no_pushdown explain format=json $query; + +--echo # conjunctive subformula : equalities pushdown +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.c +HAVING (t1.a = 1) AND (t1.c = 3) AND MAX(t1.b = 14); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.a = 1) AND (t1.c = 3) +GROUP BY t1.a,t1.c +HAVING (MAX(t1.b) = 14); +eval $no_pushdown explain format=json $query; + +--echo # conjunctive subformula : multiple equality consists of +--echo two equalities pushdown +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +GROUP BY t1.a,t1.c +HAVING (t1.a = 1) AND (t1.c = 1) AND MAX(t1.b = 14); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.a = 1) AND (t1.c = 1) +GROUP BY t1.a,t1.c +HAVING (MAX(t1.b) = 14); +eval $no_pushdown explain format=json $query; + +--echo # +--echo # Pushdown from HAVING into non-empty WHERE +--echo # + +--echo # inequality : inequality in WHERE +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b > 2) +GROUP BY t1.a +HAVING (t1.a < 3); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b > 2) AND (t1.a < 3) +GROUP BY t1.a; +eval $no_pushdown explain format=json $query; + +--echo # equality : inequality in WHERE +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b > 2) +GROUP BY t1.a +HAVING (t1.a = 3); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b > 2) AND (t1.a = 3) +GROUP BY t1.a; +eval $no_pushdown explain format=json $query; + +--echo # inequality : equality in WHERE +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b = 14) +GROUP BY t1.a +HAVING (t1.a < 3); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b = 14) AND (t1.a < 3) +GROUP BY t1.a; +eval $no_pushdown explain format=json $query; + +--echo # equality : equality in WHERE +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b = 14) +GROUP BY t1.a +HAVING (t1.a = 1); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,t1.b,MAX(t1.c) +FROM t1 +WHERE (t1.b = 14) AND (t1.a = 1) +GROUP BY t1.a; +eval $no_pushdown explain format=json $query; + +--echo # equality : equality in WHERE, impossible WHERE +let $query= +SELECT t1.a,MAX(t1.c) +FROM t1 +WHERE (t1.a = 3) +GROUP BY t1.a +HAVING (t1.a = 1); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,MAX(t1.c) +FROM t1 +WHERE (t1.a = 3) AND (t1.a = 1) +GROUP BY t1.a; +eval $no_pushdown explain format=json $query; + +--echo # equality : equality in WHERE (equal through constant) +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.c = 1) +GROUP BY t1.a +HAVING (t1.a = 1); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.c = 1) AND (t1.a = 1) +GROUP BY t1.a; +eval $no_pushdown explain format=json $query; + +--echo # inequality : AND formula in WHERE +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.c > 0) AND (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a > 1); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.c > 0) AND (t1.c < 3) AND (t1.a > 1) +GROUP BY t1.a; +eval $no_pushdown explain format=json $query; + +--echo # equality : AND formula in WHERE +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.c > 0) AND (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a = 1); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.c > 0) AND (t1.c < 3) AND (t1.a = 1) +GROUP BY t1.a; +eval $no_pushdown explain format=json $query; + +--echo # equality : AND formula in WHERE, impossible WHERE +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 0) AND (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a = 1); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 0) AND (t1.c < 3) AND (t1.a = 1) +GROUP BY t1.a; +eval $no_pushdown explain format=json $query; + +let $query= +SELECT t1.a,MAX(t1.b) +FROM t1 +WHERE (t1.a = 0) AND (t1.a = 3) +GROUP BY t1.a +HAVING (t1.a = 1); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,MAX(t1.b) +FROM t1 +WHERE (t1.a = 0) AND (t1.a = 3) AND (t1.a = 1) +GROUP BY t1.a; +eval $no_pushdown explain format=json $query; + +let $query= +SELECT t3.a,t3.b,MAX(t3.c),t3.d +FROM t3 +WHERE (t3.b = 2) AND (t3.d = 1) +GROUP BY t3.a,t3.b,t3.d +HAVING (t3.a = 1); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t3.a,t3.b,MAX(t3.c),t3.d +FROM t3 +WHERE (t3.b = 2) AND (t3.d = 1) AND (t3.a = 1) +GROUP BY t3.a,t3.b,t3.d; +eval $no_pushdown explain format=json $query; + +--echo # inequality : OR formula in WHERE +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) OR (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a < 2); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE ((t1.a > 1) OR (t1.c < 3)) AND (t1.a < 2) +GROUP BY t1.a; +eval $no_pushdown explain format=json $query; + +let $query= +SELECT t1.a,MAX(t1.b) +FROM t1 +WHERE (t1.a = 1) OR (t1.a = 3) +GROUP BY t1.a +HAVING (t1.a = 2); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,MAX(t1.b) +FROM t1 +WHERE ((t1.a = 1) OR (t1.a = 3)) AND (t1.a = 2) +GROUP BY t1.a; +eval $no_pushdown explain format=json $query; + +--echo # AND formula : inequality in WHERE +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) +GROUP BY t1.a +HAVING (t1.a < 4) AND (t1.a > 0); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) AND (t1.a < 4) AND (t1.a > 0) +GROUP BY t1.a; +eval $no_pushdown explain format=json $query; + +--echo # AND formula : equality in WHERE +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) +GROUP BY t1.a +HAVING (t1.a < 4) AND (t1.a > 0); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.a < 4) AND (t1.a > 0) +GROUP BY t1.a; +eval $no_pushdown explain format=json $query; + +--echo # OR formula : inequality in WHERE +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) +GROUP BY t1.a +HAVING (t1.a < 4) OR (t1.a > 0); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) AND ((t1.a < 4) OR (t1.a > 0)) +GROUP BY t1.a; +eval $no_pushdown explain format=json $query; + +--echo # OR formula : equality in WHERE +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) +GROUP BY t1.a +HAVING (t1.a < 4) OR (t1.a > 0); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND ((t1.a < 4) OR (t1.a > 0)) +GROUP BY t1.a; +eval $no_pushdown explain format=json $query; + +--echo # AND formula : AND formula in WHERE +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) AND (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a < 4) AND (t1.c > 1); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE ((t1.a > 1) AND (t1.c < 3)) AND + (t1.a < 4) +GROUP BY t1.a +HAVING (t1.c > 1); +eval $no_pushdown explain format=json $query; + +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.c < 3) +GROUP BY t1.a,t1.c +HAVING (t1.a < 4) AND (t1.c > 1); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE ((t1.a = 1) AND (t1.c < 3)) AND + ((t1.a < 4) AND (t1.c > 1)) +GROUP BY t1.a,t1.c; +eval $no_pushdown explain format=json $query; + +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.c = 3) +GROUP BY t1.a,t1.c +HAVING (t1.a < 4) AND (t1.c > 1); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE ((t1.a = 1) AND (t1.c = 3)) AND + ((t1.a < 4) AND (t1.c > 1)) +GROUP BY t1.a,t1.c; +eval $no_pushdown explain format=json $query; + +let $query= +SELECT t3.a,t3.b,MAX(t3.c),t3.d +FROM t3 +WHERE (t3.a = 1) AND (t3.d = 1) +GROUP BY t3.a,t3.b +HAVING (t3.b = 2) AND (t3.d > 0); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t3.a,t3.b,MAX(t3.c),t3.d +FROM t3 +WHERE (t3.a = 1) AND (t3.d = 1) AND + (t3.b = 2) +GROUP BY t3.a,t3.b +HAVING (t3.d > 0); +eval $no_pushdown explain format=json $query; + +let $query= +SELECT t3.a,t3.b,MAX(t3.c),t3.d +FROM t3 +WHERE (t3.a = 1) AND (t3.d = 1) +GROUP BY t3.a,t3.b,t3.d +HAVING (t3.b = 2) AND (t3.d > 0); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t3.a,t3.b,MAX(t3.c),t3.d +FROM t3 +WHERE (t3.a = 1) AND (t3.d = 1) AND + (t3.b = 2) AND (t3.d > 0) +GROUP BY t3.a,t3.b,t3.d; +eval $no_pushdown explain format=json $query; + +--echo # AND formula : OR formula in WHERE +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) OR (t1.c < 3) +GROUP BY t1.a +HAVING (t1.a < 4) AND (t1.c > 1); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE ((t1.a > 1) OR (t1.c < 3)) AND + (t1.a < 4) +GROUP BY t1.a +HAVING (t1.c > 1); +eval $no_pushdown explain format=json $query; + +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a > 1) OR (t1.c < 3) +GROUP BY t1.a,t1.c +HAVING (t1.a < 4) AND (t1.c > 1); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE ((t1.a > 1) OR (t1.c < 3)) AND + (t1.a < 4) AND (t1.c > 1) +GROUP BY t1.a,t1.c; +eval $no_pushdown explain format=json $query; + +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) OR (t1.a = 3) +GROUP BY t1.a,t1.c +HAVING (t1.a = 4) OR (t1.c > 1); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE ((t1.a = 1) OR (t1.a = 3)) AND + ((t1.a = 4) OR (t1.c > 1)) +GROUP BY t1.a,t1.c; +eval $no_pushdown explain format=json $query; + +--echo # equality : pushdown through equality in WHERE +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.a = t1.c) +GROUP BY t1.a +HAVING (t1.c = 1); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.a = t1.c) AND (t1.c = 1) +GROUP BY t1.a; +eval $no_pushdown explain format=json $query; + +--echo # OR formula : pushdown through equality +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.a = t1.c) +GROUP BY t1.a +HAVING (t1.c = 1) OR (t1.c = 2); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.a = t1.c) AND + ((t1.c = 1) OR (t1.c = 2)) +GROUP BY t1.a; +eval $no_pushdown explain format=json $query; + +--echo # OR formula : pushdown through equality, impossible WHERE +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.a = t1.c) +GROUP BY t1.a +HAVING (t1.c = 3) OR (t1.c = 2); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.a = t1.c) AND + ((t1.c = 3) OR (t1.c = 2)) +GROUP BY t1.a; +eval $no_pushdown explain format=json $query; + +--echo # AND formula : pushdown through equality, impossible WHERE +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) +GROUP BY t1.a,t1.c +HAVING (t1.c = 3) AND (t1.a > 2) AND (t1.a = t1.c); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.c = 3) AND + (t1.a > 2) AND (t1.a = t1.c) +GROUP BY t1.a,t1.c; +eval $no_pushdown explain format=json $query; + +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) +GROUP BY t1.a +HAVING (t1.c = 3) AND (t1.a > 2) AND (t1.a = t1.c); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +WHERE (t1.a = 1) AND (t1.c = 3) AND + (t1.a > 2) AND (t1.a = t1.c) +GROUP BY t1.a; +eval $no_pushdown explain format=json $query; + +--echo # AND formula with OR subformula : AND condition in WHERE +let $query= +SELECT t3.a,MAX(t3.b),t3.c,t3.d +FROM t3 +WHERE (t3.a > 1) AND ((t3.c = 3) OR (t3.c < 2)) +GROUP BY t3.a +HAVING (t3.a = t3.d) AND ((t3.d = 1) OR (t3.d > 1)); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t3.a,MAX(t3.c),t3.d +FROM t3 +WHERE (t3.a > 1) AND ((t3.c = 3) OR (t3.c < 2)) AND + (t3.a = t3.d) AND ((t3.d = 1) OR (t3.d > 1)) +GROUP BY t3.a; +eval $no_pushdown explain format=json $query; + +--echo # AND formula with OR subformula : AND condition in WHERE +let $query= +SELECT t3.a,MAX(t3.b),t3.c,t3.d +FROM t3 +WHERE (t3.a > 1) AND ((t3.c = 3) OR (t3.c < 2)) +GROUP BY t3.a +HAVING (t3.a = t3.d) AND (((t3.d = t3.c) AND (t3.c < 15)) OR (t3.d > 1)); +eval $no_pushdown $query; +eval $query; +eval explain $query; +eval explain format=json $query; +let $query= +SELECT t3.a,t3.b,MAX(t3.c),t3.d +FROM t3 +WHERE (t3.a > 1) AND ((t3.c = 3) OR (t3.c < 2)) AND + (t3.a = t3.d) AND (((t3.d = t3.c) AND (t3.c < 15)) OR (t3.d > 1)) +GROUP BY t3.a; +eval $no_pushdown explain format=json $query; + +--echo # prepare statement +PREPARE stmt1 from " +SELECT t1.a,MAX(t1.b),t1.c +FROM t1 +GROUP BY t1.a +HAVING (t1.a = 1) +"; +execute stmt1; +execute stmt1; +deallocate prepare stmt1; + +DROP TABLE t1,t3; diff --git a/mysql-test/main/union.result b/mysql-test/main/union.result index ce14b68ae2d..a0421bae922 100644 --- a/mysql-test/main/union.result +++ b/mysql-test/main/union.result @@ -2332,7 +2332,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL No tables used 2 UNION NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables Warnings: -Note 1003 /* select#1 */ select 1 AS `1`,2 AS `2` union all /* select#2 */ select 1 AS `i`,count(0) AS `COUNT(*)` from `test`.`t2` where 0 group by 1 having multiple equal(10, `i`) +Note 1003 /* select#1 */ select 1 AS `1`,2 AS `2` union all /* select#2 */ select 1 AS `i`,count(0) AS `COUNT(*)` from `test`.`t2` where 0 group by 1 having 1 DROP TABLE t1,t2; # # Start of 10.3 tests diff --git a/sql/item.cc b/sql/item.cc index 6839a631ec2..543dc971228 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2832,8 +2832,6 @@ Item_sp::init_result_field(THD *thd, uint max_length, uint maybe_null, Item* Item_ref::build_clone(THD *thd) { - if (thd->having_pushdown) - return real_item()->build_clone(thd); Item_ref *copy= (Item_ref *) get_copy(thd); if (unlikely(!copy) || unlikely(!(copy->ref= (Item**) alloc_root(thd->mem_root, @@ -7195,8 +7193,9 @@ void Item::check_pushable_cond(Pushdown_checker checker, uchar *arg) Build condition extractable from this condition for pushdown @param thd the thread handle - @param checker the checker callback function to be applied to the - equal items of multiple equality items + @param checker the checker callback function to be applied to the nodes + of the tree of the object to check if multiple equality + elements can be used to create equalities @param arg parameter to be passed to the checker @details @@ -7300,19 +7299,6 @@ Item *Item::build_pushable_cond(THD *thd, (equalities.elements == 0)) return 0; - if (thd->having_pushdown) - { - /* Creates multiple equalities from equalities that can be pushed */ - Item::cond_result cond_value; - COND_EQUAL *cond_equal= new (thd->mem_root) COND_EQUAL(); - new_cond= and_new_conditions_to_optimized_cond(thd, new_cond, - &cond_equal, - equalities, - &cond_value, - false); - return new_cond; - } - switch (equalities.elements) { case 0: @@ -7484,15 +7470,6 @@ Item *Item_field::grouping_field_transformer_for_where(THD *thd, uchar *arg) } -bool Item::pushable_equality_checker_for_having_pushdown(uchar *arg) -{ - return (type() == Item::FIELD_ITEM || - (type() == Item::REF_ITEM && - ((((Item_ref *) this)->ref_type() == Item_ref::VIEW_REF) || - (((Item_ref *) this)->ref_type() == Item_ref::REF)))); -} - - Item * Item_direct_view_ref::grouping_field_transformer_for_where(THD *thd, uchar *arg) @@ -9079,18 +9056,7 @@ bool Item_direct_view_ref::excl_dep_on_grouping_fields(st_select_lex *sel) } -bool Item_direct_view_ref::excl_dep_on_group_fields_for_having_pushdown(st_select_lex *sel) -{ - if (item_equal) - { - DBUG_ASSERT(real_item()->type() == Item::FIELD_ITEM); - return (find_matching_field_pair(this, sel->grouping_tmp_fields) != NULL); - } - return (*ref)->excl_dep_on_group_fields_for_having_pushdown(sel); -} - - -bool Item_args::excl_dep_on_group_fields_for_having_pushdown(st_select_lex *sel) +bool Item_args::excl_dep_on_grouping_fields(st_select_lex *sel) { for (uint i= 0; i < arg_count; i++) { @@ -9100,7 +9066,7 @@ bool Item_args::excl_dep_on_group_fields_for_having_pushdown(st_select_lex *sel) return false; if (args[i]->const_item()) continue; - if (!args[i]->excl_dep_on_group_fields_for_having_pushdown(sel)) + if (!args[i]->excl_dep_on_grouping_fields(sel)) return false; } return true; diff --git a/sql/item.h b/sql/item.h index a7cef61533b..716b411082f 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1870,9 +1870,11 @@ public: Not to be used for AND/OR formulas. */ virtual bool excl_dep_on_table(table_map tab_map) { return false; } - /* + /* TRUE if the expression depends only on grouping fields of sel - or can be converted to such an exression using equalities. + or can be converted to such an expression using equalities. + It also checks if the expression doesn't contain stored procedures, + subqueries or randomly generated elements. Not to be used for AND/OR formulas. */ virtual bool excl_dep_on_grouping_fields(st_select_lex *sel) @@ -1884,15 +1886,6 @@ public: */ virtual bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) { return false; } - /* - TRUE if the expression depends only on grouping fields of sel - or can be converted to such an expression using equalities. - It also checks if the expression doesn't contain stored procedures, - subqueries or randomly generated elements. - Not to be used for AND/OR formulas. - */ - virtual bool excl_dep_on_group_fields_for_having_pushdown(st_select_lex *sel) - { return false; } virtual bool switch_to_nullable_fields_processor(void *arg) { return 0; } virtual bool find_function_processor (void *arg) { return 0; } @@ -2089,6 +2082,10 @@ public: { return this; } virtual Item *in_predicate_to_in_subs_transformer(THD *thd, uchar *arg) { return this; } + virtual Item *field_transformer_for_having_pushdown(THD *thd, uchar *arg) + { return this; } + virtual Item *multiple_equality_transformer(THD *thd, uchar *arg) + { return this; } virtual bool expr_cache_is_needed(THD *) { return FALSE; } virtual Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs); bool needs_charset_converter(uint32 length, CHARSET_INFO *tocs) const @@ -2269,6 +2266,11 @@ public: */ virtual void under_not(Item_func_not * upper __attribute__((unused))) {}; + /* + If Item_field is wrapped in Item_direct_wrep remove this Item_direct_ref + wrapper. + */ + virtual Item *remove_item_direct_ref() { return this; } void register_in(THD *thd); @@ -2309,24 +2311,6 @@ public: Checks if this item consists in the left part of arg IN subquery predicate */ bool pushable_equality_checker_for_subquery(uchar *arg); - /* - Checks if this item is of the type FIELD_ITEM or REF_ITEM so it - can be pushed as the part of the equality into the WHERE clause. - */ - bool pushable_equality_checker_for_having_pushdown(uchar *arg); - /* - Checks if this item consists in the GROUP BY of the SELECT arg - */ - bool dep_on_grouping_fields_checker(uchar *arg) - { return excl_dep_on_grouping_fields((st_select_lex *) arg); } - /* - Checks if this item consists in the GROUP BY of the SELECT arg - with respect to the pushdown from HAVING into WHERE clause limitations. - */ - bool dep_on_grouping_fields_checker_for_having_pushdown(uchar *arg) - { - return excl_dep_on_group_fields_for_having_pushdown((st_select_lex *) arg); - } }; MEM_ROOT *get_thd_memroot(THD *thd); @@ -2504,17 +2488,7 @@ protected: } return true; } - bool excl_dep_on_grouping_fields(st_select_lex *sel) - { - for (uint i= 0; i < arg_count; i++) - { - if (args[i]->const_item()) - continue; - if (!args[i]->excl_dep_on_grouping_fields(sel)) - return false; - } - return true; - } + bool excl_dep_on_grouping_fields(st_select_lex *sel); bool eq(const Item_args *other, bool binary_cmp) const { for (uint i= 0; i < arg_count ; i++) @@ -2535,7 +2509,6 @@ protected: } return true; } - bool excl_dep_on_group_fields_for_having_pushdown(st_select_lex *sel); public: Item_args(void) :args(NULL), arg_count(0) @@ -3450,8 +3423,6 @@ public: bool excl_dep_on_table(table_map tab_map); bool excl_dep_on_grouping_fields(st_select_lex *sel); bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred); - bool excl_dep_on_group_fields_for_having_pushdown(st_select_lex *sel) - { return excl_dep_on_grouping_fields(sel); } bool cleanup_excluding_fields_processor(void *arg) { return field ? 0 : cleanup_processor(arg); } bool cleanup_excluding_const_fields_processor(void *arg) @@ -5342,8 +5313,6 @@ public: { return (*ref)->excl_dep_on_grouping_fields(sel); } bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) { return (*ref)->excl_dep_on_in_subq_left_part(subq_pred); } - bool excl_dep_on_group_fields_for_having_pushdown(st_select_lex *sel) - { return (*ref)->excl_dep_on_group_fields_for_having_pushdown(sel); } bool cleanup_excluding_fields_processor(void *arg) { Item *item= real_item(); @@ -5362,6 +5331,13 @@ public: } bool with_sum_func() const { return m_with_sum_func; } With_sum_func_cache* get_with_sum_func_cache() { return this; } + Item *field_transformer_for_having_pushdown(THD *thd, uchar *arg) + { return (*ref)->field_transformer_for_having_pushdown(thd, arg); } + Item *remove_item_direct_ref() + { + *ref= (*ref)->remove_item_direct_ref(); + return this; + } }; @@ -5406,6 +5382,8 @@ public: virtual Ref_Type ref_type() { return DIRECT_REF; } Item *get_copy(THD *thd) { return get_item_copy(thd, this); } + Item *remove_item_direct_ref() + { return (*ref)->remove_item_direct_ref(); } }; @@ -5658,7 +5636,6 @@ public: bool excl_dep_on_table(table_map tab_map); bool excl_dep_on_grouping_fields(st_select_lex *sel); bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred); - bool excl_dep_on_group_fields_for_having_pushdown(st_select_lex *sel); Item *derived_field_transformer_for_having(THD *thd, uchar *arg); Item *derived_field_transformer_for_where(THD *thd, uchar *arg); Item *grouping_field_transformer_for_where(THD *thd, uchar *arg); @@ -5754,6 +5731,8 @@ public: } Item *get_copy(THD *thd) { return get_item_copy(thd, this); } + Item *field_transformer_for_having_pushdown(THD *thd, uchar *arg) + { return this; } }; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index dcd48a679d7..feb41940865 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -5227,20 +5227,6 @@ bool Item_cond::excl_dep_on_table(table_map tab_map) bool Item_cond::excl_dep_on_grouping_fields(st_select_lex *sel) -{ - List_iterator_fast li(list); - Item *item; - while ((item= li++)) - { - if (!item->excl_dep_on_grouping_fields(sel)) - return false; - } - return true; -} - - -bool -Item_cond::excl_dep_on_group_fields_for_having_pushdown(st_select_lex *sel) { if (has_rand_bit()) return false; @@ -5248,7 +5234,7 @@ Item_cond::excl_dep_on_group_fields_for_having_pushdown(st_select_lex *sel) Item *item; while ((item= li++)) { - if (!item->excl_dep_on_group_fields_for_having_pushdown(sel)) + if (!item->excl_dep_on_grouping_fields(sel)) return false; } return true; @@ -7359,14 +7345,14 @@ Item_bool_rowready_func2* Le_creator::create_swap(THD *thd, Item *a, Item *b) co bool -Item_equal::excl_dep_on_group_fields_for_having_pushdown(st_select_lex *sel) +Item_equal::excl_dep_on_grouping_fields(st_select_lex *sel) { Item_equal_fields_iterator it(*this); Item *item; while ((item=it++)) { - if (item->excl_dep_on_group_fields_for_having_pushdown(sel)) + if (item->excl_dep_on_grouping_fields(sel)) { set_extraction_flag(FULL_EXTRACTION_FL); return true; @@ -7378,31 +7364,71 @@ Item_equal::excl_dep_on_group_fields_for_having_pushdown(st_select_lex *sel) /** @brief - Create from this multiple equality equalities that can be pushed down + Transform multiple equality into list of equalities @param thd the thread handle - @param equalities the result list of created equalities + @param equalities the list where created equalities are stored @param checker the checker callback function to be applied to the nodes - of the tree of the object + of the tree of the object to check if multiple equality + elements can be used to create equalities @param arg parameter to be passed to the checker @details - The method traverses this multiple equality trying to create from it - new equalities that can be pushed down. It creates equalities with - the constant used in this multiple equality if it exists or the first - item for which checker returns non-NULL result and all other items - in this multiple equality for which checker returns non-NULL result. + How the method works on examples: - Example: + Example 1: + It takes MULT_EQ(x,a,b) and tries to create from its elements a set of + equalities {(x=a),(x=b)}. - MULT_EQ(1,a,b) - => - Created equalities: {(1=a),(1=b)} + Example 2: + It takes MULT_EQ(1,a,b) and tries to create from its elements a set of + equalities {(1=a),(1=b)}. - MULT_EQ(a,b,c,d) - => - Created equalities: {(a=b),(a=c),(a=d)} + How it is done: + 1. The method finds the left part of the equalities to be built. It will + be the same for all equalities. It is either: + a. A constant if there is any + b. A first element in the multiple equality that satisfies + checker function + + For the example 1 the left element is field 'x'. + For the example 2 it is constant '1'. + + 2. If the left element is found the rest elements of the multiple equality + are checked with the checker function if they can be right parts + of equalities. + If the element can be a right part of the equality, equality is built. + It is built with the left part element found at the step 1 and + the right part element found at this step (step 2). + + Suppose for the example above that both 'a' and 'b' fields can be used + to build equalities: + + Example 1: + for 'a' field (x=a) is built + for 'b' field (x=b) is built + + Example 2: + for 'a' field (1=a) is built + for 'b' field (1=b) is built + + 3. As a result we get a set of equalities built with the elements of + this multiple equality. They are saved in the equality list. + + Example 1: + {(x=a),(x=b)} + + Example 2: + {(1=a),(1=b)} + + @note + This method is called for condition pushdown into materialized + derived table/view, and IN subquery, and pushdown from HAVING into WHERE. + When it is called for pushdown from HAVING the empty checker is passed. + It happens because elements of this multiple equality don't need to be + checked if they can be used to build equalities. There are no elements + that can't be used to build equalities. @retval true if an error occurs @retval false otherwise @@ -7416,14 +7442,14 @@ bool Item_equal::create_pushable_equalities(THD *thd, Item *item; Item_equal_fields_iterator it(*this); Item *left_item = get_const(); - Item *right_item; if (!left_item) { while ((item=it++)) { - left_item= ((item->*checker) (arg)) ? item : NULL; - if (left_item) - break; + left_item= item; + if (checker && !((item->*checker) (arg))) + continue; + break; } } if (!left_item) @@ -7431,8 +7457,7 @@ bool Item_equal::create_pushable_equalities(THD *thd, while ((item=it++)) { - right_item= ((item->*checker) (arg)) ? item : NULL; - if (!right_item) + if (checker && !((item->*checker) (arg))) continue; Item_func_eq *eq= 0; Item *left_item_clone= left_item->build_clone(thd); @@ -7450,3 +7475,38 @@ bool Item_equal::create_pushable_equalities(THD *thd, } return false; } + + +/** + Transform multiple equality into the AND condition of equalities. + + Example: + MULT_EQ(x,a,b) + => + (x=a) AND (x=b) + + Equalities are built in Item_equal::create_pushable_equalities() method + using elements of this multiple equality. The result of this method is + saved in an equality list. + This method returns the condition where the elements of the equality list + are anded. +*/ + +Item *Item_equal::multiple_equality_transformer(THD *thd, uchar *arg) +{ + List equalities; + if (create_pushable_equalities(thd, &equalities, 0, 0)) + return 0; + + switch (equalities.elements) + { + case 0: + return 0; + case 1: + return equalities.head(); + break; + default: + return new (thd->mem_root) Item_cond_and(thd, equalities); + break; + } +} diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index adf6f33c55f..a6bf0a6d427 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -3012,7 +3012,6 @@ public: Item *build_clone(THD *thd); bool excl_dep_on_table(table_map tab_map); bool excl_dep_on_grouping_fields(st_select_lex *sel); - bool excl_dep_on_group_fields_for_having_pushdown(st_select_lex *sel); }; template class LI, class T> class Item_equal_iterator; @@ -3200,13 +3199,14 @@ public: return used_tables() & tab_map; } bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred); - bool excl_dep_on_group_fields_for_having_pushdown(st_select_lex *sel); + bool excl_dep_on_grouping_fields(st_select_lex *sel); bool create_pushable_equalities(THD *thd, List *equalities, Pushdown_checker checker, uchar *arg); /* Return the number of elements in this multiple equality */ uint elements_count() { return equal_items.elements; } friend class Item_equal_fields_iterator; bool count_sargable_conds(void *arg); + Item *multiple_equality_transformer(THD *thd, uchar *arg); friend class Item_equal_iterator; friend class Item_equal_iterator; friend Item *eliminate_item_equal(THD *thd, COND *cond, diff --git a/sql/item_func.h b/sql/item_func.h index 7447d57722a..aaf5eaacc88 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -342,6 +342,8 @@ public: bool excl_dep_on_grouping_fields(st_select_lex *sel) { + if (has_rand_bit()) + return false; return Item_args::excl_dep_on_grouping_fields(sel); } @@ -350,13 +352,6 @@ public: return Item_args::excl_dep_on_in_subq_left_part(subq_pred); } - bool excl_dep_on_group_fields_for_having_pushdown(st_select_lex *sel) - { - if (has_rand_bit()) - return false; - return Item_args::excl_dep_on_group_fields_for_having_pushdown(sel); - } - /* We assume the result of any function that has a TIMESTAMP argument to be timezone-dependent, since a TIMESTAMP value in both numeric and string @@ -2340,8 +2335,6 @@ public: } bool excl_dep_on_grouping_fields(st_select_lex *sel) { return false; } - bool excl_dep_on_group_fields_for_having_pushdown(st_select_lex *sel) - { return false;} }; @@ -3239,7 +3232,7 @@ public: not_null_tables_cache= 0; return 0; } - bool excl_dep_on_group_fields_for_having_pushdown(st_select_lex *sel) + bool excl_dep_on_grouping_fields(st_select_lex *sel) { return false; } }; diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index a1d60aff6ef..32b70b41eb3 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -5601,44 +5601,44 @@ int select_value_catcher::send_data(List &items) /** @brief - Conjunct conditions after optimize_cond() call + Attach conditions to already optimized condition - @param thd the thread handle - @param cond the condition where to attach new conditions - @param cond_eq IN/OUT the multiple equalities of cond - @param new_conds IN/OUT the list of conditions needed to add - @param cond_value the returned value of the condition - @param build_cond_equal flag to control if COND_EQUAL elements for - AND-conditions should be built + @param thd the thread handle + @param cond the condition to which add new conditions + @param cond_eq IN/OUT the multiple equalities of cond + @param new_conds the list of conditions to be added + @param cond_value the returned value of the condition + if it can be evaluated @details - The method creates new condition through conjunction of cond and + The method creates new condition through union of cond and the conditions from new_conds list. The method is called after optimize_cond() for cond. The result - of the conjunction should be the same as if it was done before the + of the union should be the same as if it was done before the the optimize_cond() call. - @retval NULL if an error occurs @retval otherwise the created condition + @retval NULL if an error occurs */ Item *and_new_conditions_to_optimized_cond(THD *thd, Item *cond, COND_EQUAL **cond_eq, List &new_conds, - Item::cond_result *cond_value, - bool build_cond_equal) + Item::cond_result *cond_value) { COND_EQUAL new_cond_equal; Item *item; - Item_equal *equality; + Item_equal *mult_eq; bool is_simplified_cond= false; + /* The list where parts of the new condition are stored. */ List_iterator li(new_conds); List_iterator_fast it(new_cond_equal.current_level); /* - Creates multiple equalities new_cond_equal from new_conds list - equalities. If multiple equality can't be created or the condition - from new_conds list isn't an equality the method leaves it in new_conds + Create multiple equalities from the equalities of the list new_conds. + Save the created multiple equalities in new_cond_equal. + If multiple equality can't be created or the condition + from new_conds list isn't an equality leave it in new_conds list. The equality can't be converted into the multiple equality if it @@ -5664,150 +5664,224 @@ Item *and_new_conditions_to_optimized_cond(THD *thd, Item *cond, ((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC) { /* - cond is an AND-condition. - The method conjugates the AND-condition cond, created multiple - equalities new_cond_equal and remain conditions from new_conds. - - First, the method disjoins multiple equalities of cond and - merges new_cond_equal multiple equalities with these equalities. - It checks if after the merge the multiple equalities are knowingly - true or false equalities. - It attaches to cond the conditions from new_conds list and the result - of the merge of multiple equalities. The multiple equalities are - attached only to the upper level of AND-condition cond. So they - should be pushed down to the inner levels of cond AND-condition - if needed. It is done by propagate_new_equalities(). + Case when cond is an AND-condition. + Union AND-condition cond, created multiple equalities from + new_cond_equal and remaining conditions from new_conds. */ COND_EQUAL *cond_equal= &((Item_cond_and *) cond)->m_cond_equal; List *cond_equalities= &cond_equal->current_level; List *and_args= ((Item_cond_and *)cond)->argument_list(); - and_args->disjoin((List *) cond_equalities); - and_args->append(&new_conds); - while ((equality= it++)) + /* + Disjoin multiple equalities of cond. + Merge these multiple equalities with the multiple equalities of + new_cond_equal. Save the result in new_cond_equal. + Check if after the merge some multiple equalities are knowingly + true or false. + */ + and_args->disjoin((List *) cond_equalities); + while ((mult_eq= it++)) { - equality->upper_levels= 0; - equality->merge_into_list(thd, cond_equalities, false, false); + mult_eq->upper_levels= 0; + mult_eq->merge_into_list(thd, cond_equalities, false, false); } List_iterator_fast ei(*cond_equalities); - while ((equality= ei++)) + while ((mult_eq= ei++)) { - if (equality->const_item() && !equality->val_int()) + if (mult_eq->const_item() && !mult_eq->val_int()) is_simplified_cond= true; - equality->fixed= 0; - if (equality->fix_fields(thd, NULL)) - return NULL; + else + { + mult_eq->unfix_fields(); + if (mult_eq->fix_fields(thd, NULL)) + return NULL; + } } + li.rewind(); + while ((item=li++)) + { + /* + There still can be some equalities at not top level of new_conds + conditions that are not transformed into multiple equalities. + To transform them build_item_equal() is called. + + Examples of not top level equalities: + + 1. (t1.a = 3) OR (t1.b > 5) + (t1.a = 3) - not top level equality. + It is inside OR condition + + 2. ((t3.d = t3.c) AND (t3.c < 15)) OR (t3.d > 1) + (t1.d = t3.c) - not top level equality. + It is inside AND condition which is a part of OR condition + */ + if (item->type() == Item::COND_ITEM && + ((Item_cond *)item)->functype() == Item_func::COND_OR_FUNC) + { + item= item->build_equal_items(thd, + &((Item_cond_and *) cond)->m_cond_equal, + false, NULL); + } + /* + Check if equalities that can't be transformed into multiple + equalities are knowingly true or false. + */ + if (item->const_item() && !item->val_int()) + is_simplified_cond= true; + and_args->push_back(item, thd->mem_root); + } and_args->append((List *) cond_equalities); *cond_eq= &((Item_cond_and *) cond)->m_cond_equal; - - propagate_new_equalities(thd, cond, cond_equalities, - cond_equal->upper_levels, - &is_simplified_cond); - cond= cond->propagate_equal_fields(thd, - Item::Context_boolean(), - cond_equal); } else { /* - cond isn't AND-condition or is NULL. + Case when cond isn't an AND-condition or is NULL. There can be several cases: 1. cond is a multiple equality. - In this case cond is merged with the multiple equalities of + In this case merge cond with the multiple equalities of new_cond_equal. - The new condition is created with the conjunction of new_conds - list conditions and the result of merge of multiple equalities. + Create new condition from the created multiple equalities + and new_conds list conditions. 2. cond is NULL - The new condition is created from the conditions of new_conds - list and multiple equalities from new_cond_equal. + Create new condition from new_conds list conditions + and multiple equalities from new_cond_equal. 3. Otherwise - In this case the new condition is created from cond, remain conditions - from new_conds list and created multiple equalities from - new_cond_equal. + Create new condition through union of cond, conditions from new_conds + list and created multiple equalities from new_cond_equal. */ List new_conds_list; /* Flag is set to true if cond is a multiple equality */ bool is_mult_eq= (cond && cond->type() == Item::FUNC_ITEM && ((Item_func*) cond)->functype() == Item_func::MULT_EQUAL_FUNC); + /* + If cond is non-empty and is not multiple equality save it as + a part of a new condition. + */ if (cond && !is_mult_eq && new_conds_list.push_back(cond, thd->mem_root)) return NULL; - if (new_conds.elements > 0) - { - li.rewind(); - while ((item=li++)) - { - if (!item->is_fixed() && item->fix_fields(thd, NULL)) - return NULL; - if (item->const_item() && !item->val_int()) - is_simplified_cond= true; - } - new_conds_list.append(&new_conds); - } - + /* + If cond is a multiple equality merge it with new_cond_equal + multiple equalities. + */ if (is_mult_eq) { Item_equal *eq_cond= (Item_equal *)cond; eq_cond->upper_levels= 0; eq_cond->merge_into_list(thd, &new_cond_equal.current_level, false, false); + } - while ((equality= it++)) + /** + Fix created multiple equalities and check if they are knowingly + true or false. + */ + List_iterator_fast ei(new_cond_equal.current_level); + while ((mult_eq=ei++)) + { + if (mult_eq->const_item() && !mult_eq->val_int()) + is_simplified_cond= true; + else { - if (equality->const_item() && !equality->val_int()) - is_simplified_cond= true; - } - - if (new_cond_equal.current_level.elements + - new_conds_list.elements == 1) - { - it.rewind(); - equality= it++; - equality->fixed= 0; - if (equality->fix_fields(thd, NULL)) + mult_eq->unfix_fields(); + if (mult_eq->fix_fields(thd, NULL)) return NULL; } - (*cond_eq)->copy(new_cond_equal); + } + + /* + Create AND condition if new condition will have two or + more elements. + */ + Item_cond_and *and_cond= 0; + COND_EQUAL *inherited= 0; + if (new_conds_list.elements + + new_conds.elements + + new_cond_equal.current_level.elements > 1) + { + and_cond= new (thd->mem_root) Item_cond_and(thd); + and_cond->m_cond_equal.copy(new_cond_equal); + inherited= &and_cond->m_cond_equal; + } + + li.rewind(); + while ((item=li++)) + { + /* + Look for the comment in the case when cond is an + AND condition above the build_equal_items() call. + */ + if (item->type() == Item::COND_ITEM && + ((Item_cond *)item)->functype() == Item_func::COND_OR_FUNC) + { + item= item->build_equal_items(thd, inherited, false, NULL); + } + /* + Check if equalities that can't be transformed into multiple + equalities are knowingly true or false. + */ + if (item->const_item() && !item->val_int()) + is_simplified_cond= true; + new_conds_list.push_back(item, thd->mem_root); } new_conds_list.append((List *)&new_cond_equal.current_level); - if (new_conds_list.elements > 1) + if (and_cond) { - Item_cond_and *and_cond= - new (thd->mem_root) Item_cond_and(thd, new_conds_list); - - and_cond->m_cond_equal.copy(new_cond_equal); + and_cond->argument_list()->append(&new_conds_list); cond= (Item *)and_cond; - *cond_eq= &((Item_cond_and *)cond)->m_cond_equal; + *cond_eq= &((Item_cond_and *) cond)->m_cond_equal; } else { List_iterator_fast iter(new_conds_list); cond= iter++; + if (cond->type() == Item::FUNC_ITEM && + ((Item_func *)cond)->functype() == Item_func::MULT_EQUAL_FUNC) + { + if (!(*cond_eq)) + *cond_eq= new COND_EQUAL(); + (*cond_eq)->copy(new_cond_equal); + } + else + *cond_eq= 0; } + } - if (!cond->is_fixed() && cond->fix_fields(thd, NULL)) - return NULL; + if (!cond) + return NULL; - if (new_cond_equal.current_level.elements > 0) - cond= cond->propagate_equal_fields(thd, - Item::Context_boolean(), - &new_cond_equal); + if (*cond_eq) + { + /* + The multiple equalities are attached only to the upper level + of AND-condition cond. + Push them down to the bottom levels of cond AND-condition if needed. + */ + propagate_new_equalities(thd, cond, + &(*cond_eq)->current_level, + 0, + &is_simplified_cond); + cond= cond->propagate_equal_fields(thd, + Item::Context_boolean(), + *cond_eq); } /* - If it was found that some of the created condition parts are knowingly - true or false equalities the method calls removes_eq_cond() to remove them - from cond and set the cond_value to the appropriate value. + If it was found that there are some knowingly true or false equalities + remove them from cond and set cond_value to the appropriate value. */ - if (is_simplified_cond) + if (cond && is_simplified_cond) cond= cond->remove_eq_conds(thd, cond_value, true); + if (cond && cond->fix_fields_if_needed(thd, NULL)) + return NULL; + return cond; } @@ -6889,10 +6963,14 @@ bool Item_in_subselect::pushdown_cond_for_in_subquery(THD *thd, Item *cond) remaining_cond->transform(thd, &Item::in_subq_field_transformer_for_having, (uchar *)this); - if (!remaining_cond) + if (!remaining_cond || + remaining_cond->walk(&Item::cleanup_excluding_const_fields_processor, + 0, 0)) goto exit; - sel->mark_or_conds_to_avoid_pushdown(remaining_cond); + mark_or_conds_to_avoid_pushdown(remaining_cond); + + sel->cond_pushed_into_having= remaining_cond; exit: thd->lex->current_select= save_curr_select; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 5b32cf6598b..3567e790f78 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -865,7 +865,6 @@ THD::THD(my_thread_id id, bool is_wsrep_applier, bool skip_global_sys_var_lock) create_tmp_table_for_derived= FALSE; save_prep_leaf_list= FALSE; org_charset= 0; - having_pushdown= FALSE; /* Restore THR_THD */ set_current_thd(old_THR_THD); } diff --git a/sql/sql_class.h b/sql/sql_class.h index 3deb3d8cd23..f8dd9f78500 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -5032,8 +5032,6 @@ public: Item *sp_fix_func_item(Item **it_addr); Item *sp_prepare_func_item(Item **it_addr, uint cols= 1); bool sp_eval_expr(Field *result_field, Item **expr_item_ptr); - - bool having_pushdown; }; /** A short cut for thd->get_stmt_da()->set_ok_status(). */ diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 1ad97e4244d..548383e818c 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -47,7 +47,6 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived); bool mysql_derived_reinit(THD *thd, LEX *lex, TABLE_LIST *derived); bool mysql_derived_merge_for_insert(THD *thd, LEX *lex, TABLE_LIST *derived); - dt_processor processors[]= { &mysql_derived_init, @@ -1463,7 +1462,13 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived) if (!remaining_cond) continue; - sl->mark_or_conds_to_avoid_pushdown(remaining_cond); + if (remaining_cond->walk(&Item::cleanup_excluding_const_fields_processor, + 0, 0)) + continue; + + mark_or_conds_to_avoid_pushdown(remaining_cond); + + sl->cond_pushed_into_having= remaining_cond; } thd->lex->current_select= save_curr_select; DBUG_RETURN(false); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 22b1cfc91a3..4dc6b94465d 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -7893,11 +7893,9 @@ bool st_select_lex::collect_grouping_fields(THD *thd) */ void -st_select_lex::check_cond_extraction_for_grouping_fields(THD *thd, Item *cond, - Pushdown_checker checker) +st_select_lex::check_cond_extraction_for_grouping_fields(THD *thd, Item *cond) { - if (thd->having_pushdown && - cond->get_extraction_flag() == NO_EXTRACTION_FL) + if (cond->get_extraction_flag() == NO_EXTRACTION_FL) return; cond->clear_extraction_flag(); if (cond->type() == Item::COND_ITEM) @@ -7913,7 +7911,7 @@ st_select_lex::check_cond_extraction_for_grouping_fields(THD *thd, Item *cond, Item *item; while ((item=li++)) { - check_cond_extraction_for_grouping_fields(thd, item, checker); + check_cond_extraction_for_grouping_fields(thd, item); if (item->get_extraction_flag() != NO_EXTRACTION_FL) { count++; @@ -7938,7 +7936,7 @@ st_select_lex::check_cond_extraction_for_grouping_fields(THD *thd, Item *cond, } else { - int fl= ((cond->*checker) ((uchar *)this)) ? + int fl= cond->excl_dep_on_grouping_fields(this) ? FULL_EXTRACTION_FL : NO_EXTRACTION_FL; cond->set_extraction_flag(fl); } @@ -9569,46 +9567,42 @@ bool LEX::sp_proc_stmt_statement_finalize(THD *thd, bool no_lookahead) /** @brief - Extract from given item a condition pushable into WHERE clause + Extract the condition that can be pushed into WHERE clause @param thd the thread handle - @param cond the item to extract a condition to be pushed - into WHERE - @param remaining_cond the condition that will remain of cond after - the pushdown of its parts into the WHERE clause + @param cond the condition from which to extract a pushed condition + @param remaining_cond IN/OUT the condition that will remain of cond after + the extraction @param transformer the transformer callback function to be - applied to the condition so it can be pushed - down into the WHERE clause of this select + applied to the fields of the condition so it + can be pushed` @param arg parameter to be passed to the transformer @details - This method checks if cond entirely or its parts can be - pushed into the WHERE clause of this select and prepares it for pushing. + This function builds the most restrictive condition depending only on + the fields used in the GROUP BY of this SELECT. These fields were + collected before in grouping_tmp_fields list of this SELECT. - First it checks wherever this select doesn't have any aggregation function - in its projection and GROUP BY clause. If so cond can be entirely - pushed into the WHERE clause of this select but before its fields should - be transformed with transformer_for_where to make it pushable. + First this method checks if this SELECT doesn't have any aggregation + functions and has no GROUP BY clause. If so cond can be entirely pushed + into WHERE. + + Otherwise the method checks if there is a condition depending only on + grouping fields that can be extracted from cond. + + The condition that can be pushed into WHERE should be transformed. + It is done by transformer. - Otherwise the method checks wherever any condition depending only on - grouping fields can be extracted from cond. If there is any it prepares it - for pushing using grouping_field_transformer_for_where and if it happens to - be a conjunct of cond it removes it from cond. It saves the result of - removal in remaining_cond. The extracted condition is saved in cond_pushed_into_where of this select. - - @note - When looking for pushable condition the method considers only the grouping - fields from the list grouping_tmp_fields whose elements are of the type - Field_pair. This list must be prepared before the call of the - function. + cond can remain un empty after the extraction of the condition that can be + pushed into WHERE. It is saved in remaining_cond. @note This method is called for pushdown conditions into materialized derived tables/views optimization. Item::derived_field_transformer_for_where is passed as the actual callback function. - Also it is called for pushdown conditions into materialized IN subqueries. + Also it is called for pushdown into materialized IN subqueries. Item::in_subq_field_transformer_for_where is passed as the actual callback function. */ @@ -9624,8 +9618,7 @@ void st_select_lex::pushdown_cond_into_where_clause(THD *thd, Item *cond, if (have_window_funcs()) { Item *cond_over_partition_fields; - check_cond_extraction_for_grouping_fields(thd, cond, - &Item::dep_on_grouping_fields_checker); + check_cond_extraction_for_grouping_fields(thd, cond); cond_over_partition_fields= build_cond_for_grouping_fields(thd, cond, true); if (cond_over_partition_fields) @@ -9657,19 +9650,17 @@ void st_select_lex::pushdown_cond_into_where_clause(THD *thd, Item *cond, } /* - Figure out what can be extracted from cond - that could be pushed into the WHERE clause of this select + Figure out what can be extracted from cond and pushed into + the WHERE clause of this select. */ Item *cond_over_grouping_fields; - check_cond_extraction_for_grouping_fields(thd, cond, - &Item::dep_on_grouping_fields_checker); + check_cond_extraction_for_grouping_fields(thd, cond); cond_over_grouping_fields= build_cond_for_grouping_fields(thd, cond, true); /* - Transform the references to the columns from the cond - pushed into the WHERE clause of this select to make them usable in - the new context + Transform references to the columns of condition that can be pushed + into WHERE so it can be pushed. */ if (cond_over_grouping_fields) cond_over_grouping_fields= cond_over_grouping_fields->transform(thd, @@ -9680,7 +9671,7 @@ void st_select_lex::pushdown_cond_into_where_clause(THD *thd, Item *cond, { /* - In cond remove top conjuncts that has been pushed into the WHERE + Remove top conjuncts in cond that has been pushed into the WHERE clause of this select */ cond= remove_pushed_top_conjuncts(thd, cond); @@ -9698,14 +9689,14 @@ void st_select_lex::pushdown_cond_into_where_clause(THD *thd, Item *cond, @brief Mark OR-conditions as non-pushable to avoid repeatable pushdown - @param cond The condition that should be marked (or its subformulas) + @param cond the processed condition @details - In the case when OR-condition can be pushed into the HAVING clause - of the materialized derived table/view/IN subquery and some of - its parts can be pushed into the WHERE clause it can cause - repeatable pushdown in the pushdown from HAVING into WHERE clause. - Example: + Consider pushdown into the materialized derived table/view. + Consider OR condition that can be pushed into HAVING and some + parts of this OR condition that can be pushed into WHERE. + + On example: SELECT * FROM t1, @@ -9716,8 +9707,15 @@ void st_select_lex::pushdown_cond_into_where_clause(THD *thd, Item *cond, WHERE ((dt.m_c>10) AND (dt.a>2)) OR ((dt.m_c<7) and (dt.a<3)) AND (t1.a=v1.a); - after the pushdown into the materialized views/derived tables optimization - is done: + + Here ((dt.m_c>10) AND (dt.a>2)) OR ((dt.m_c<7) and (dt.a<3)) or1 + can be pushed down into the HAVING of the materialized + derived table dt. + + (dt.a>2) OR (dt.a<3) part of or1 depends only on grouping fields + of dt and can be pushed into WHERE. + + As a result: SELECT * FROM t1, @@ -9730,21 +9728,23 @@ void st_select_lex::pushdown_cond_into_where_clause(THD *thd, Item *cond, WHERE ((dt.m_c>10) AND (dt.a>2)) OR ((dt.m_c<7) and (dt.a<3)) AND (t1.a=v1.a); - In the optimization stage for the select that defines derived table - in the pushdown from HAVING into WHERE optimization - (dt.a>2) OR (dt.a<3) will be again extracted from - ((dt.m_c>10) AND (dt.a>2)) OR ((dt.m_c<7) and (dt.a<3)) - and pushed into the WHERE clause of the select that defines derived table. - To avoid it after conditions are pushed into the materialized derived - tables/views or IN subqueries OR-conditions that were pushed are marked - with NO_EXTRACTION_FL flag to avoid repeatable pushdown. + Here (dt.a>2) OR (dt.a<3) also remains in HAVING of dt. + When SELECT that defines df is processed HAVING pushdown optimization + is made. In HAVING pushdown optimization it will extract + (dt.a>2) OR (dt.a<3) condition from or1 again and push it into WHERE. + This will cause duplicate conditions in WHERE of dt. + + To avoid repeatable pushdown such OR conditions as or1 describen + above are marked with NO_EXTRACTION_FL. + + @note + This method is called for pushdown into materialized + derived tables/views/IN subqueries optimization. */ -void st_select_lex::mark_or_conds_to_avoid_pushdown(Item *cond) +void mark_or_conds_to_avoid_pushdown(Item *cond) { - cond->walk(&Item::cleanup_excluding_const_fields_processor, 0, 0); - if (cond->type() == Item::COND_ITEM && ((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC) { @@ -9760,37 +9760,55 @@ void st_select_lex::mark_or_conds_to_avoid_pushdown(Item *cond) else if (cond->type() == Item::COND_ITEM && ((Item_cond*) cond)->functype() == Item_func::COND_OR_FUNC) cond->set_extraction_flag(NO_EXTRACTION_FL); - - cond_pushed_into_having= cond; } /** @brief - Gets conditions that can be pushed down for pushdown from HAVING into WHERE + Get condition that can be pushed from HAVING into WHERE - @param thd The thread handle - @param cond The condition from which the condition depended on grouping - fields is to be extracted - @param checker The checker callback function to be applied to the nodes - of the tree of the object + @param thd the thread handle + @param cond the condition from which to extract the condition @details - The method finds out what conditions can be extracted from cond depended - only on the grouping fields of this SELECT or fields equal to them. - If the condition that can be pushed is AND-condition it is splitted up - and for each its element it is checked if it can be pushed. - Pushable elements are attached to the attach_to_conds list. - If the condition isn't AND-condition it is entirely pushed into - the attach_to_conds list. If the condition that is extracted is a multiple - equality it is transformed into the set of equalities. + The method collects in attach_to_conds list conditions from cond + that can be pushed from HAVING into WHERE. - attach_to_conds list is created to be passed to - and_new_conditions_to_optimized_cond() method so extracted conditions can - be joined to the already optimized WHERE clause in the right way. + Conditions that can be pushed were marked with FULL_EXTRACTION_FL in + check_cond_extraction_for_grouping_fields() method. + Conditions that can't be pushed were marked with NO_EXTRACTION_FL. + Conditions which parts can be pushed weren't marked. + + There are two types of conditions that can be pushed: + 1. Condition that can be simply moved from HAVING + (if cond is marked with FULL_EXTRACTION_FL or + cond is an AND condition and some of its parts are marked with + FULL_EXTRACTION_FL) + In this case condition is transformed and pushed into attach_to_conds + list. + 2. Part of some other condition c1 that can't be entirely pushed + (if с1 isn't marked with any flag). + + For example: + + SELECT t1.a,MAX(t1.b),t1.c + FROM t1 + GROUP BY t1.a + HAVING ((t1.a > 5) AND (t1.c < 3)) OR (t1.a = 3); + + Here (t1.a > 5) OR (t1.a = 3) from HAVING can be pushed into WHERE. + + In this case build_pushable_cond() is called for c1. + This method builds a clone of the c1 part that can be pushed. + + Transformation mentioned above is made with multiple_equality_transformer + transformer. It transforms all multiple equalities in the extracted + condition into the set of equalities. @note - The method is similar to st_select_lex::build_cond_for_grouping_fields() and - Item::build_pushable_cond(). + Conditions that can be pushed are collected in attach_to_conds in this way: + 1. if cond is an AND condition its parts that can be pushed into WHERE + are added to attach_to_conds list separately. + 2. in all other cases conditions are pushed into the list entirely. @retval true - if an error occurs @@ -9798,101 +9816,107 @@ void st_select_lex::mark_or_conds_to_avoid_pushdown(Item *cond) */ bool -st_select_lex::build_pushable_cond_for_having_pushdown(THD *thd, - Item *cond) +st_select_lex::build_pushable_cond_for_having_pushdown(THD *thd, Item *cond) { - Pushdown_checker checker= - &Item::pushable_equality_checker_for_having_pushdown; - - bool is_multiple_equality= cond->type() == Item::FUNC_ITEM && - ((Item_func*) cond)->functype() == Item_func::MULT_EQUAL_FUNC; + List equalities; + /* Condition can't be pushed */ if (cond->get_extraction_flag() == NO_EXTRACTION_FL) return false; - if (cond->type() == Item::COND_ITEM) + /** + Condition can be pushed entirely. + Transform its multiple equalities and add to attach_to_conds list. + */ + if (cond->get_extraction_flag() == FULL_EXTRACTION_FL) + { + Item *result= cond->transform(thd, + &Item::multiple_equality_transformer, + (uchar *)this); + if (!result) + return true; + if (result->type() == Item::COND_ITEM && + ((Item_cond*) result)->functype() == Item_func::COND_AND_FUNC) + { + List_iterator li(*((Item_cond*) result)->argument_list()); + Item *item; + while ((item=li++)) + { + if (attach_to_conds.push_back(item, thd->mem_root)) + return true; + } + } + else + { + if (attach_to_conds.push_back(result, thd->mem_root)) + return true; + } + return false; + } + + /** + There is no flag set for this condition. It means that some + part of this condition can be pushed. + */ + if (cond->type() != Item::COND_ITEM) + return false; + if (((Item_cond *)cond)->functype() != Item_cond::COND_AND_FUNC) + { + Item *fix= cond->build_pushable_cond(thd, 0, 0); + if (!fix) + return false; + if (attach_to_conds.push_back(fix, thd->mem_root)) + return true; + } + else { - bool cond_and= false; - if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC) - cond_and= true; - List equalities; - List new_conds; List_iterator li(*((Item_cond*) cond)->argument_list()); Item *item; - while ((item=li++)) { if (item->get_extraction_flag() == NO_EXTRACTION_FL) continue; - - if (item->type() == Item::FUNC_ITEM && - ((Item_func*) item)->functype() == Item_func::MULT_EQUAL_FUNC) + else if (item->get_extraction_flag() == FULL_EXTRACTION_FL) { - equalities.empty(); - if (((Item_equal*) item)->create_pushable_equalities(thd, &equalities, - checker, (uchar *)this)) + Item *result= item->transform(thd, + &Item::multiple_equality_transformer, + (uchar *)item); + + if (!result) return true; - if (equalities.elements != 0) + if (result->type() == Item::COND_ITEM && + ((Item_cond*) result)->functype() == Item_func::COND_AND_FUNC) { - if (cond_and) - new_conds.append(&equalities); - else + List_iterator li(*((Item_cond*) result)->argument_list()); + Item *item; + while ((item=li++)) { - Item_cond_and *new_cond= - new (thd->mem_root) Item_cond_and(thd, equalities); - if (!new_cond || new_conds.push_back(new_cond, thd->mem_root)) + if (attach_to_conds.push_back(item, thd->mem_root)) return true; } } - else if (!cond_and) - return true; - continue; + else + { + if (attach_to_conds.push_back(result, thd->mem_root)) + return true; + } } - - Item *fix= item->build_pushable_cond(thd, checker, (uchar *)this); - - if (!fix && !cond_and) + else { - attach_to_conds.empty(); - return false; + Item *fix= item->build_pushable_cond(thd, 0, 0); + if (!fix) + continue; + if (attach_to_conds.push_back(fix, thd->mem_root)) + return true; } - if (!fix) - continue; - - if (new_conds.push_back(fix, thd->mem_root)) - return true; } - if (!cond_and) - { - Item_cond_or *new_cond= new (thd->mem_root) Item_cond_or(thd, new_conds); - if (attach_to_conds.push_back(new_cond, thd->mem_root)) - return true; - } - else - attach_to_conds.append(&new_conds); - } - else if (is_multiple_equality) - { - List equalities; - Item_equal *item_equal= (Item_equal *)cond; - if (item_equal->create_pushable_equalities(thd, &equalities, - checker, (uchar *)this)) - return true; - attach_to_conds.append(&equalities); - return false; - } - else if (cond->get_extraction_flag() != NO_EXTRACTION_FL) - { - Item *copy= cond->build_clone(thd); - if (attach_to_conds.push_back(copy, thd->mem_root)) - return true; } return false; } /** - Check if the item is equal to some field in Field_pair 'field_pair' + Check if item is equal to some field in Field_pair 'field_pair' from 'pair_list' and return found 'field_pair' if it exists. */ @@ -9918,15 +9942,14 @@ Field_pair *get_corresponding_field_pair(Item *item, /** @brief - Collect fields in multiple equalities usable for pushdown from having + Collect fields from multiple equalities which are equal to grouping - @param thd The thread handle + @param thd the thread handle @details - This method looks through the multiple equalities of the WHERE clause - trying to find any of them whose fields are used in the GROUP BY of the - SELECT. Any field from these multiple equality is included into the - the list of fields against which any candidate for pushing is checked. + This method checks if multiple equalities of the WHERE clause contain + fields from GROUP BY of this SELECT. If so all fields of such multiple + equalities are collected in grouping_tmp_fields list without repetitions. @retval true - if an error occurs @@ -9967,68 +9990,17 @@ bool st_select_lex::collect_fields_equal_to_grouping(THD *thd) return false; } -/** - @brief - Cleanup and fix of the condition that is ready to be pushed down - - @param thd The thread handle - @param cond The condition to be processed - - @details - This method recursively traverses cond making cleanup and fix - where needed. - There is no need to make cleanup and fix for multiple equalities as - they are created so they can be immediately pushed down. - - @retval - true - if an error occurs - false - otherwise -*/ - -static -bool cleanup_condition_pushed_from_having(THD *thd, Item *cond) -{ - if (cond->type() == Item::FUNC_ITEM && - ((Item_func*) cond)->functype() == Item_func::MULT_EQUAL_FUNC) - return false; - - if (cond->type() == Item::COND_ITEM) - { - List_iterator_fast it(*((Item_cond *)cond)->argument_list()); - Item *item; - - while ((item=it++)) - cleanup_condition_pushed_from_having(thd, item); - } - else - { - cond->walk(&Item::cleanup_excluding_const_fields_processor, 0, 0); - if (cond->fix_fields(thd, NULL)) - return true; - } - return false; -} - /** @brief - Remove marked top conjuncts of condition for pushdown from HAVING into WHERE + Remove marked top conjuncts of HAVING for having pushdown - @param thd The thread handle - @param cond The condition which subformulas are to be removed + @param thd the thread handle + @param cond the condition which subformulas are to be removed @details - The function behavior is similar to remove_pushed_top_conjuncts() - except the case when 'cond' is the AND-condition. - As in the pushdown from HAVING into WHERE conditions are not just cloned - so they can be later pushed down as it is for pushdown into materialized - derived tables/views or IN subqueries, but also should be removed from - the HAVING clause. - The multiple equalities of the HAVING clause are not removed in this - function, but rather marked as to be removed later. Their removal is - done in substitute_for_best_equal_field() called for HAVING at the moment - when all multiple equalities referencing the top level multiple equalities - have been already eliminated. + This method removes from cond all subformulas that can be moved from HAVING + into WHERE. @retval condition without removed subformulas @@ -10037,43 +10009,47 @@ bool cleanup_condition_pushed_from_having(THD *thd, Item *cond) Item *remove_pushed_top_conjuncts_for_having(THD *thd, Item *cond) { + /* Nothing to extract */ + if (cond->get_extraction_flag() == NO_EXTRACTION_FL) + { + cond->clear_extraction_flag(); + return cond; + } + /* cond can be pushed in WHERE entirely */ if (cond->get_extraction_flag() == FULL_EXTRACTION_FL) { cond->clear_extraction_flag(); - if (cond->type() == Item::FUNC_ITEM && - ((Item_func*) cond)->functype() == Item_func::MULT_EQUAL_FUNC) - { - cond->set_extraction_flag(DELETION_FL); - return cond; - } return 0; } - if (cond->type() != Item::COND_ITEM) - return cond; - if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC) + /* Some parts of cond can be pushed */ + if (cond->type() == Item::COND_ITEM && + ((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC) { - List *cond_arg_list= ((Item_cond_and *)cond)->argument_list(); - List_iterator li(*cond_arg_list); + List_iterator li(*((Item_cond*) cond)->argument_list()); Item *item; - while ((item= li++)) + while ((item=li++)) { - if (item->get_extraction_flag() == FULL_EXTRACTION_FL) - { + if (item->get_extraction_flag() == NO_EXTRACTION_FL) item->clear_extraction_flag(); + else if (item->get_extraction_flag() == FULL_EXTRACTION_FL) + { if (item->type() == Item::FUNC_ITEM && ((Item_func*) item)->functype() == Item_func::MULT_EQUAL_FUNC) item->set_extraction_flag(DELETION_FL); else + { + item->clear_extraction_flag(); li.remove(); + } } } - switch (cond_arg_list->elements) + switch (((Item_cond*) cond)->argument_list()->elements) { case 0: return 0; case 1: - return (cond_arg_list->head()); + return (((Item_cond*) cond)->argument_list()->head()); default: return cond; } @@ -10084,19 +10060,21 @@ Item *remove_pushed_top_conjuncts_for_having(THD *thd, Item *cond) /** @brief - Extract condition that can be pushed from HAVING clause into WHERE clause + Extract condition that can be pushed from HAVING into WHERE @param thd the thread handle @param having the HAVING clause of this select @param having_equal multiple equalities of HAVING @details - This function builds the most restrictive condition depending only on - the fields used in the GROUP BY of this select (directly or indirectly - through equality) that can be extracted from the HAVING clause of this - select and pushes it into the WHERE clause of this select. + This method builds a set of conditions dependent only on + fields used in the GROUP BY of this select (directly or indirectly + through equalities). These conditions are extracted from the HAVING + clause of this select. + The method saves these conditions into attach_to_conds list and removes + from HAVING conditions that can be entirely pushed into WHERE. - Example of the transformation: + Example of the HAVING pushdown transformation: SELECT t1.a,MAX(t1.b) FROM t1 @@ -10111,14 +10089,27 @@ Item *remove_pushed_top_conjuncts_for_having(THD *thd, Item *cond) GROUP BY t1.a HAVING (MAX(c)>12); + In this method (t1.a>2) is not attached to the WHERE clause. + It is pushed into the attach_to_conds list to be attached to + the WHERE clause later. + In details: 1. Collect fields used in the GROUP BY grouping_fields of this SELECT 2. Collect fields equal to grouping_fields from the WHERE clause of this SELECT and add them to the grouping_fields list. 3. Extract the most restrictive condition from the HAVING clause of this select that depends only on the grouping fields (directly or indirectly - through equality). Store it in the attach_to_conds list. - 4. Remove pushable conditions from the HAVING clause if it's possible. + through equality). + If the extracted condition is an AND condition it is transformed into a + list of all its conjuncts saved in attach_to_conds. Otherwise, + the condition is put into attach_to_conds as the only its element. + 4. Remove conditions from HAVING clause that can be entirely pushed + into WHERE. + Multiple equalities are not removed but marked with DELETION_FL flag. + They will be deleted later in substitite_for_best_equal_field() called + for the HAVING condition. + 5. Unwrap fields wrapped in Item_ref wrappers contain in the condition + of attach_to_conds so the condition could be pushed into WHERE. @note This method is similar to st_select_lex::pushdown_cond_into_where_clause(). @@ -10149,56 +10140,84 @@ Item *st_select_lex::pushdown_from_having_into_where(THD *thd, Item *having) /* 3. Extract the most restrictive condition from the HAVING clause of this select that depends only on the grouping fields (directly or indirectly - through equality). Store it in the attach_to_conds list. + through equality). + If the extracted condition is an AND condition it is transformed into a + list of all its conjuncts saved in attach_to_conds. Otherwise, + the condition is put into attach_to_conds as the only its element. */ - thd->having_pushdown= true; List_iterator_fast it(attach_to_conds); Item *item; - check_cond_extraction_for_grouping_fields(thd, having, - &Item::dep_on_grouping_fields_checker_for_having_pushdown); + check_cond_extraction_for_grouping_fields(thd, having); if (build_pushable_cond_for_having_pushdown(thd, having)) { attach_to_conds.empty(); goto exit; } - if (attach_to_conds.elements != 0) - { - /* - 4. Remove pushable conditions from the HAVING clause if it's possible. - */ - having= remove_pushed_top_conjuncts_for_having(thd, having); + if (!attach_to_conds.elements) + goto exit; - it.rewind(); - while ((item=it++)) - { - if (cleanup_condition_pushed_from_having(thd, item)) - { - attach_to_conds.empty(); - goto exit; - } - } - /* - Refresh having_equal as some of the multiple equalities of - having can be removed after pushdown. - */ + /* + 4. Remove conditions from HAVING clause that can be entirely pushed + into WHERE. + Multiple equalities are not removed but marked with DELETION_FL flag. + They will be deleted later in substitite_for_best_equal_field() called + for the HAVING condition. + */ + having= remove_pushed_top_conjuncts_for_having(thd, having); + + /* + Change join->cond_equal which points to the multiple equalities of + the top level of HAVING. + Removal of AND conditions may leave only one conjunct in HAVING. + + Example 1: + SELECT * + FROM t1 + GROUP BY t1.a + (t1.a < 2) AND (t1.b = 2) + + (t1.a < 2) is pushed into WHERE. + join->cond_equal should point on (t1.b = 2) multiple equality now. + + Example 2: + SELECT * + FROM t1 + GROUP BY t1.a + (t1.a = 2) AND (t1.b < 2) + + (t1.a = 2) is pushed into WHERE. + join->cond_equal should be NULL now. + */ + if (having && + having->type() == Item::FUNC_ITEM && + ((Item_func*) having)->functype() == Item_func::MULT_EQUAL_FUNC) + join->having_equal= new (thd->mem_root) COND_EQUAL((Item_equal *)having, + thd->mem_root); + else if (!having || + having->type() != Item::COND_ITEM || + ((Item_cond *)having)->functype() != Item_cond::COND_AND_FUNC) join->having_equal= 0; - if (having) + + /* + 5. Unwrap fields wrapped in Item_ref wrappers contain in the condition + of attach_to_conds so the condition could be pushed into WHERE. + */ + it.rewind(); + while ((item=it++)) + { + item= item->transform(thd, + &Item::field_transformer_for_having_pushdown, + (uchar *)this); + + if (item->walk(&Item::cleanup_processor, 0, 0) || + item->fix_fields(thd, NULL)) { - if (having->type() == Item::COND_ITEM && - ((Item_cond*) having)->functype() == Item_func::COND_AND_FUNC) - { - Item_cond_and *and_having= (Item_cond_and *)having; - join->having_equal= &and_having->m_cond_equal; - } - if (having->type() == Item::FUNC_ITEM && - ((Item_func*) having)->functype() == Item_func::MULT_EQUAL_FUNC) - join->having_equal= new (thd->mem_root) COND_EQUAL((Item_equal *)having, - thd->mem_root); + attach_to_conds.empty(); + goto exit; } } exit: thd->lex->current_select= save_curr_select; - thd->having_pushdown= false; return having; } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 1060e1e1c5e..8d5c2484cbf 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1479,8 +1479,7 @@ public: void collect_grouping_fields_for_derived(THD *thd, ORDER *grouping_list); bool collect_grouping_fields(THD *thd); bool collect_fields_equal_to_grouping(THD *thd); - void check_cond_extraction_for_grouping_fields(THD *thd, Item *cond, - Pushdown_checker excl_dep); + void check_cond_extraction_for_grouping_fields(THD *thd, Item *cond); Item *build_cond_for_grouping_fields(THD *thd, Item *cond, bool no_to_clones); @@ -1506,13 +1505,11 @@ public: bool cond_pushdown_is_allowed() const { return !olap && !explicit_limit && !tvc; } - bool build_pushable_cond_for_having_pushdown(THD *thd, - Item *cond); + bool build_pushable_cond_for_having_pushdown(THD *thd, Item *cond); void pushdown_cond_into_where_clause(THD *thd, Item *extracted_cond, Item **remaining_cond, Item_transformer transformer, uchar *arg); - void mark_or_conds_to_avoid_pushdown(Item *cond); Item *pushdown_from_having_into_where(THD *thd, Item *having); select_handler *find_select_handler(THD *thd); @@ -4790,5 +4787,7 @@ Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal, void sp_create_assignment_lex(THD *thd, bool no_lookahead); bool sp_create_assignment_instr(THD *thd, bool no_lookahead); +void mark_or_conds_to_avoid_pushdown(Item *cond); + #endif /* MYSQL_SERVER */ #endif /* SQL_LEX_INCLUDED */ diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c619cd4e066..676a73d5958 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1958,9 +1958,7 @@ JOIN::optimize_inner() { conds= and_new_conditions_to_optimized_cond(thd, conds, &cond_equal, select_lex->attach_to_conds, - &cond_value, true); - if (conds && !conds->is_fixed() && conds->fix_fields(thd, &conds)) - DBUG_RETURN(1); + &cond_value); sel->attach_to_conds.empty(); } } @@ -1983,48 +1981,13 @@ JOIN::optimize_inner() if (eq_list.elements != 0) { conds= and_new_conditions_to_optimized_cond(thd, conds, &cond_equal, - eq_list, &cond_value, false); + eq_list, &cond_value); if (!conds && cond_value != Item::COND_FALSE && cond_value != Item::COND_TRUE) DBUG_RETURN(TRUE); } - { - if (select_lex->where) - { - select_lex->cond_value= cond_value; - if (sel->where != conds && cond_value == Item::COND_OK) - thd->change_item_tree(&sel->where, conds); - } - if (select_lex->having) - { - select_lex->having_value= having_value; - if (sel->having != having && having_value == Item::COND_OK) - thd->change_item_tree(&sel->having, having); - } - if (cond_value == Item::COND_FALSE || having_value == Item::COND_FALSE || - (!unit->select_limit_cnt && !(select_options & OPTION_FOUND_ROWS))) - { /* Impossible cond */ - if (unit->select_limit_cnt) - { - DBUG_PRINT("info", (having_value == Item::COND_FALSE ? - "Impossible HAVING" : "Impossible WHERE")); - zero_result_cause= having_value == Item::COND_FALSE ? - "Impossible HAVING" : "Impossible WHERE"; - } - else - { - DBUG_PRINT("info", ("Zero limit")); - zero_result_cause= "Zero limit"; - } - table_count= top_join_tab_count= 0; - error= 0; - subq_exit_fl= true; - goto setup_subq_exit; - } - } - if (optimizer_flag(thd, OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED)) { TABLE_LIST *tbl; @@ -2062,6 +2025,40 @@ JOIN::optimize_inner() if (select_lex->handle_derived(thd->lex, DT_OPTIMIZE)) DBUG_RETURN(1); } + { + if (select_lex->where) + { + select_lex->cond_value= cond_value; + if (sel->where != conds && cond_value == Item::COND_OK) + thd->change_item_tree(&sel->where, conds); + } + if (select_lex->having) + { + select_lex->having_value= having_value; + if (sel->having != having && having_value == Item::COND_OK) + thd->change_item_tree(&sel->having, having); + } + if (cond_value == Item::COND_FALSE || having_value == Item::COND_FALSE || + (!unit->select_limit_cnt && !(select_options & OPTION_FOUND_ROWS))) + { /* Impossible cond */ + if (unit->select_limit_cnt) + { + DBUG_PRINT("info", (having_value == Item::COND_FALSE ? + "Impossible HAVING" : "Impossible WHERE")); + zero_result_cause= having_value == Item::COND_FALSE ? + "Impossible HAVING" : "Impossible WHERE"; + } + else + { + DBUG_PRINT("info", ("Zero limit")); + zero_result_cause= "Zero limit"; + } + table_count= top_join_tab_count= 0; + error= 0; + subq_exit_fl= true; + goto setup_subq_exit; + } + } #ifdef WITH_PARTITION_STORAGE_ENGINE { @@ -15316,8 +15313,9 @@ Item *eliminate_item_equal(THD *thd, COND *cond, COND_EQUAL *upper_levels, */ Item *head_item= (!item_const && current_sjm && current_sjm_head != field_item) ? current_sjm_head: head; - - eq_item= new (thd->mem_root) Item_func_eq(thd, field_item, head_item); + eq_item= new (thd->mem_root) Item_func_eq(thd, + field_item->remove_item_direct_ref(), + head_item->remove_item_direct_ref()); if (!eq_item || eq_item->set_cmp_func()) return 0; diff --git a/sql/sql_select.h b/sql/sql_select.h index 55ab94186ad..482b4ff9608 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -228,8 +228,7 @@ Item *remove_pushed_top_conjuncts(THD *thd, Item *cond); Item *and_new_conditions_to_optimized_cond(THD *thd, Item *cond, COND_EQUAL **cond_eq, List &new_conds, - Item::cond_result *cond_value, - bool build_cond_equal); + Item::cond_result *cond_value); #include "sql_explain.h"