← Back to team overview

maria-developers team mailing list archive

Re: step7 (cleanup) MDEV-7950 Item_func::type() takes 0.26% in OLTP RO

 

Hi Sergey,

On 05/27/2015 11:23 AM, Sergey Vojtovich wrote:
Hi Alexander,

ok to push. I just wish to study this code a bit before we continue.


Thanks!

I'm sending the next step, as agreed on IRC.



Thanks,
Sergey

On Wed, May 27, 2015 at 08:03:57AM +0400, Alexander Barkov wrote:
   Hi Sergey,

please review the next step for MDEV-7950.

It breaks get_mm_parts() into a virtual method in Item, so
- replaces one virtual call item->type() to another virtual call,
   item->get_mm_tree().
- and also removes this virtual call for functype(), which used to
   distinguish between COND_AND_FUNC and COND_OR_FUNC:

- if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)


The next patches will:

1. Split the code in Item::get_mm_tree() responsible for functions into
    methods in Item_func and its descendants:
    Item_func
    Item_func_like, to get rid of the select_optimize() call
    Item_func_between
    Item_func_in
    Item_equal

2. Remove virtual method Item_func::select_optimize(),
    as well as enum Item_func::optimize_type, because they won't be
    needed any more.

Thanks.

diff --git a/sql/item.h b/sql/item.h
index 56b2edc..9cabbb1 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -62,6 +62,8 @@ class user_var_entry;
  class JOIN;
  struct KEY_FIELD;
  struct SARGABLE_PARAM;
+class RANGE_OPT_PARAM;
+class SEL_TREE;


  static inline uint32
@@ -1147,6 +1149,15 @@ class Item: public Type_std_attributes
    {
      return;
    }
+   /*
+     Make a select tree for all keys in a condition or a condition part
+     @param param         Context
+     @param cond_ptr[OUT] Store a replacement item here if the condition
+                          can be simplified, e.g.:
+                            WHERE part1 OR part2 OR part3
+                          with one of the partN evalutating to SEL_TREE::ALWAYS.
+   */
+   virtual SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr);
    /*
      Checks whether the item is:
      - a simple equality (field=field_item or field=constant_item), or
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 204e6ed..f814666 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -1733,6 +1733,7 @@ class Item_cond :public Item_bool_func
    void add_key_fields(JOIN *join, KEY_FIELD **key_fields,
                        uint *and_level, table_map usable_tables,
                        SARGABLE_PARAM **sargables);
+  SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr);
    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,
@@ -2082,6 +2083,7 @@ class Item_cond_and :public Item_cond
                            COND_EQUAL **cond_equal_ref);
    void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
                        table_map usable_tables, SARGABLE_PARAM **sargables);
+  SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr);
  };

  inline bool is_cond_and(Item *item)
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 0f1fa40..d03e399 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -952,7 +952,6 @@ static SEL_TREE * get_mm_parts(RANGE_OPT_PARAM *param,COND *cond_func,Field *fie
  static SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param,COND *cond_func,Field *field,
  			    KEY_PART *key_part,
  			    Item_func::Functype type,Item *value);
-static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond);

  static bool is_key_scan_ror(PARAM *param, uint keynr, uint8 nparts);
  static ha_rows check_quick_select(PARAM *param, uint idx, bool index_only,
@@ -3131,7 +3130,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,

      if (cond)
      {
-      if ((tree= get_mm_tree(&param, &cond)))
+      if ((tree= cond->get_mm_tree(&param, &cond)))
        {
          if (tree->type == SEL_TREE::IMPOSSIBLE)
          {
@@ -3628,7 +3627,7 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond)

      thd->no_errors=1;		

-    tree= get_mm_tree(&param, cond);
+    tree= cond[0]->get_mm_tree(&param, cond);

      if (!tree)
        goto free_alloc;
@@ -4061,7 +4060,7 @@ bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond)
    SEL_TREE *tree;
    int res;

-  tree= get_mm_tree(range_par, &pprune_cond);
+  tree= pprune_cond->get_mm_tree(range_par, &pprune_cond);
    if (!tree)
      goto all_used;

@@ -7967,104 +7966,106 @@ static SEL_TREE *get_full_func_mm_tree(RANGE_OPT_PARAM *param,
      NULL     - Could not infer anything from condition cond.
      SEL_TREE with type=IMPOSSIBLE - condition can never be true.
  */
