summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/derived_cond_pushdown.result196
-rw-r--r--mysql-test/t/derived_cond_pushdown.test56
-rw-r--r--sql/item.cc11
-rw-r--r--sql/sql_lex.cc1
-rw-r--r--sql/sql_lex.h5
-rw-r--r--sql/sql_select.cc2
6 files changed, 267 insertions, 4 deletions
diff --git a/mysql-test/r/derived_cond_pushdown.result b/mysql-test/r/derived_cond_pushdown.result
index 3fbc81019cc..83e70dd634c 100644
--- a/mysql-test/r/derived_cond_pushdown.result
+++ b/mysql-test/r/derived_cond_pushdown.result
@@ -9473,3 +9473,199 @@ WHERE (a>0 AND a<2 OR a IN (2,3)) AND
a
2
DROP TABLE t1;
+#
+# MDEV-16386: pushing condition into the HAVING clause when ambiguous
+# fields warning appears
+#
+CREATE TABLE t1 (a INT, b INT);
+INSERT INTO t1 VALUES (1,2),(2,3),(3,4);
+SELECT * FROM
+(
+SELECT t1.b AS a
+FROM t1
+GROUP BY t1.a
+) dt
+WHERE (dt.a=2);
+a
+2
+EXPLAIN FORMAT=JSON SELECT * FROM
+(
+SELECT t1.b AS a
+FROM t1
+GROUP BY t1.a
+) dt
+WHERE (dt.a=2);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ALL",
+ "rows": 3,
+ "filtered": 100,
+ "attached_condition": "dt.a = 2",
+ "materialized": {
+ "query_block": {
+ "select_id": 2,
+ "having_condition": "a = 2",
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 3,
+ "filtered": 100
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+SELECT * FROM
+(
+SELECT t1.b AS a
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a<3)
+) dt
+WHERE (dt.a>1);
+a
+2
+3
+EXPLAIN FORMAT=JSON SELECT * FROM
+(
+SELECT t1.b AS a
+FROM t1
+GROUP BY t1.a
+HAVING (t1.a<3)
+) dt
+WHERE (dt.a>1);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ALL",
+ "rows": 3,
+ "filtered": 100,
+ "attached_condition": "dt.a > 1",
+ "materialized": {
+ "query_block": {
+ "select_id": 2,
+ "having_condition": "t1.a < 3 and a > 1",
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 3,
+ "filtered": 100
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+SELECT * FROM
+(
+SELECT 'ab' AS a
+FROM t1
+GROUP BY t1.a
+) dt
+WHERE (dt.a='ab');
+a
+ab
+ab
+ab
+EXPLAIN FORMAT=JSON SELECT * FROM
+(
+SELECT 'ab' AS a
+FROM t1
+GROUP BY t1.a
+) dt
+WHERE (dt.a='ab');
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ALL",
+ "rows": 3,
+ "filtered": 100,
+ "attached_condition": "dt.a = 'ab'",
+ "materialized": {
+ "query_block": {
+ "select_id": 2,
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 3,
+ "filtered": 100
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+SELECT * FROM
+(
+SELECT 1 AS a
+FROM t1
+GROUP BY t1.a
+) dt
+WHERE (dt.a=1);
+a
+1
+1
+1
+EXPLAIN FORMAT=JSON SELECT * FROM
+(
+SELECT 1 AS a
+FROM t1
+GROUP BY t1.a
+) dt
+WHERE (dt.a=1);
+EXPLAIN
+{
+ "query_block": {
+ "select_id": 1,
+ "table": {
+ "table_name": "<derived2>",
+ "access_type": "ALL",
+ "rows": 3,
+ "filtered": 100,
+ "attached_condition": "dt.a = 1",
+ "materialized": {
+ "query_block": {
+ "select_id": 2,
+ "filesort": {
+ "sort_key": "t1.a",
+ "temporary_table": {
+ "table": {
+ "table_name": "t1",
+ "access_type": "ALL",
+ "rows": 3,
+ "filtered": 100
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+DROP TABLE t1;
diff --git a/mysql-test/t/derived_cond_pushdown.test b/mysql-test/t/derived_cond_pushdown.test
index d3832ce1ec3..718140d3a77 100644
--- a/mysql-test/t/derived_cond_pushdown.test
+++ b/mysql-test/t/derived_cond_pushdown.test
@@ -1745,3 +1745,59 @@ WHERE (a>0 AND a<2 OR a IN (2,3)) AND
(a=2 OR 0);
DROP TABLE t1;
+
+--echo #
+--echo # MDEV-16386: pushing condition into the HAVING clause when ambiguous
+--echo # fields warning appears
+--echo #
+
+CREATE TABLE t1 (a INT, b INT);
+
+INSERT INTO t1 VALUES (1,2),(2,3),(3,4);
+
+LET $query=
+SELECT * FROM
+(
+ SELECT t1.b AS a
+ FROM t1
+ GROUP BY t1.a
+) dt
+WHERE (dt.a=2);
+EVAL $query;
+EVAL EXPLAIN FORMAT=JSON $query;
+
+LET $query=
+SELECT * FROM
+(
+ SELECT t1.b AS a
+ FROM t1
+ GROUP BY t1.a
+ HAVING (t1.a<3)
+) dt
+WHERE (dt.a>1);
+EVAL $query;
+EVAL EXPLAIN FORMAT=JSON $query;
+
+LET $query=
+SELECT * FROM
+(
+ SELECT 'ab' AS a
+ FROM t1
+ GROUP BY t1.a
+) dt
+WHERE (dt.a='ab');
+EVAL $query;
+EVAL EXPLAIN FORMAT=JSON $query;
+
+LET $query=
+SELECT * FROM
+(
+ SELECT 1 AS a
+ FROM t1
+ GROUP BY t1.a
+) dt
+WHERE (dt.a=1);
+EVAL $query;
+EVAL EXPLAIN FORMAT=JSON $query;
+
+DROP TABLE t1;
diff --git a/sql/item.cc b/sql/item.cc
index f9200ccf56d..4bc6fe7e5bc 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -4984,9 +4984,11 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list)
in the SELECT clause of Q.
- Search for a column named col_ref_i [in table T_j]
in the GROUP BY clause of Q.
- - If found different columns with the same name in GROUP BY and SELECT
- - issue a warning and return the GROUP BY column,
- - otherwise
+ - If found different columns with the same name in GROUP BY and SELECT:
+ - if the condition that uses this column name is pushed down into
+ the HAVING clause return the SELECT column
+ - else issue a warning and return the GROUP BY column.
+ - Otherwise
- if the MODE_ONLY_FULL_GROUP_BY mode is enabled return error
- else return the found SELECT column.
@@ -5025,7 +5027,8 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select)
/* Check if the fields found in SELECT and GROUP BY are the same field. */
if (group_by_ref && (select_ref != not_found_item) &&
- !((*group_by_ref)->eq(*select_ref, 0)))
+ !((*group_by_ref)->eq(*select_ref, 0)) &&
+ (!select->having_fix_field_for_pushed_cond))
{
ambiguous_fields= TRUE;
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 750fb75bfb9..d3ddd9e208c 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -2107,6 +2107,7 @@ void st_select_lex::init_query()
cond_pushed_into_where= cond_pushed_into_having= 0;
olap= UNSPECIFIED_OLAP_TYPE;
having_fix_field= 0;
+ having_fix_field_for_pushed_cond= 0;
context.select_lex= this;
context.init();
/*
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index ed5e423fd5a..a1f6b202ae6 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -887,6 +887,11 @@ public:
bool braces; /* SELECT ... UNION (SELECT ... ) <- this braces */
/* TRUE when having fix field called in processing of this SELECT */
bool having_fix_field;
+ /*
+ TRUE when fix field is called for a new condition pushed into the
+ HAVING clause of this SELECT
+ */
+ bool having_fix_field_for_pushed_cond;
/* List of references to fields referenced from inner selects */
List<Item_outer_ref> inner_refs_list;
/* Number of Item_sum-derived objects in this SELECT */
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index ee5ba4ade54..4ebd5ef4954 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1350,9 +1350,11 @@ JOIN::optimize_inner()
if (having)
{
select_lex->having_fix_field= 1;
+ select_lex->having_fix_field_for_pushed_cond= 1;
if (having->fix_fields(thd, &having))
DBUG_RETURN(1);
select_lex->having_fix_field= 0;
+ select_lex->having_fix_field_for_pushed_cond= 0;
}
}