diff --git a/sql/item.h b/sql/item.h
index 043605a..a665d23 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1133,6 +1133,13 @@ class Item: public Type_std_attributes
     update_used_tables();
     return this;
   }
+  virtual COND *build_equal_items_and_cond(THD *thd, COND_EQUAL *inherited,
+                                           bool link_item_fields,
+                                           COND_EQUAL **cond_equal_ref)
+  {
+    *cond_equal_ref= NULL;
+    return Item::build_equal_items(thd, inherited, link_item_fields);
+  }
   /*
     Checks whether the item is:
     - a simple equality (field=field_item or field=constant_item), or
@@ -2353,6 +2360,13 @@ class Item_field :public Item_ident
     DBUG_ASSERT(type() != FIELD_ITEM);
     return Item_ident::build_equal_items(thd, inherited, link_item_fields);
   }
+  COND *build_equal_items_and_cond(THD *thd, COND_EQUAL *inherited,
+                                   bool link_item_fields,
+                                   COND_EQUAL **cond_equal_ref)
+  {
+    *cond_equal_ref= NULL;
+    return Item_ident::build_equal_items(thd, inherited, link_item_fields);
+  }
   bool is_result_field() { return false; }
   void set_result_field(Field *field) {}
   void save_in_result_field(bool no_conversions) { }
@@ -3606,6 +3620,13 @@ class Item_ref :public Item_ident
     DBUG_ASSERT(real_type() != FIELD_ITEM);
     return Item_ident::build_equal_items(thd, inherited, link_item_fields);
   }
+  COND *build_equal_items_and_cond(THD *thd, COND_EQUAL *inherited,
+                                   bool link_item_fields,
+                                   COND_EQUAL **cond_equal_ref)
+  {
+    *cond_equal_ref= NULL;
+    return Item_ref::build_equal_items(thd, inherited, link_item_fields);
+  }
   bool const_item() const 
   {
     return (*ref)->const_item();
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 53f249d..0c279ed 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -564,6 +564,9 @@ class Item_func_eq :public Item_bool_rowready_func2
   Item *negated_item();
   COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
                           bool link_item_fields);
+  COND *build_equal_items_and_cond(THD *thd, COND_EQUAL *inherited,
+                                   bool link_item_fields,
+                                   COND_EQUAL **cond_equal_ref);
   bool check_equality(THD *thd, COND_EQUAL *cond, List<Item> *eq_list);
   /* 
     - If this equality is created from the subquery's IN-equality:
@@ -1773,6 +1776,13 @@ class Item_cond :public Item_bool_func
   }
   COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
                           bool link_item_fields);
+  COND *build_equal_items_and_cond(THD *thd, COND_EQUAL *inherited,
+                                           bool link_item_fields,
+                                           COND_EQUAL **cond_equal_ref)
+  {
+    *cond_equal_ref= NULL;
+    return Item_cond::build_equal_items(thd, inherited, link_item_fields);
+  }
   virtual void print(String *str, enum_query_type query_type);
   void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields);
   friend int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
@@ -1960,6 +1970,9 @@ class Item_equal: public Item_bool_func
   void fix_length_and_dec();
   bool fix_fields(THD *thd, Item **ref);
   void update_used_tables();
+  COND *build_equal_items_and_cond(THD *thd, COND_EQUAL *inherited,
+                                   bool link_item_fields,
+                                   COND_EQUAL **cond_equal_ref);
   bool walk(Item_processor processor, bool walk_subquery, uchar *arg);
   Item *transform(Item_transformer transformer, uchar *arg);
   virtual void print(String *str, enum_query_type query_type);
@@ -1989,6 +2002,11 @@ class COND_EQUAL: public Sql_alloc
   { 
     upper_levels= 0;
   }
+  COND_EQUAL(Item_equal *item_equal)
+   :upper_levels(0)
+  {
+    current_level.push_back(item_equal);
+  }
   void copy(COND_EQUAL &cond_equal)
   {
     max_members= cond_equal.max_members;
@@ -1998,6 +2016,8 @@ class COND_EQUAL: public Sql_alloc
     else
       current_level= cond_equal.current_level;
   }
+  Item_equal *build_item_equal_from_current_level(THD *thd,
+                                                  COND_EQUAL *inherited);
 };
 
 
@@ -2106,8 +2126,23 @@ class Item_cond_and :public Item_cond
   void mark_as_condition_AND_part(TABLE_LIST *embedding);
   virtual uint exists2in_reserved_items() { return list.elements; };
   bool walk_top_and(Item_processor processor, uchar *arg);
+  void build_new_level(THD *thd, COND_EQUAL *cond_equal);
   COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
                           bool link_item_fields);
+  COND *build_equal_items_and_cond(THD *thd, COND_EQUAL *inherited,
+                                   bool link_item_fields,
+                                   COND_EQUAL **cond_equal_ref)
+  {
+    COND *cond= Item_cond_and::build_equal_items(thd, inherited,
+                                                 link_item_fields);
+    /*
+      cond is either NULL (on OEM), or this,
+      or a new Item_int if all predicates of the level were eliminated.
+    */
+    DBUG_ASSERT(!cond || cond == this || cond->type() == INT_ITEM);
+    *cond_equal_ref= cond == this ? &m_cond_equal : NULL;
+    return cond;
+  }
 };
 
 inline bool is_cond_and(Item *item)