-
-static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
+SEL_TREE *Item_cond_and::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
  {
-  SEL_TREE *tree=0;
-  SEL_TREE *ftree= 0;
-  Item_field *field_item= 0;
-  bool inv= FALSE;
-  Item *value= 0;
-  Item *cond= *cond_ptr;
-  DBUG_ENTER("get_mm_tree");
-
-  if (cond->type() == Item::COND_ITEM)
+  DBUG_ENTER("Item_cond_and::get_mm_tree");
+  SEL_TREE *tree= NULL;
+  List_iterator<Item> li(*argument_list());
+  Item *item;
+  while ((item= li++))
    {
-    List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
+    SEL_TREE *new_tree= li.ref()[0]->get_mm_tree(param,li.ref());
+    if (param->statement_should_be_aborted())
+      DBUG_RETURN(NULL);
+    tree= tree_and(param, tree, new_tree);
+    if (tree && tree->type == SEL_TREE::IMPOSSIBLE)
+    {
+      /*
+        Do not remove 'item' from 'cond'. We return a SEL_TREE::IMPOSSIBLE
+        and that is sufficient for the caller to see that the whole
+        condition is never true.
+      */
+      break;
+    }
+  }
+  DBUG_RETURN(tree);
+}

-    if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
+
+SEL_TREE *Item_cond::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
+{
+  DBUG_ENTER("Item_cond::get_mm_tree");
+  List_iterator<Item> li(*argument_list());
+  bool replace_cond= false;
+  Item *replacement_item= li++;
+  SEL_TREE *tree= li.ref()[0]->get_mm_tree(param, li.ref());
+  if (param->statement_should_be_aborted())
+    DBUG_RETURN(NULL);
+  if (tree)
+  {
+    if (tree->type == SEL_TREE::IMPOSSIBLE &&
+        param->remove_false_where_parts)
      {
-      tree= NULL;
-      Item *item;
-      while ((item=li++))
-      {
-        SEL_TREE *new_tree= get_mm_tree(param,li.ref());
-        if (param->statement_should_be_aborted())
-          DBUG_RETURN(NULL);
-        tree= tree_and(param,tree,new_tree);
-        if (tree && tree->type == SEL_TREE::IMPOSSIBLE)
-        {
-          /*
-            Do not remove 'item' from 'cond'. We return a SEL_TREE::IMPOSSIBLE
-            and that is sufficient for the caller to see that the whole
-            condition is never true.
-          */
-          break;
-        }
-      }
+      /* See the other li.remove() call below */
+      li.remove();
+      if (argument_list()->elements <= 1)
+        replace_cond= true;
      }
-    else
-    {                                           // COND OR
-      bool replace_cond= false;
-      Item *replacement_item= li++;
-      tree= get_mm_tree(param, li.ref());
-      if (param->statement_should_be_aborted())
+
+    Item *item;
+    while ((item= li++))
+    {
+      SEL_TREE *new_tree= li.ref()[0]->get_mm_tree(param, li.ref());
+      if (new_tree == NULL || param->statement_should_be_aborted())
          DBUG_RETURN(NULL);
-      if (tree)
+      tree= tree_or(param, tree, new_tree);
+      if (tree == NULL || tree->type == SEL_TREE::ALWAYS)
        {
-        if (tree->type == SEL_TREE::IMPOSSIBLE &&
-            param->remove_false_where_parts)
-        {
-          /* See the other li.remove() call below */
-          li.remove();
-          if (((Item_cond*)cond)->argument_list()->elements <= 1)
-            replace_cond= true;
-        }
-
-        Item *item;
-        while ((item=li++))
-        {
-          SEL_TREE *new_tree=get_mm_tree(param,li.ref());
-          if (new_tree == NULL || param->statement_should_be_aborted())
-            DBUG_RETURN(NULL);
-          tree= tree_or(param,tree,new_tree);
-          if (tree == NULL || tree->type == SEL_TREE::ALWAYS)
-          {
-            replacement_item= *li.ref();
-            break;
-          }
+        replacement_item= *li.ref();
+        break;
+      }

-          if (new_tree && new_tree->type == SEL_TREE::IMPOSSIBLE &&
-              param->remove_false_where_parts)
-          {
-            /*
-              This is a condition in form
+      if (new_tree && new_tree->type == SEL_TREE::IMPOSSIBLE &&
+          param->remove_false_where_parts)
+      {
+        /*
+          This is a condition in form

-                cond = item1 OR ... OR item_i OR ... itemN
+            cond = item1 OR ... OR item_i OR ... itemN

-              and item_i produces SEL_TREE(IMPOSSIBLE). We should remove item_i
-              from cond.  This may cause 'cond' to become a degenerate,
-              one-way OR. In that case, we replace 'cond' with the remaining
-              item_i.
-            */
-            li.remove();
-            if (((Item_cond*)cond)->argument_list()->elements <= 1)
-              replace_cond= true;
-          }
-          else
-            replacement_item= *li.ref();
-        }
-
-        if (replace_cond)
-          *cond_ptr= replacement_item;
+          and item_i produces SEL_TREE(IMPOSSIBLE). We should remove item_i
+          from cond.  This may cause 'cond' to become a degenerate,
+          one-way OR. In that case, we replace 'cond' with the remaining
+          item_i.
+        */
+        li.remove();
+        if (argument_list()->elements <= 1)
+          replace_cond= true;
        }
+      else
+        replacement_item= *li.ref();
      }
-    DBUG_RETURN(tree);
+
+    if (replace_cond)
+      *cond_ptr= replacement_item;
    }
+  DBUG_RETURN(tree);
+}
+
+
+SEL_TREE *Item::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
+{
+  SEL_TREE *tree=0;
+  SEL_TREE *ftree= 0;
+  Item_field *field_item= 0;
+  bool inv= FALSE;
+  Item *value= 0;
+  DBUG_ENTER("Item::get_mm_tree");
+
    /* Here when simple cond */
-  if (cond->const_item())
+  if (const_item())
    {
-    if (cond->is_expensive())
+    if (is_expensive())
        DBUG_RETURN(0);
      /*
        During the cond->val_int() evaluation we can come across a subselect
@@ -8074,8 +8075,8 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
      */
      MEM_ROOT *tmp_root= param->mem_root;
      param->thd->mem_root= param->old_root;
-    tree= cond->val_int() ? new(tmp_root) SEL_TREE(SEL_TREE::ALWAYS) :
-                            new(tmp_root) SEL_TREE(SEL_TREE::IMPOSSIBLE);
+    tree= val_int() ? new(tmp_root) SEL_TREE(SEL_TREE::ALWAYS) :
+                      new(tmp_root) SEL_TREE(SEL_TREE::IMPOSSIBLE);
      param->thd->mem_root= tmp_root;
      DBUG_RETURN(tree);
    }
@@ -8083,23 +8084,23 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
    table_map ref_tables= 0;
    table_map param_comp= ~(param->prev_tables | param->read_tables |
  		          param->current_table);
-  if (cond->type() != Item::FUNC_ITEM)
+  if (type() != Item::FUNC_ITEM)
    {						// Should be a field
-    ref_tables= cond->used_tables();
+    ref_tables= used_tables();
      if ((ref_tables & param->current_table) ||
  	(ref_tables & ~(param->prev_tables | param->read_tables)))
        DBUG_RETURN(0);
      DBUG_RETURN(new SEL_TREE(SEL_TREE::MAYBE));
    }

-  Item_func *cond_func= (Item_func*) cond;
+  Item_func *cond_func= (Item_func*) this;
    if (cond_func->functype() == Item_func::BETWEEN ||
        cond_func->functype() == Item_func::IN_FUNC)
      inv= ((Item_func_opt_neg *) cond_func)->negated;
    else if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE)
      DBUG_RETURN(0);			

