[Commits] 4fb20f1: Fixed the bug mdev-12845.

IgorBabaev igor at mariadb.com
Thu Jun 22 10:41:44 EEST 2017


revision-id: 4fb20f1961dca7310dbf91f2155246ff74a73eb2 (mariadb-10.2.6-33-g4fb20f1)
parent(s): bb1f41423a0c26313a7bd4b7704ccc4ad66e348a
author: Igor Babaev
committer: Igor Babaev
timestamp: 2017-06-22 00:41:44 -0700
message:

Fixed the bug mdev-12845.

This patch fills in a serious flaw in the
code that supports condition pushdown into
materialized views / derived tables.

If a predicate happened to contain a reference
to a mergeable view / derived table and it does
not depended directly on the target materialized
view / derived table then the predicate was not
considered as a subject to pusdown to this view
/ derived table.

---
 mysql-test/r/derived.result               |   2 +-
 mysql-test/r/derived_cond_pushdown.result | 229 ++++++++++++++++++++++-
 mysql-test/r/derived_view.result          |   4 +-
 mysql-test/t/derived_cond_pushdown.test   |  57 ++++++
 sql/item.cc                               | 299 ++++++++++++++++++------------
 sql/item.h                                |  66 ++++++-
 sql/item_cmpfunc.h                        |   8 +
 sql/item_func.h                           |  13 ++
 sql/item_row.h                            |  10 +
 sql/sql_derived.cc                        |   5 +-
 sql/sql_lex.cc                            |  17 +-
 sql/sql_lex.h                             |   2 +-
 sql/table.cc                              |   3 +-
 13 files changed, 568 insertions(+), 147 deletions(-)

diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result
index 8a7422b..722ff76 100644
--- a/mysql-test/r/derived.result
+++ b/mysql-test/r/derived.result
@@ -554,7 +554,7 @@ EXPLAIN SELECT * FROM (SELECT * FROM t1) AS table1,
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	PRIMARY	t1	system	NULL	NULL	NULL	NULL	1	
 1	PRIMARY	<derived3>	ref	key0	key0	5	const	0	
-3	DERIVED	t2	ALL	NULL	NULL	NULL	NULL	2	Using temporary
+3	DERIVED	t2	ALL	NULL	NULL	NULL	NULL	2	Using where; Using temporary
 Warnings:
 Note	1249	Select 4 was reduced during optimization
 DROP TABLE t1, t2;