diff --git a/sql/item_func.h b/sql/item_func.h
index 0d57c2b..01e1527 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -133,6 +133,15 @@ class Item_func :public Item_func_or_sum, public Used_tables_and_const_cache
   }
   COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
                           bool link_item_fields);
+  COND *build_equal_items_and_cond(THD *thd, COND_EQUAL *inherited,
+                                   bool link_item_fields,
+                                   COND_EQUAL **cond_equal_ref)
+  {
+    *cond_equal_ref= NULL;
+    COND *cond= build_equal_items(thd, inherited, link_item_fields);
+    DBUG_ASSERT(cond == this);
+    return cond;
+  }
   bool eq(const Item *item, bool binary_cmp) const;
   virtual optimize_type select_optimize() const { return OPTIMIZE_NONE; }
   virtual bool have_rev_func() const { return 0; }
diff --git a/sql/item_sum.h b/sql/item_sum.h
index b540b44..e1b231a 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -455,6 +455,13 @@ class Item_sum :public Item_func_or_sum
     DBUG_ASSERT(0);
     return Item::build_equal_items(thd, inherited, link_item_fields);
   }
+  COND *build_equal_items_and_cond(THD *thd, COND_EQUAL *inherited,
+                                   bool link_item_fields,
+                                   COND_EQUAL **cond_equal_ref)
+  {
+    *cond_equal_ref= NULL;
+    return Item_sum::build_equal_items(thd, inherited, link_item_fields);
+  }
   bool is_null() { return null_value; }
   void make_const () 
   { 
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 95778f0..7658a24 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -12887,6 +12887,42 @@ COND *Item_cond::build_equal_items(THD *thd,
 }
 
 
+void Item_cond_and::build_new_level(THD *thd, COND_EQUAL *cond_equal)
+{
+  Item_equal *item_equal;
+  quick_fix_field();
+  List_iterator_fast<Item_equal> it(cond_equal->current_level);
+  while ((item_equal= it++))
+  {
+    item_equal->fix_length_and_dec();
+    item_equal->update_used_tables();
+    set_if_bigger(thd->lex->current_select->max_equal_elems,
+                  item_equal->n_field_items());  
+  }
+  m_cond_equal.copy(*cond_equal);
+  cond_equal->current_level= m_cond_equal.current_level;
+  argument_list()->append((List<Item> *) &cond_equal->current_level);
+  update_used_tables();
+}
+
+
+Item_equal *
+COND_EQUAL::build_item_equal_from_current_level(THD *thd,
+                                                COND_EQUAL *inherited)
+{
+  Item_equal *item_equal;
+  if ((item_equal= current_level.pop()))
+  {
+    item_equal->fix_fields(thd, NULL);
+    item_equal->update_used_tables();
+    set_if_bigger(thd->lex->current_select->max_equal_elems,
+                  item_equal->n_field_items());  
+    item_equal->upper_levels= inherited;
+  }
+  return item_equal;
+}
+
+
 COND *Item_func_eq::build_equal_items(THD *thd,
                                       COND_EQUAL *inherited,
                                       bool link_item_fields)
@@ -12906,21 +12942,15 @@ COND *Item_func_eq::build_equal_items(THD *thd,
    */
   if (Item_func_eq::check_equality(thd, &cond_equal, &eq_list))
   {
-    Item_equal *item_equal;
     int n= cond_equal.current_level.elements + eq_list.elements;
     if (n == 0)
       return new Item_int((longlong) 1,1);
     else if (n == 1)
     {
-      if ((item_equal= cond_equal.current_level.pop()))
-      {
-        item_equal->fix_fields(thd, NULL);
-        item_equal->update_used_tables();
-        set_if_bigger(thd->lex->current_select->max_equal_elems,
-                      item_equal->n_field_items());  
-        item_equal->upper_levels= inherited;
+      Item_equal *item_equal;
+      if ((item_equal= cond_equal.build_item_equal_from_current_level(thd,
+                                                                   inherited)))
         return item_equal;
-      }
       Item *res= eq_list.pop();
       res->update_used_tables();
       return res;
@@ -12932,23 +12962,55 @@ COND *Item_func_eq::build_equal_items(THD *thd,
         when a row equality is processed as a standalone predicate.
       */
       Item_cond_and *and_cond= new Item_cond_and(eq_list);
-      and_cond->quick_fix_field();
-      List<Item> *args= and_cond->argument_list();
-      List_iterator_fast<Item_equal> it(cond_equal.current_level);
-      while ((item_equal= it++))
+      and_cond->build_new_level(thd, &cond_equal);
+      return and_cond;
+    }
+  }
+  return Item_func::build_equal_items(thd, inherited, link_item_fields);
+}
+
+
+COND *Item_func_eq::build_equal_items_and_cond(THD *thd,
+                                               COND_EQUAL *inherited,
+                                               bool link_item_fields,
+                                               COND_EQUAL **cond_equal_ref)
+{
+  COND_EQUAL cond_equal;
+  cond_equal.upper_levels= inherited;
+  List<Item> eq_list;
+
+  if (Item_func_eq::check_equality(thd, &cond_equal, &eq_list))
+  {
+    int n= cond_equal.current_level.elements + eq_list.elements;
+    if (n == 0)
+    {
+      *cond_equal_ref= NULL;
+      return new Item_int((longlong) 1,1);
+    }
+    else if (n == 1)
+    {
+      Item_equal *item_equal;
+      if ((item_equal= cond_equal.build_item_equal_from_current_level(thd,
+                                                                   inherited)))
       {
-        item_equal->fix_length_and_dec();
-        item_equal->update_used_tables();
-        set_if_bigger(thd->lex->current_select->max_equal_elems,
-                      item_equal->n_field_items());  
+        *cond_equal_ref= new COND_EQUAL(item_equal);
+        return item_equal;
       }
-      and_cond->m_cond_equal.copy(cond_equal);
-      cond_equal.current_level= and_cond->m_cond_equal.current_level;
-      args->append((List<Item> *)&cond_equal.current_level);
-      and_cond->update_used_tables();
+      Item *res= eq_list.pop();
+      res->update_used_tables();
+      DBUG_ASSERT(res->type() == FUNC_ITEM);
+      *cond_equal_ref= NULL;
+      return res;
+    }
+    else
+    {
+      Item_cond_and *and_cond= new Item_cond_and(eq_list);
+      and_cond->build_new_level(thd, &cond_equal);
+      *cond_equal_ref= &and_cond->m_cond_equal;
       return and_cond;
     }
   }
+  *cond_equal_ref= NULL;
   return Item_func::build_equal_items(thd, inherited, link_item_fields);
 }
 
@@ -12972,6 +13034,18 @@ COND *Item_func::build_equal_items(THD *thd, COND_EQUAL *inherited,
 }
 
 
+COND *Item_equal::build_equal_items_and_cond(THD *thd, COND_EQUAL *inherited,
+                                             bool link_item_fields,
+                                             COND_EQUAL **cond_equal_ref)
+{
+  COND *cond= Item_equal::build_equal_items(thd, inherited, link_item_fields);
+  DBUG_ASSERT(cond == this);
+  if ((*cond_equal_ref= new COND_EQUAL))
+    (*cond_equal_ref)->current_level.push_back(this);
+  return cond;
+}
+
+
 /**
   Build multiple equalities for a condition and all on expressions that
   inherit these multiple equalities.
@@ -13053,23 +13127,14 @@ static COND *build_equal_items(JOIN *join, COND *cond,
 
   if (cond) 
   {
-    cond= cond->build_equal_items(thd, inherited, link_equal_fields);
-    if (cond->type() == Item::COND_ITEM &&
-        ((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
-      cond_equal= &((Item_cond_and*) cond)->m_cond_equal;
-
-    else if (cond->type() == Item::FUNC_ITEM &&
-             ((Item_cond*) cond)->functype() == Item_func::MULT_EQUAL_FUNC)
+    cond= cond->build_equal_items_and_cond(thd, inherited, link_equal_fields,
+                                           &cond_equal);
+    if (cond_equal)
     {
-      cond_equal= new COND_EQUAL;
-      cond_equal->current_level.push_back((Item_equal *) cond);
+      cond_equal->upper_levels= inherited;
+      inherited= cond_equal;
     }
   }
-  if (cond_equal)
-  {
-    cond_equal->upper_levels= inherited;
-    inherited= cond_equal;
-  }
   *cond_equal_ref= cond_equal;
 
   if (join_list && !ignore_on_conds)