-  param->cond= cond;
+  param->cond= this;

    switch (cond_func->functype()) {
    case Item_func::BETWEEN:
@@ -8149,7 +8150,7 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
    }
    case Item_func::MULT_EQUAL_FUNC:
    {
-    Item_equal *item_equal= (Item_equal *) cond;
+    Item_equal *item_equal= (Item_equal *) this;
      if (!(value= item_equal->get_const()) || value->is_expensive())
        DBUG_RETURN(0);
      Item_equal_fields_iterator it(*item_equal);
@@ -8160,7 +8161,7 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
        Item_result cmp_type= field->cmp_type();
        if (!((ref_tables | field->table->map) & param_comp))
        {
-        tree= get_mm_parts(param, cond, field, Item_func::EQ_FUNC,
+        tree= get_mm_parts(param, this, field, Item_func::EQ_FUNC,
  		           value,cmp_type);
          ftree= !ftree ? tree : tree_and(param, ftree, tree);
        }

diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index f814666..2f26e48 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -655,6 +655,7 @@ class Item_func_between :public Item_func_opt_neg
   void add_key_fields(JOIN *join, KEY_FIELD **key_fields,
                       uint *and_level, table_map usable_tables,
                       SARGABLE_PARAM **sargables);
+  SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr);
 };
 
 