diff --git a/mysql-test/r/derived_cond_pushdown.result b/mysql-test/r/derived_cond_pushdown.result
index dbc25fb..db65d9c 100644
--- a/mysql-test/r/derived_cond_pushdown.result
+++ b/mysql-test/r/derived_cond_pushdown.result
@@ -7234,6 +7234,7 @@ EXPLAIN
             "materialized": {
               "query_block": {
                 "select_id": 5,
+                "having_condition": "s > 2",
                 "filesort": {
                   "sort_key": "t4.d",
                   "temporary_table": {
@@ -7605,6 +7606,7 @@ EXPLAIN
             "materialized": {
               "query_block": {
                 "select_id": 3,
+                "having_condition": "s < 50",
                 "filesort": {
                   "sort_key": "t3.a",
                   "temporary_table": {
@@ -7755,9 +7757,14 @@ EXPLAIN
           "select_id": 4,
           "table": {
             "table_name": "t",
-            "access_type": "ALL",
+            "access_type": "range",
+            "possible_keys": ["PRIMARY"],
+            "key": "PRIMARY",
+            "key_length": "4",
+            "used_key_parts": ["pk"],
             "rows": 2,
-            "filtered": 100
+            "filtered": 100,
+            "index_condition": "t.pk > 2"
           }
         }
       }
@@ -8447,3 +8454,221 @@ WHERE row <> order_number;
 row	order_number
 14	51
 DROP TABLE sales_documents;
+#
+# MDEV-12845: pushdown from merged derived using equalities  
+#
+create table t1 (a int);
+insert into t1 values
+(4), (8), (5), (3), (10), (2), (7);
+create table t2 (b int, c int);
+insert into t2 values
+(2,1), (5,2), (2,2), (4,1), (4,3),
+(5,3), (2,4), (4,6), (2,1);
+create view v1 as
+select b, sum(c) as s from t2 group by b;
+create view v2 as
+select distinct b, c from t2;
+create view v3 as
+select b, max(c) as m from t2 group by b;
+select b
+from ( select t1.a, v1.b, v1.s from t1, v1 where t1.a = v1.b ) as t
+where b > 2;
+b
+4
+5
+explain format=json select b
+from ( select t1.a, v1.b, v1.s from t1, v1 where t1.a = v1.b ) as t
+where b > 2;
+EXPLAIN
+{
+  "query_block": {
+    "select_id": 1,
+    "table": {
+      "table_name": "t1",
+      "access_type": "ALL",
+      "rows": 7,
+      "filtered": 100,
+      "attached_condition": "t1.a > 2 and t1.a is not null"
+    },
+    "table": {
+      "table_name": "<derived3>",
+      "access_type": "ref",
+      "possible_keys": ["key0"],
+      "key": "key0",
+      "key_length": "5",
+      "used_key_parts": ["b"],
+      "ref": ["test.t1.a"],
+      "rows": 2,
+      "filtered": 100,
+      "materialized": {
+        "query_block": {
+          "select_id": 3,
+          "filesort": {
+            "sort_key": "t2.b",
+            "temporary_table": {
+              "table": {
+                "table_name": "t2",
+                "access_type": "ALL",
+                "rows": 9,
+                "filtered": 100,
+                "attached_condition": "t2.b > 2"
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+select a
+from ( select t1.a, v1.b, v1.s from t1, v1 where t1.a = v1.b ) as t
+where a > 2;
+a
+4
+5
+explain format=json select a
+from ( select t1.a, v1.b, v1.s from t1, v1 where t1.a = v1.b ) as t
+where a > 2;
+EXPLAIN
+{
+  "query_block": {
+    "select_id": 1,
+    "table": {
+      "table_name": "t1",
+      "access_type": "ALL",
+      "rows": 7,
+      "filtered": 100,
+      "attached_condition": "t1.a > 2 and t1.a is not null"
+    },
+    "table": {
+      "table_name": "<derived3>",
+      "access_type": "ref",
+      "possible_keys": ["key0"],
+      "key": "key0",
+      "key_length": "5",
+      "used_key_parts": ["b"],
+      "ref": ["test.t1.a"],
+      "rows": 2,
+      "filtered": 100,
+      "materialized": {
+        "query_block": {
+          "select_id": 3,
+          "filesort": {
+            "sort_key": "t2.b",
+            "temporary_table": {
+              "table": {
+                "table_name": "t2",
+                "access_type": "ALL",
+                "rows": 9,
+                "filtered": 100,
+                "attached_condition": "t2.b > 2"
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+select a
+from  ( select t1.a, v2.b, v2.c from t1, v2 where t1.a = v2.b ) as t
+where a > 2;
+a
+4
+4
+4
+5
+5
+explain format=json select a
+from  ( select t1.a, v2.b, v2.c from t1, v2 where t1.a = v2.b ) as t
+where a > 2;
+EXPLAIN
+{
+  "query_block": {
+    "select_id": 1,
+    "table": {
+      "table_name": "t1",
+      "access_type": "ALL",
+      "rows": 7,
+      "filtered": 100,
+      "attached_condition": "t1.a > 2 and t1.a is not null"
+    },
+    "table": {
+      "table_name": "<derived3>",
+      "access_type": "ref",
+      "possible_keys": ["key0"],
+      "key": "key0",
+      "key_length": "5",
+      "used_key_parts": ["b"],
+      "ref": ["test.t1.a"],
+      "rows": 2,
+      "filtered": 100,
+      "materialized": {
+        "query_block": {
+          "select_id": 3,
+          "temporary_table": {
+            "table": {
+              "table_name": "t2",
+              "access_type": "ALL",
+              "rows": 9,
+              "filtered": 100,
+              "attached_condition": "t2.b > 2"
+            }
+          }
+        }
+      }
+    }
+  }
+}
+select a
+from  ( select t1.a, v3.b, v3.m from t1, v3 where t1.a = v3.m ) as t
+where a > 2;
+a
+4
+3
+explain format=json select a
+from  ( select t1.a, v3.b, v3.m from t1, v3 where t1.a = v3.m ) as t
+where a > 2;
+EXPLAIN
+{
+  "query_block": {
+    "select_id": 1,
+    "table": {
+      "table_name": "t1",
+      "access_type": "ALL",
+      "rows": 7,
+      "filtered": 100,
+      "attached_condition": "t1.a > 2 and t1.a is not null"
+    },
+    "table": {
+      "table_name": "<derived3>",
+      "access_type": "ref",
+      "possible_keys": ["key0"],
+      "key": "key0",
+      "key_length": "5",
+      "used_key_parts": ["m"],
+      "ref": ["test.t1.a"],
+      "rows": 2,
+      "filtered": 100,
+      "materialized": {
+        "query_block": {
+          "select_id": 3,
+          "having_condition": "m > 2",
+          "filesort": {
+            "sort_key": "t2.b",
+            "temporary_table": {
+              "table": {
+                "table_name": "t2",
+                "access_type": "ALL",
+                "rows": 9,
+                "filtered": 100
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+drop view v1,v2,v3;
+drop table t1,t2;
diff --git a/mysql-test/r/derived_view.result b/mysql-test/r/derived_view.result
index 5e6bcd0..f396460 100644
--- a/mysql-test/r/derived_view.result
+++ b/mysql-test/r/derived_view.result
@@ -900,7 +900,7 @@ EXPLAIN
                 "access_type": "ALL",
                 "rows": 11,
                 "filtered": 100,
-                "attached_condition": "t1.f1 in (2,3)"
+                "attached_condition": "t1.f1 < 7 and t1.f1 in (2,3)"
               }
             }
           }
@@ -1107,7 +1107,7 @@ id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	PRIMARY	t1	system	NULL	NULL	NULL	NULL	1	
 1	PRIMARY	t2	ref	a	a	4	const	1	Using index
 1	PRIMARY	<derived2>	ref	key0	key0	8	const,const	1	
-2	DERIVED	t3	ALL	NULL	NULL	NULL	NULL	12	Using temporary; Using filesort
+2	DERIVED	t3	ALL	NULL	NULL	NULL	NULL	12	Using where; Using temporary; Using filesort
 SELECT * FROM t1, t2, v1 WHERE t2.a=t1.a AND t2.a=v1.a AND t2.a=v1.b;
 a	a	a	b
 c	c	c	c
diff --git a/mysql-test/t/derived_cond_pushdown.test b/mysql-test/t/derived_cond_pushdown.test
index bc44809..6b5da54 100644
--- a/mysql-test/t/derived_cond_pushdown.test
+++ b/mysql-test/t/derived_cond_pushdown.test
@@ -1452,3 +1452,60 @@ SELECT * FROM
 WHERE row <> order_number;
  
 DROP TABLE sales_documents;
+
+--echo #
+--echo # MDEV-12845: pushdown from merged derived using equalities  
+--echo #
+
+create table t1 (a int);
+insert into t1 values
+  (4), (8), (5), (3), (10), (2), (7);
+
+create table t2 (b int, c int);
+insert into t2 values
+  (2,1), (5,2), (2,2), (4,1), (4,3),
+  (5,3), (2,4), (4,6), (2,1);
+
+create view v1 as
+select b, sum(c) as s from t2 group by b;
+
+create view v2 as
+select distinct b, c from t2;
+
+create view v3 as
+select b, max(c) as m from t2 group by b;
+
+let $q1=
+select b
+from ( select t1.a, v1.b, v1.s from t1, v1 where t1.a = v1.b ) as t
+where b > 2;
+
+eval $q1;
+eval explain format=json $q1;
+
+let $q2=
+select a
+from ( select t1.a, v1.b, v1.s from t1, v1 where t1.a = v1.b ) as t
+where a > 2;
+
+eval $q2;
+eval explain format=json $q2;
+
+let $q3=
+select a
+from  ( select t1.a, v2.b, v2.c from t1, v2 where t1.a = v2.b ) as t
+where a > 2;
+
+eval $q3;
+eval explain format=json $q3;
+
+let $q4=
+select a
+from  ( select t1.a, v3.b, v3.m from t1, v3 where t1.a = v3.m ) as t
+where a > 2;
+
+eval $q4;
+eval explain format=json $q4;
+
+drop view v1,v2,v3;
+drop table t1,t2;
diff --git a/sql/item.cc b/sql/item.cc
index a130cfd..cd7e49d 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -7120,121 +7120,182 @@ Item *Item_field::update_value_transformer(THD *thd, uchar *select_arg)
 }
 
 
-Item *Item_field::derived_field_transformer_for_having(THD *thd, uchar *arg)
-{
-  st_select_lex *sl= (st_select_lex *)arg;
-  table_map map= sl->master_unit()->derived->table->map;
-  if (!((Item_field*)this)->item_equal)
-  {
-    if (used_tables() == map)
-    {
-      Item_ref *rf= 
-	new (thd->mem_root) Item_ref(thd, &sl->context, 
-	  	   	             NullS, NullS,
-				   ((Item_field*) this)->field_name);
-      if (!rf)
-	return 0;
-      return rf;
-    }
-  }
+static
+Item *get_field_item_for_having(THD *thd, Item *item, st_select_lex *sel)
+{
+  DBUG_ASSERT(item->type() == Item::FIELD_ITEM ||
+              (item->type() == Item::REF_ITEM &&
+               ((Item_ref *) item)->ref_type() == Item_ref::VIEW_REF)); 
+  Item_field *field_item= NULL;
+  table_map map= sel->master_unit()->derived->table->map;
+  Item_equal *item_equal= item->get_item_equal();
+  if (!item_equal)
+    field_item= (Item_field *)(item->real_item());
   else
   {
-    Item_equal *cond= (Item_equal *) ((Item_field*)this)->item_equal;
-    Item_equal_fields_iterator li(*cond);
-    Item *item;
-    while ((item=li++))
+    Item_equal_fields_iterator li(*item_equal);
+    Item *equal_item;
+    while ((equal_item= li++))
     {
-      if (item->used_tables() == map && item->real_item()->type() == FIELD_ITEM)
+      if (equal_item->used_tables() == map)
       {
-	Item_ref *rf= 
-	  new (thd->mem_root) Item_ref(thd, &sl->context, 
-				       NullS, NullS,
-			      ((Item_field*) (item->real_item()))->field_name);
-	if (!rf)
-	  return 0;
-	return rf;
+        field_item= (Item_field *)(equal_item->real_item());
+	break;
       }
     }
   }
-  return this;
+  if (field_item)
+  {
+    Item_ref *ref= new (thd->mem_root) Item_ref(thd, &sel->context,
+                                                NullS, NullS,
+                                                field_item->field_name);
+    return ref;
+  }
+  DBUG_ASSERT(0);
+  return NULL; 
 }
 
 
-Item *Item_field::derived_field_transformer_for_where(THD *thd, uchar *arg)
+Item *Item_field::derived_field_transformer_for_having(THD *thd, uchar *arg)
+{
+  st_select_lex *sel= (st_select_lex *)arg;
+  table_map tab_map= sel->master_unit()->derived->table->map;
+  if (item_equal && !(item_equal->used_tables() & tab_map))
+    return this;
+  if (!item_equal && used_tables() != tab_map)
+    return this;
+  return get_field_item_for_having(thd, this, sel);
+}
+
+
+Item *Item_direct_view_ref::derived_field_transformer_for_having(THD *thd,
+                                                                 uchar *arg)
 {
+  st_select_lex *sel= (st_select_lex *)arg;
+  table_map tab_map= sel->master_unit()->derived->table->map;
+  if (item_equal && !(item_equal->used_tables() & tab_map))
+    return this;
+  if (!item_equal && used_tables() != tab_map)
+    return this;
+  return get_field_item_for_having(thd, this, sel);
+}
+
+
+static 
+Item *find_producing_item(Item *item, st_select_lex *sel)
+{
+  DBUG_ASSERT(item->type() == Item::FIELD_ITEM ||
+              (item->type() == Item::REF_ITEM &&
+               ((Item_ref *) item)->ref_type() == Item_ref::VIEW_REF)); 
   Item *producing_item;
-  st_select_lex *sl= (st_select_lex *)arg;
-  List_iterator_fast<Item> li(sl->item_list);
-  table_map map= sl->master_unit()->derived->table->map;
-  if (used_tables() == map)
-  {
-    uint field_no= ((Item_field*) this)->field->field_index;
-    for (uint i= 0; i <= field_no; i++)
-      producing_item= li++;
-    return producing_item->build_clone(thd, thd->mem_root);
-  }
-  else if (((Item_field*)this)->item_equal)
-  {
-    Item_equal *cond= (Item_equal *) ((Item_field*)this)->item_equal;
-    Item_equal_fields_iterator it(*cond);
-    Item *item;
-    while ((item=it++))
+  Item_field *field_item= NULL;
+  Item_equal *item_equal= item->get_item_equal();
+  table_map tab_map= sel->master_unit()->derived->table->map;
+  if (item->used_tables() == tab_map)
+    field_item= (Item_field *) (item->real_item());
+  if (!field_item && item_equal)
+  {
+    Item_equal_fields_iterator it(*item_equal);
+    Item *equal_item;
+    while ((equal_item= it++))
     {
-      if (item->used_tables() == map && item->real_item()->type() == FIELD_ITEM)
-      {   
-	Item_field *field_item= (Item_field *) (item->real_item());
-	li.rewind();
-        uint field_no= field_item->field->field_index;
-        for (uint i= 0; i <= field_no; i++)
-          producing_item= li++;
-        return producing_item->build_clone(thd, thd->mem_root);
+      if (equal_item->used_tables() == tab_map)
+      {
+        field_item= (Item_field *) (equal_item->real_item());
+        break;
       }
     }
   }
-  return this;
+  List_iterator_fast<Item> li(sel->item_list);
+  if (field_item)
+  {
+    uint field_no= field_item->field->field_index;
+    for (uint i= 0; i <= field_no; i++)
+      producing_item= li++;
+    return producing_item;
+  }
+  return NULL;
 }
 
+Item *Item_field::derived_field_transformer_for_where(THD *thd, uchar *arg)
+{
+  st_select_lex *sel= (st_select_lex *)arg;
+  Item *producing_item= find_producing_item(this, sel);
+  if (producing_item)
+    return producing_item->build_clone(thd, thd->mem_root);
+  return this;
+}
 
-Item *Item_field::derived_grouping_field_transformer_for_where(THD *thd,
-                                                               uchar *arg)
+Item *Item_direct_view_ref::derived_field_transformer_for_where(THD *thd,
+                                                                uchar *arg)
 {
-  st_select_lex *sl= (st_select_lex *)arg;
-  List_iterator<Grouping_tmp_field> li(sl->grouping_tmp_fields);
-  Grouping_tmp_field *field;
-  table_map map= sl->master_unit()->derived->table->map;
-  if (used_tables() == map)
+  if (item_equal)
   {
-    while ((field=li++))
-    {
-      if (((Item_field*) this)->field == field->tmp_field)
-	return field->producing_item->build_clone(thd, thd->mem_root);
-    }
+    st_select_lex *sel= (st_select_lex *)arg;
+    Item *producing_item= find_producing_item(this, sel);
+    DBUG_ASSERT (producing_item != NULL);
+    return producing_item->build_clone(thd, thd->mem_root);
   }
-  else if (((Item_field*)this)->item_equal)
-  {
-    Item_equal *cond= (Item_equal *) ((Item_field*)this)->item_equal;
-    Item_equal_fields_iterator it(*cond);
-    Item *item;
-    while ((item=it++))
+  return this;
+}
+
+static
+Grouping_tmp_field *find_matching_grouping_field(Item *item,
+                                                 st_select_lex *sel)
+{
+  DBUG_ASSERT(item->type() == Item::FIELD_ITEM ||
+              (item->type() == Item::REF_ITEM &&
+               ((Item_ref *) item)->ref_type() == Item_ref::VIEW_REF)); 
+  List_iterator<Grouping_tmp_field> li(sel->grouping_tmp_fields);
+  Grouping_tmp_field *gr_field;
+  Item_field *field_item= (Item_field *) (item->real_item());
+  while ((gr_field= li++))
+  {
+    if (field_item->field == gr_field->tmp_field)
+      return gr_field;
+  }
+  Item_equal *item_equal= item->get_item_equal();
+  if (item_equal)
+  {
+    Item_equal_fields_iterator it(*item_equal);
+    Item *equal_item;
+    while ((equal_item= it++))
     {
-      if (item->used_tables() == map && item->real_item()->type() == FIELD_ITEM)
-      {   
-	Item_field *field_item= (Item_field *) (item->real_item());
-	li.rewind();
-        while ((field=li++))
-        {
-	  if (field_item->field == field->tmp_field)
-	  {
-	    return field->producing_item->build_clone(thd, thd->mem_root);
-	  }
-        }  
+      field_item= (Item_field *) (equal_item->real_item());
+      li.rewind();
+      while ((gr_field= li++))
+      {
+        if (field_item->field == gr_field->tmp_field)
+	  return gr_field;
       }
     }
   }
+  return NULL;
+}
+    
+
+Item *Item_field::derived_grouping_field_transformer_for_where(THD *thd,
+                                                               uchar *arg)
+{
+  st_select_lex *sel= (st_select_lex *)arg;
+  Grouping_tmp_field *gr_field= find_matching_grouping_field(this, sel);
+  if (gr_field)
+    return gr_field->producing_item->build_clone(thd, thd->mem_root);
   return this;
 }
 
 
+Item *
+Item_direct_view_ref::derived_grouping_field_transformer_for_where(THD *thd,
+                                                                   uchar *arg)
+{
+  if (!item_equal)
+    return this;
+  st_select_lex *sel= (st_select_lex *)arg;
+  Grouping_tmp_field *gr_field= find_matching_grouping_field(this, sel);
+  return gr_field->producing_item->build_clone(thd, thd->mem_root);
+}
+
 void Item_field::print(String *str, enum_query_type query_type)
 {
   if (field && field->table->const_table &&
@@ -8702,6 +8763,32 @@ Item *Item_direct_view_ref::replace_equal_field(THD *thd, uchar *arg)
 }
 
 
+bool Item_direct_view_ref::excl_dep_on_table(table_map tab_map)
+{
+  table_map used= used_tables();
+  if (used & OUTER_REF_TABLE_BIT)
+    return false;
+  if (!(used & ~tab_map))
+    return true; 
+  if (item_equal)
+  {
+    DBUG_ASSERT(real_item()->type() == Item::FIELD_ITEM);
+    return item_equal->used_tables() & tab_map;
+  }
+  return (*ref)->excl_dep_on_table(tab_map);
+}
+
+bool Item_direct_view_ref::excl_dep_on_grouping_fields(st_select_lex *sel)
+{
+  if (item_equal)
+  {
+    DBUG_ASSERT(real_item()->type() == Item::FIELD_ITEM);
+    return find_matching_grouping_field(this, sel) != NULL;
+  }    
+  return (*ref)->excl_dep_on_grouping_fields(sel);
+}
+
+
 bool Item_default_value::eq(const Item *item, bool binary_cmp) const
 {
   return item->type() == DEFAULT_VALUE_ITEM && 
@@ -10613,46 +10700,16 @@ const char *dbug_print_unit(SELECT_LEX_UNIT *un)
 
 #endif /*DBUG_OFF*/
 
-bool Item_field::exclusive_dependence_on_table_processor(void *map)
+bool Item_field::excl_dep_on_table(table_map tab_map)
 {
-  table_map tab_map= *((table_map *) map);
-  return !((used_tables() == tab_map || 
-         (item_equal && item_equal->used_tables() & tab_map))); 
+  return used_tables() == tab_map || 
+         (item_equal && (item_equal->used_tables() & tab_map)); 
 }
 
-bool Item_field::exclusive_dependence_on_grouping_fields_processor(void *arg)
+bool
+Item_field::excl_dep_on_grouping_fields(st_select_lex *sel)
 {
-  st_select_lex *sl= (st_select_lex *)arg;
-  List_iterator<Grouping_tmp_field> li(sl->grouping_tmp_fields);
-  Grouping_tmp_field *field;
-  table_map map= sl->master_unit()->derived->table->map;
-  if (used_tables() == map)
-  {
-    while ((field=li++))
-    {
-      if (((Item_field*) this)->field == field->tmp_field)
-        return false;
-    }
-  }
-  else if (((Item_field*)this)->item_equal)
-  {
-    Item_equal *cond= (Item_equal *) ((Item_field*)this)->item_equal;
-    Item_equal_fields_iterator it(*cond);
-    Item *item;
-    while ((item=it++))
-    {
-      if (item->used_tables() == map && item->real_item()->type() == FIELD_ITEM)
-      {
-	li.rewind();
-        while ((field=li++))
-        {
-	  if (((Item_field *)(item->real_item()))->field == field->tmp_field)
-	    return false;
-	}
-      }
-    }
-  }
-  return true;
+  return find_matching_grouping_field(this, sel) != NULL;
 }
 
 void Item::register_in(THD *thd)
diff --git a/sql/item.h b/sql/item.h
index 42e9fd9..828223a 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1580,8 +1580,20 @@ class Item: public Value_source,
   virtual bool limit_index_condition_pushdown_processor(void *arg) { return 0; }
   virtual bool exists2in_processor(void *arg) { return 0; }
   virtual bool find_selective_predicates_list_processor(void *arg) { return 0; }
-  virtual bool exclusive_dependence_on_table_processor(void *arg) { return 0; }
-  virtual bool exclusive_dependence_on_grouping_fields_processor(void *arg) { return 0; }
+
+  /* 
+    TRUE if the expression depends only on the table indicated by tab_map
+    or can be converted to such an exression using equalities.
+    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.
+    Not to be used for AND/OR formulas.
+  */
+  virtual bool excl_dep_on_grouping_fields(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; }
   /*
@@ -2633,8 +2645,8 @@ class Item_field :public Item_ident
   Item *derived_field_transformer_for_where(THD *thd, uchar *arg);
   Item *derived_grouping_field_transformer_for_where(THD *thd, uchar *arg);
   virtual void print(String *str, enum_query_type query_type);
-  bool exclusive_dependence_on_table_processor(void *map);
-  bool exclusive_dependence_on_grouping_fields_processor(void *arg);
+  bool excl_dep_on_table(table_map tab_map);
+  bool excl_dep_on_grouping_fields(st_select_lex *sel);
   bool cleanup_excluding_fields_processor(void *arg)
   { return field ? 0 : cleanup_processor(arg); }
   bool cleanup_excluding_const_fields_processor(void *arg)
@@ -3855,6 +3867,28 @@ class Item_args
   }
   bool transform_args(THD *thd, Item_transformer transformer, uchar *arg);
   void propagate_equal_fields(THD *, const Item::Context &, COND_EQUAL *);
+  bool excl_dep_on_table(table_map tab_map)
+  {
+    for (uint i= 0; i < arg_count; i++)
+    {
+      if (args[i]->const_item())
+        continue;
+      if (!args[i]->excl_dep_on_table(tab_map))
+        return false;
+    }
+    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;
+  }
 public:
   Item_args(void)
     :args(NULL), arg_count(0)
@@ -4323,10 +4357,15 @@ class Item_ref :public Item_ident
   }
   Item *get_copy(THD *thd, MEM_ROOT *mem_root)
   { return get_item_copy<Item_ref>(thd, mem_root, this); }
-  bool exclusive_dependence_on_table_processor(void *map)
-  { return depended_from != NULL; }
-  bool exclusive_dependence_on_grouping_fields_processor(void *arg)
-  { return depended_from != NULL; }
+  bool excl_dep_on_table(table_map tab_map)
+  { 
+    table_map used= used_tables();
+    if (used & OUTER_REF_TABLE_BIT)
+      return false;
+    return (used == tab_map) || (*ref)->excl_dep_on_table(tab_map);
+  }
+  bool excl_dep_on_grouping_fields(st_select_lex *sel)
+  { return (*ref)->excl_dep_on_grouping_fields(sel); }
   bool cleanup_excluding_fields_processor(void *arg)
   {
     Item *item= real_item();
@@ -4623,13 +4662,20 @@ class Item_direct_view_ref :public Item_direct_ref
     return (*ref)->walk(processor, walk_subquery, arg) ||
            (this->*processor)(arg);
   }
-   bool view_used_tables_processor(void *arg) 
+  bool view_used_tables_processor(void *arg) 
   {
     TABLE_LIST *view_arg= (TABLE_LIST *) arg;
     if (view_arg == view)
       view_arg->view_used_tables|= (*ref)->used_tables();
     return 0;
   }
+  bool excl_dep_on_table(table_map tab_map);
+  bool excl_dep_on_grouping_fields(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 *derived_grouping_field_transformer_for_where(THD *thd,
+                                                     uchar *arg);
+
   void save_val(Field *to)
   {
     if (check_null_ref())
@@ -4711,6 +4757,8 @@ class Item_direct_view_ref :public Item_direct_ref
     item_equal= NULL;
     Item_direct_ref::cleanup();
   }
+  Item *get_copy(THD *thd, MEM_ROOT *mem_root)
+  { return get_item_copy<Item_direct_view_ref>(thd, mem_root, this); }
 };
 
 
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 12eb5cb..56c27f9 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -2398,6 +2398,14 @@ class Item_equal: public Item_bool_func
   void set_context_field(Item_field *ctx_field) { context_field= ctx_field; }
   void set_link_equal_fields(bool flag) { link_equal_fields= flag; }
   Item* get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; }
+  /*
+    This does not comply with the specification of the virtual method,
+    but Item_equal items are processed distinguishly anyway
+  */
+  bool excl_dep_on_table(table_map tab_map)
+  {
+    return used_tables() & tab_map;
+  }
   friend class Item_equal_fields_iterator;
   bool count_sargable_conds(void *arg);
   friend class Item_equal_iterator<List_iterator_fast,Item>;
diff --git a/sql/item_func.h b/sql/item_func.h
index 7ee4b67..5034cd6 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -316,6 +316,19 @@ class Item_func :public Item_func_or_sum
     return this;
   }
 
+  bool excl_dep_on_table(table_map tab_map)
+  {
+    if (used_tables() & OUTER_REF_TABLE_BIT)
+      return false; 
+    return !(used_tables() & ~tab_map) || 
+           Item_args::excl_dep_on_table(tab_map);
+  }
+
+  bool excl_dep_on_grouping_fields(st_select_lex *sel)
+  {
+    return Item_args::excl_dep_on_grouping_fields(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
diff --git a/sql/item_row.h b/sql/item_row.h
index 2646833..cd58e15f 100644
--- a/sql/item_row.h
+++ b/sql/item_row.h
@@ -126,6 +126,16 @@ class Item_row: public Item,
     return this;
   }
 
+  bool excl_dep_on_table(table_map tab_map)
+  {
+    return Item_args::excl_dep_on_table(tab_map);
+  }
+
+  bool excl_dep_on_grouping_fields(st_select_lex *sel)
+  {
+    return Item_args::excl_dep_on_grouping_fields(sel);
+  }
+
   bool check_vcol_func_processor(void *arg) {return FALSE; }
   Item *get_copy(THD *thd, MEM_ROOT *mem_root)
   { return get_item_copy<Item_row>(thd, mem_root, this); }
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 8f0410b..649f745 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -1246,7 +1246,7 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
     Item *cond_over_grouping_fields;
     sl->collect_grouping_fields(thd);
     sl->check_cond_extraction_for_grouping_fields(extracted_cond_copy,
-              &Item::exclusive_dependence_on_grouping_fields_processor);
+                                                  derived);
     cond_over_grouping_fields=
       sl->build_cond_for_grouping_fields(thd, extracted_cond_copy, true);
   
@@ -1285,7 +1285,8 @@ bool pushdown_cond_for_derived(THD *thd, Item *cond, TABLE_LIST *derived)
     if (!extracted_cond_copy)
       continue;
 
-    extracted_cond_copy->walk(&Item::cleanup_processor, 0, 0);
+    extracted_cond_copy->walk(&Item::cleanup_excluding_const_fields_processor,
+                              0, 0);
     sl->cond_pushed_into_having= extracted_cond_copy;
   }
   thd->lex->current_select= save_curr_select;
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index e3ead45..9584f2a 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -5006,8 +5006,9 @@ void st_select_lex::collect_grouping_fields(THD *thd)
     from cond.
 */ 
 
-void st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond,
-                                              Item_processor check_processor)
+void 
+st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond,
+                                                         TABLE_LIST *derived)
 {
   cond->clear_extraction_flag();
   if (cond->type() == Item::COND_ITEM)
@@ -5020,7 +5021,7 @@ void st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond,
     Item *item;
     while ((item=li++))
     {
-      check_cond_extraction_for_grouping_fields(item, check_processor);
+      check_cond_extraction_for_grouping_fields(item, derived);
       if (item->get_extraction_flag() !=  NO_EXTRACTION_FL)
       {
         count++;
@@ -5041,10 +5042,12 @@ void st_select_lex::check_cond_extraction_for_grouping_fields(Item *cond,
         item->clear_extraction_flag();
     }
   }
-  else 
-    cond->set_extraction_flag(cond->walk(check_processor, 
-				   0, (uchar *) this) ?
-     NO_EXTRACTION_FL : FULL_EXTRACTION_FL);
+  else
+  {
+    int fl= cond->excl_dep_on_grouping_fields(this) ?
+      FULL_EXTRACTION_FL : NO_EXTRACTION_FL;
+    cond->set_extraction_flag(fl);
+  }
 }
 
 
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index face3bc..1b7bfe2 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -1138,7 +1138,7 @@ class st_select_lex: public st_select_lex_node
   bool check_subqueries_with_recursive_references();
   void collect_grouping_fields(THD *thd); 
   void check_cond_extraction_for_grouping_fields(Item *cond,
-                                                 Item_processor processor);
+                                                 TABLE_LIST *derived);
   Item *build_cond_for_grouping_fields(THD *thd, Item *cond,
 				       bool no_to_clones);
   
diff --git a/sql/table.cc b/sql/table.cc
index 398383e..66bce76 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -8091,8 +8091,7 @@ void TABLE_LIST::check_pushable_cond_for_table(Item *cond)
         item->clear_extraction_flag();
     }
   }
-  else if (cond->walk(&Item::exclusive_dependence_on_table_processor,
-                      0, (void *) &tab_map))
+  else if (!cond->excl_dep_on_table(tab_map))
     cond->set_extraction_flag(NO_EXTRACTION_FL);
 }
 


More information about the commits mailing list