@@ -1337,6 +1338,7 @@ class Item_func_in :public Item_func_opt_neg
     { return OPTIMIZE_KEY; }
   void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
                       table_map usable_tables, SARGABLE_PARAM **sargables);
+  SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr);
   virtual void print(String *str, enum_query_type query_type);
   enum Functype functype() const { return IN_FUNC; }
   const char *func_name() const { return " IN "; }
@@ -1927,6 +1929,7 @@ class Item_equal: public Item_bool_func
   void add_key_fields(JOIN *join, KEY_FIELD **key_fields,
                       uint *and_level, table_map usable_tables,
                       SARGABLE_PARAM **sargables);
+  SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr);
   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);
diff --git a/sql/item_func.h b/sql/item_func.h
index a5ddb24..cb8975a 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -134,6 +134,7 @@ 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_EQUAL **cond_equal_ref);
+  SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr);
   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/opt_range.cc b/sql/opt_range.cc
index d03e399..fd3b45d 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -8053,160 +8053,199 @@ SEL_TREE *Item_cond::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
 }
 
 
+static SEL_TREE *get_mm_tree_for_const(RANGE_OPT_PARAM *param, Item *cond)
+{
+  DBUG_ENTER("get_mm_tree_for_const");
+  if (cond->is_expensive())
+    DBUG_RETURN(0);
+  /*
+    During the cond->val_int() evaluation we can come across a subselect 
+    item which may allocate memory on the thd->mem_root and assumes 
+    all the memory allocated has the same life span as the subselect 
+    item itself. So we have to restore the thread's mem_root here.
+  */
+  MEM_ROOT *tmp_root= param->mem_root;
+  param->thd->mem_root= param->old_root;
+  SEL_TREE *tree;
+  tree= cond->val_int() ? new(tmp_root) SEL_TREE(SEL_TREE::ALWAYS) :
+                          new(tmp_root) SEL_TREE(SEL_TREE::IMPOSSIBLE);
+  param->thd->mem_root= tmp_root;
+  DBUG_RETURN(tree);
+}
+
+
 SEL_TREE *Item::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
 {
-  SEL_TREE *tree=0;
-  SEL_TREE *ftree= 0;
-  Item_field *field_item= 0;
-  bool inv= FALSE;
-  Item *value= 0;
   DBUG_ENTER("Item::get_mm_tree");
+  if (const_item())
+    DBUG_RETURN(get_mm_tree_for_const(param, this));
+
+  /*
+    Here we have a not-constant non-function Item.
+
+    Item_field should not appear, as normalize_cond() replaces
+    "WHERE field" to "WHERE field<>0".
 
-  /* Here when simple cond */
+    Item_exists_subselect is possible, e.g. in this query:
+    SELECT id, st FROM t1
+    WHERE st IN ('GA','FL') AND EXISTS (SELECT 1 FROM t2 WHERE t2.id=t1.id)
+    GROUP BY id;
+  */
+  table_map ref_tables= used_tables();
+  if ((ref_tables & param->current_table) ||
+      (ref_tables & ~(param->prev_tables | param->read_tables)))
+    DBUG_RETURN(0);
+  DBUG_RETURN(new SEL_TREE(SEL_TREE::MAYBE));
+}
+
+
+SEL_TREE *
+Item_func_between::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
+{
+  DBUG_ENTER("Item::get_mm_tree");
   if (const_item())
+    DBUG_RETURN(get_mm_tree_for_const(param, this));
+
+  param->cond= this;
+
+  SEL_TREE *tree= 0;
+  SEL_TREE *ftree= 0;
+
+  if (arguments()[0]->real_item()->type() == Item::FIELD_ITEM)
   {
-    if (is_expensive())
-      DBUG_RETURN(0);
-    /*
-      During the cond->val_int() evaluation we can come across a subselect 
-      item which may allocate memory on the thd->mem_root and assumes 
-      all the memory allocated has the same life span as the subselect 
-      item itself. So we have to restore the thread's mem_root here.
-    */
-    MEM_ROOT *tmp_root= param->mem_root;
-    param->thd->mem_root= param->old_root;
-    tree= val_int() ? new(tmp_root) SEL_TREE(SEL_TREE::ALWAYS) :
-                      new(tmp_root) SEL_TREE(SEL_TREE::IMPOSSIBLE);
-    param->thd->mem_root= tmp_root;
-    DBUG_RETURN(tree);
+    Item_field *field_item= (Item_field*) (arguments()[0]->real_item());
+    ftree= get_full_func_mm_tree(param, this, field_item, NULL, negated);
   }
 
-  table_map ref_tables= 0;
-  table_map param_comp= ~(param->prev_tables | param->read_tables |
-		          param->current_table);
-  if (type() != Item::FUNC_ITEM)
-  {						// Should be a field
-    ref_tables= used_tables();
-    if ((ref_tables & param->current_table) ||
-	(ref_tables & ~(param->prev_tables | param->read_tables)))
-      DBUG_RETURN(0);
-    DBUG_RETURN(new SEL_TREE(SEL_TREE::MAYBE));
+  /*
+    Concerning the code below see the NOTES section in
+    the comments for the function get_full_func_mm_tree()
+  */
+  for (uint i= 1 ; i < arg_count ; i++)
+  {
+    if (arguments()[i]->real_item()->type() == Item::FIELD_ITEM)
+    {
+      Item_field *field_item= (Item_field*) (arguments()[i]->real_item());
+      SEL_TREE *tmp= get_full_func_mm_tree(param, this, field_item,
+                                           (Item*)(intptr) i, negated);
+      if (negated)
+      {
+        tree= !tree ? tmp : tree_or(param, tree, tmp);
+        if (tree == NULL)
+          break;
+      }
+      else 
+        tree= tree_and(param, tree, tmp);
+    }
+    else if (negated)
+    { 
+      tree= 0;
+      break;
+    }
   }
 
-  Item_func *cond_func= (Item_func*) this;
-  if (cond_func->functype() == Item_func::BETWEEN ||
-      cond_func->functype() == Item_func::IN_FUNC)
-    inv= ((Item_func_opt_neg *) cond_func)->negated;
-  else if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE)
-    DBUG_RETURN(0);			       
+  ftree= tree_and(param, ftree, tree);
+  DBUG_RETURN(ftree);
+}
+
+
+SEL_TREE *Item_func_in::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
+{
+  DBUG_ENTER("Item_func_in::get_mm_tree");
+  if (const_item())
+    DBUG_RETURN(get_mm_tree_for_const(param, this));
 
   param->cond= this;
 
-  switch (cond_func->functype()) {
-  case Item_func::BETWEEN:
-    if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM)
-    {
-      field_item= (Item_field*) (cond_func->arguments()[0]->real_item());
-      ftree= get_full_func_mm_tree(param, cond_func, field_item, NULL, inv);
-    }
+  if (key_item()->real_item()->type() != Item::FIELD_ITEM)
+    DBUG_RETURN(0);
+  Item_field *field= (Item_field*) (key_item()->real_item());
+  SEL_TREE *tree= get_full_func_mm_tree(param, this, field, NULL, negated);
+  DBUG_RETURN(tree);
+}
 
-    /*
-      Concerning the code below see the NOTES section in
-      the comments for the function get_full_func_mm_tree()
-    */
-    for (uint i= 1 ; i < cond_func->arg_count ; i++)
+
+SEL_TREE *Item_equal::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
+{
+  DBUG_ENTER("Item_equal::get_mm_tree");
+  if (const_item())
+    DBUG_RETURN(get_mm_tree_for_const(param, this));
+
+  param->cond= this;
+
+  SEL_TREE *tree= 0;
+  SEL_TREE *ftree= 0;
+
+  Item *value;
+  if (!(value= get_const()) || value->is_expensive())
+    DBUG_RETURN(0);
+
+  Item_equal_fields_iterator it(*this);
+  table_map ref_tables= value->used_tables();
+  table_map param_comp= ~(param->prev_tables | param->read_tables |
+		          param->current_table);
+  while (it++)
+  {
+    Field *field= it.get_curr_field();
+    Item_result cmp_type= field->cmp_type();
+    if (!((ref_tables | field->table->map) & param_comp))
     {
-      if (cond_func->arguments()[i]->real_item()->type() == Item::FIELD_ITEM)
-      {
-        field_item= (Item_field*) (cond_func->arguments()[i]->real_item());
-        SEL_TREE *tmp= get_full_func_mm_tree(param, cond_func, 
-                                    field_item, (Item*)(intptr)i, inv);
-        if (inv)
-        {
-          tree= !tree ? tmp : tree_or(param, tree, tmp);
-          if (tree == NULL)
-            break;
-        }
-        else 
-          tree= tree_and(param, tree, tmp);
-      }
-      else if (inv)
-      { 
-        tree= 0;
-        break;
-      }
+      tree= get_mm_parts(param, this, field, Item_func::EQ_FUNC,
+                         value, cmp_type);
+      ftree= !ftree ? tree : tree_and(param, ftree, tree);
     }
+  }
+  
+  DBUG_RETURN(ftree);
+}
 
-    ftree = tree_and(param, ftree, tree);
-    break;
-  case Item_func::IN_FUNC:
+
+SEL_TREE *Item_func::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr)
+{
+  DBUG_ENTER("Item::get_mm_tree");
+  if (const_item())
+    DBUG_RETURN(get_mm_tree_for_const(param, this));
+
+  if (select_optimize() == Item_func::OPTIMIZE_NONE)
+    DBUG_RETURN(0);			       
+
+  param->cond= this;
+
+  SEL_TREE *ftree= 0;
+  if (arguments()[0]->real_item()->type() == Item::FIELD_ITEM)
   {
-    Item_func_in *func=(Item_func_in*) cond_func;
-    if (func->key_item()->real_item()->type() != Item::FIELD_ITEM)
+    Item_field *field_item= (Item_field*) (arguments()[0]->real_item());
+    Item *value= arg_count > 1 ? arguments()[1] : NULL;
+    if (value && value->is_expensive())
       DBUG_RETURN(0);
-    field_item= (Item_field*) (func->key_item()->real_item());
-    ftree= get_full_func_mm_tree(param, cond_func, field_item, NULL, inv);
-    break;
+    if (!arguments()[0]->real_item()->const_item())
+      ftree= get_full_func_mm_tree(param, this, field_item, value, false);
   }
-  case Item_func::MULT_EQUAL_FUNC:
+  /*
+    Even if get_full_func_mm_tree() was executed above and did not
+    return a range predicate it may still be possible to create one
+    by reversing the order of the operands. Note that this only
+    applies to predicates where both operands are fields. Example: A
+    query of the form
+
+       WHERE t1.a OP t2.b
+
+    In this case, arguments()[0] == t1.a and arguments()[1] == t2.b.
+    When creating range predicates for t2, get_full_func_mm_tree()
+    above will return NULL because 'field' belongs to t1 and only
+    predicates that applies to t2 are of interest. In this case a
+    call to get_full_func_mm_tree() with reversed operands (see
+    below) may succeed.
+  */
+  if (!ftree && have_rev_func() &&
+      arguments()[1]->real_item()->type() == Item::FIELD_ITEM)
   {
-    Item_equal *item_equal= (Item_equal *) this;
-    if (!(value= item_equal->get_const()) || value->is_expensive())
+    Item_field *field_item= (Item_field*) (arguments()[1]->real_item());
+    Item *value= arguments()[0];
+    if (value && value->is_expensive())
       DBUG_RETURN(0);
-    Item_equal_fields_iterator it(*item_equal);
-    ref_tables= value->used_tables();
-    while (it++)
-    {
-      Field *field= it.get_curr_field();
-      Item_result cmp_type= field->cmp_type();
-      if (!((ref_tables | field->table->map) & param_comp))
-      {
-        tree= get_mm_parts(param, this, field, Item_func::EQ_FUNC,
-		           value,cmp_type);
-        ftree= !ftree ? tree : tree_and(param, ftree, tree);
-      }
-    }
-    
-    DBUG_RETURN(ftree);
-  }
-  default:
-
-    DBUG_ASSERT (!ftree);
-    if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM)
-    {
-      field_item= (Item_field*) (cond_func->arguments()[0]->real_item());
-      value= cond_func->arg_count > 1 ? cond_func->arguments()[1] : NULL;
-      if (value && value->is_expensive())
-        DBUG_RETURN(0);
-      if (!cond_func->arguments()[0]->real_item()->const_item())
-        ftree= get_full_func_mm_tree(param, cond_func, field_item, value, inv);
-    }
-    /*
-      Even if get_full_func_mm_tree() was executed above and did not
-      return a range predicate it may still be possible to create one
-      by reversing the order of the operands. Note that this only
-      applies to predicates where both operands are fields. Example: A
-      query of the form
-
-         WHERE t1.a OP t2.b
-
-      In this case, arguments()[0] == t1.a and arguments()[1] == t2.b.
-      When creating range predicates for t2, get_full_func_mm_tree()
-      above will return NULL because 'field' belongs to t1 and only
-      predicates that applies to t2 are of interest. In this case a
-      call to get_full_func_mm_tree() with reversed operands (see
-      below) may succeed.
-    */
-    if (!ftree && cond_func->have_rev_func() &&
-        cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM)
-    {
-      field_item= (Item_field*) (cond_func->arguments()[1]->real_item());
-      value= cond_func->arguments()[0];
-      if (value && value->is_expensive())
-        DBUG_RETURN(0);
-      if (!cond_func->arguments()[1]->real_item()->const_item())
-        ftree= get_full_func_mm_tree(param, cond_func, field_item, value, inv);
-    }
+    if (!arguments()[1]->real_item()->const_item())
+      ftree= get_full_func_mm_tree(param, this, field_item, value, false);
   }
 
   DBUG_RETURN(ftree);

Follow ups

References