[Maria-developers] Step#4: MDEV-7950 Item_func::type() takes 0.26% in OLTP RO
Hi Sergey, Please review a patch for the next step for MDEV-7950 (one small thing at a time, to avoid huge unclear patches) Thanks.
Hi Alexander, comments inline. On Wed, May 06, 2015 at 07:51:18PM +0400, Alexander Barkov wrote:
Hi Sergey,
Please review a patch for the next step for MDEV-7950
(one small thing at a time, to avoid huge unclear patches)
Thanks.
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 cond_equal_ref is initialized to 0 by caller, why duplicate initialization here and everywhere else?
index 53f249d..0c279ed 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -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; If possible, here and everywhere else please use
When you write XXX::build_equal_items() you force static call indeed, but not inlining, which we're aiming for. That is non-inlined static call as such won't save us much compared to virtual call. I think our aim should be to keep build_equal_items_and_cond() virtual and have build_equal_items() inlined into the former. So we mostly rely on compiler's optimizer. I _believe_ it should be clever enough to optimize the following as described above: class Item { ... virtual build_equal_items_and_cond() { return build_equal_items(); } ... } This should be easy to test by adding "inline" to build_equal_items() declaration and compiling with -Winline. Makes sense? ...skip... push_back(item_equal, thd->mem_root). This will save us one pthread_getspecific() call.
@@ -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); Didn't get the need for build_item_equal_from_current_level() and build_new_level(). Is it just some minor refactoring?
...skip...
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; } The only difference from base build_equal_items_and_cond() is just DBUG_ASSERT(). I think assert can be moved into base implementation with more complex condition too (assuming we'll decide to keep only base implementation).
...skip...
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 @@ -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) I believe this *cond_equal_ref= cond_equal is probably not needed. Initialize cond_equal_ref directly and remove cond_equal variable.
Regards, Sergey
Hi Alexander, following profiler reports for build_equal_items* in your and mine patches. For OLTP RO they're equal. I guess Item_func::build_equal_items() was not inlined due to recursion? Bar's patch ----------- 0.06% Item_func_eq::build_equal_items_and_cond() 0.05% build_equal_items() 0.01% Item_func::build_equal_items() 0.00% Item_func::build_equal_items_and_cond() Svoj's patch ------------ 0.06% build_equal_items() 0.05% Item_func_eq::build_equal_items_and_cond() 0.01% Item_func::build_equal_items() 0.00% Item::build_equal_items_and_cond() Regards, Sergey On Thu, May 07, 2015 at 01:58:28PM +0400, Sergey Vojtovich wrote:
Hi Alexander,
comments inline.
On Wed, May 06, 2015 at 07:51:18PM +0400, Alexander Barkov wrote:
Hi Sergey,
Please review a patch for the next step for MDEV-7950
(one small thing at a time, to avoid huge unclear patches)
Thanks.
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 cond_equal_ref is initialized to 0 by caller, why duplicate initialization here and everywhere else?
When you write XXX::build_equal_items() you force static call indeed, but not inlining, which we're aiming for. That is non-inlined static call as such won't save us much compared to virtual call.
I think our aim should be to keep build_equal_items_and_cond() virtual and have build_equal_items() inlined into the former. So we mostly rely on compiler's optimizer.
I _believe_ it should be clever enough to optimize the following as described above: class Item { ... virtual build_equal_items_and_cond() { return build_equal_items(); } ... }
This should be easy to test by adding "inline" to build_equal_items() declaration and compiling with -Winline.
Makes sense?
...skip...
index 53f249d..0c279ed 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -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; If possible, here and everywhere else please use push_back(item_equal, thd->mem_root). This will save us one pthread_getspecific() call.
@@ -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); Didn't get the need for build_item_equal_from_current_level() and build_new_level(). Is it just some minor refactoring?
...skip...
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; } The only difference from base build_equal_items_and_cond() is just DBUG_ASSERT(). I think assert can be moved into base implementation with more complex condition too (assuming we'll decide to keep only base implementation).
...skip...
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 @@ -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) I believe this *cond_equal_ref= cond_equal is probably not needed. Initialize cond_equal_ref directly and remove cond_equal variable.
Regards, Sergey
Hi Sergey, I'm sending a new version, which takes into account your review suggestions and our skype discussion. Thanks. On 05/08/2015 12:27 PM, Sergey Vojtovich wrote:
Hi Alexander,
following profiler reports for build_equal_items* in your and mine patches. For OLTP RO they're equal. I guess Item_func::build_equal_items() was not inlined due to recursion?
Bar's patch ----------- 0.06% Item_func_eq::build_equal_items_and_cond() 0.05% build_equal_items() 0.01% Item_func::build_equal_items() 0.00% Item_func::build_equal_items_and_cond()
Svoj's patch ------------ 0.06% build_equal_items() 0.05% Item_func_eq::build_equal_items_and_cond() 0.01% Item_func::build_equal_items() 0.00% Item::build_equal_items_and_cond()
Regards, Sergey
On Thu, May 07, 2015 at 01:58:28PM +0400, Sergey Vojtovich wrote:
Hi Alexander,
comments inline.
On Wed, May 06, 2015 at 07:51:18PM +0400, Alexander Barkov wrote:
Hi Sergey,
Please review a patch for the next step for MDEV-7950
(one small thing at a time, to avoid huge unclear patches)
Thanks.
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 cond_equal_ref is initialized to 0 by caller, why duplicate initialization here and everywhere else?
When you write XXX::build_equal_items() you force static call indeed, but not inlining, which we're aiming for. That is non-inlined static call as such won't save us much compared to virtual call.
I think our aim should be to keep build_equal_items_and_cond() virtual and have build_equal_items() inlined into the former. So we mostly rely on compiler's optimizer.
I _believe_ it should be clever enough to optimize the following as described above: class Item { ... virtual build_equal_items_and_cond() { return build_equal_items(); } ... }
This should be easy to test by adding "inline" to build_equal_items() declaration and compiling with -Winline.
Makes sense?
...skip...
index 53f249d..0c279ed 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -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; If possible, here and everywhere else please use push_back(item_equal, thd->mem_root). This will save us one pthread_getspecific() call.
@@ -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); Didn't get the need for build_item_equal_from_current_level() and build_new_level(). Is it just some minor refactoring?
...skip...
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; } The only difference from base build_equal_items_and_cond() is just DBUG_ASSERT(). I think assert can be moved into base implementation with more complex condition too (assuming we'll decide to keep only base implementation).
...skip...
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 @@ -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) I believe this *cond_equal_ref= cond_equal is probably not needed. Initialize cond_equal_ref directly and remove cond_equal variable.
Regards, Sergey
Hi Alexander, ok to push. Thanks, Sergey On Wed, May 13, 2015 at 02:22:22PM +0400, Alexander Barkov wrote:
Hi Sergey,
I'm sending a new version, which takes into account your review suggestions and our skype discussion.
Thanks.
On 05/08/2015 12:27 PM, Sergey Vojtovich wrote:
Hi Alexander,
following profiler reports for build_equal_items* in your and mine patches. For OLTP RO they're equal. I guess Item_func::build_equal_items() was not inlined due to recursion?
Bar's patch ----------- 0.06% Item_func_eq::build_equal_items_and_cond() 0.05% build_equal_items() 0.01% Item_func::build_equal_items() 0.00% Item_func::build_equal_items_and_cond()
Svoj's patch ------------ 0.06% build_equal_items() 0.05% Item_func_eq::build_equal_items_and_cond() 0.01% Item_func::build_equal_items() 0.00% Item::build_equal_items_and_cond()
Regards, Sergey
On Thu, May 07, 2015 at 01:58:28PM +0400, Sergey Vojtovich wrote:
Hi Alexander,
comments inline.
On Wed, May 06, 2015 at 07:51:18PM +0400, Alexander Barkov wrote:
Hi Sergey,
Please review a patch for the next step for MDEV-7950
(one small thing at a time, to avoid huge unclear patches)
Thanks.
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 cond_equal_ref is initialized to 0 by caller, why duplicate initialization here and everywhere else?
When you write XXX::build_equal_items() you force static call indeed, but not inlining, which we're aiming for. That is non-inlined static call as such won't save us much compared to virtual call.
I think our aim should be to keep build_equal_items_and_cond() virtual and have build_equal_items() inlined into the former. So we mostly rely on compiler's optimizer.
I _believe_ it should be clever enough to optimize the following as described above: class Item { ... virtual build_equal_items_and_cond() { return build_equal_items(); } ... }
This should be easy to test by adding "inline" to build_equal_items() declaration and compiling with -Winline.
Makes sense?
...skip...
index 53f249d..0c279ed 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -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; If possible, here and everywhere else please use push_back(item_equal, thd->mem_root). This will save us one pthread_getspecific() call.
@@ -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); Didn't get the need for build_item_equal_from_current_level() and build_new_level(). Is it just some minor refactoring?
...skip...
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; } The only difference from base build_equal_items_and_cond() is just DBUG_ASSERT(). I think assert can be moved into base implementation with more complex condition too (assuming we'll decide to keep only base implementation).
...skip...
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 @@ -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) I believe this *cond_equal_ref= cond_equal is probably not needed. Initialize cond_equal_ref directly and remove cond_equal variable.
Regards, Sergey
diff --git a/sql/item.h b/sql/item.h index 043605a..017d348 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1128,9 +1128,11 @@ class Item: public Type_std_attributes void print_value(String *); virtual void update_used_tables() {} virtual COND *build_equal_items(THD *thd, COND_EQUAL *inherited, - bool link_item_fields) + bool link_item_fields, + COND_EQUAL **cond_equal_ref) { update_used_tables(); + DBUG_ASSERT(!cond_equal_ref || !cond_equal_ref[0]); return this; } /* @@ -2335,7 +2337,8 @@ class Item_field :public Item_ident update_table_bitmaps(); } COND *build_equal_items(THD *thd, COND_EQUAL *inherited, - bool link_item_fields) + bool link_item_fields, + COND_EQUAL **cond_equal_ref) { /* normilize_cond() replaced all conditions of type @@ -2351,7 +2354,8 @@ class Item_field :public Item_ident SELECT * FROM t1 WHERE DEFAULT(a); */ DBUG_ASSERT(type() != FIELD_ITEM); - return Item_ident::build_equal_items(thd, inherited, link_item_fields); + return Item_ident::build_equal_items(thd, inherited, link_item_fields, + cond_equal_ref); } bool is_result_field() { return false; } void set_result_field(Field *field) {} @@ -3593,7 +3597,8 @@ class Item_ref :public Item_ident table_map used_tables() const; void update_used_tables(); COND *build_equal_items(THD *thd, COND_EQUAL *inherited, - bool link_item_fields) + bool link_item_fields, + COND_EQUAL **cond_equal_ref) { /* normilize_cond() replaced all conditions of type @@ -3604,7 +3609,8 @@ class Item_ref :public Item_ident already be replaced. No Item_ref referencing to Item_field are possible. */ DBUG_ASSERT(real_type() != FIELD_ITEM); - return Item_ident::build_equal_items(thd, inherited, link_item_fields); + return Item_ident::build_equal_items(thd, inherited, link_item_fields, + cond_equal_ref); } bool const_item() const { diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 53f249d..0a3bf41 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -563,7 +563,8 @@ class Item_func_eq :public Item_bool_rowready_func2 const char *func_name() const { return "="; } Item *negated_item(); COND *build_equal_items(THD *thd, COND_EQUAL *inherited, - bool link_item_fields); + 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: @@ -1772,7 +1773,8 @@ class Item_cond :public Item_bool_func used_tables_and_const_cache_update_and_join(list); } COND *build_equal_items(THD *thd, COND_EQUAL *inherited, - bool link_item_fields); + bool link_item_fields, + COND_EQUAL **cond_equal_ref); 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 +1962,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(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 +1994,11 @@ class COND_EQUAL: public Sql_alloc { upper_levels= 0; } + COND_EQUAL(Item_equal *item, MEM_ROOT *mem_root) + :upper_levels(0) + { + current_level.push_back(item, mem_root); + } void copy(COND_EQUAL &cond_equal) { max_members= cond_equal.max_members; @@ -2107,7 +2117,8 @@ class Item_cond_and :public Item_cond virtual uint exists2in_reserved_items() { return list.elements; }; bool walk_top_and(Item_processor processor, uchar *arg); COND *build_equal_items(THD *thd, COND_EQUAL *inherited, - bool link_item_fields); + bool link_item_fields, + COND_EQUAL **cond_equal_ref); };
inline bool is_cond_and(Item *item) diff --git a/sql/item_func.h b/sql/item_func.h index 0d57c2b..a5ddb24 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -132,7 +132,8 @@ class Item_func :public Item_func_or_sum, public Used_tables_and_const_cache used_tables_and_const_cache_update_and_join(arg_count, args); } COND *build_equal_items(THD *thd, COND_EQUAL *inherited, - bool link_item_fields); + bool link_item_fields, + COND_EQUAL **cond_equal_ref); 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..056c623 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -445,7 +445,8 @@ class Item_sum :public Item_func_or_sum table_map used_tables() const { return used_tables_cache; } void update_used_tables (); COND *build_equal_items(THD *thd, COND_EQUAL *inherited, - bool link_item_fields) + bool link_item_fields, + COND_EQUAL **cond_equal_ref) { /* Item_sum (and derivants) of the original WHERE/HAVING clauses @@ -453,7 +454,8 @@ class Item_sum :public Item_func_or_sum build_equal_items() is called. See Item::split_sum_func2(). */ DBUG_ASSERT(0); - return Item::build_equal_items(thd, inherited, link_item_fields); + return Item::build_equal_items(thd, inherited, link_item_fields, + cond_equal_ref); } bool is_null() { return null_value; } void make_const () diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 95778f0..2cc0173 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -12773,7 +12773,8 @@ bool Item_func_eq::check_equality(THD *thd, COND_EQUAL *cond_equal,
COND *Item_cond_and::build_equal_items(THD *thd, COND_EQUAL *inherited, - bool link_item_fields) + bool link_item_fields, + COND_EQUAL **cond_equal_ref) { Item_equal *item_equal; COND_EQUAL cond_equal; @@ -12785,6 +12786,7 @@ COND *Item_cond_and::build_equal_items(THD *thd, List_iterator<Item> li(*args); Item *item;
+ DBUG_ASSERT(!cond_equal_ref || !cond_equal_ref[0]); /* Retrieve all conjuncts of this level detecting the equality that are subject to substitution by multiple equality items and @@ -12809,7 +12811,7 @@ COND *Item_cond_and::build_equal_items(THD *thd, if (!args->elements && !cond_equal.current_level.elements && !eq_list.elements) - return new Item_int((longlong) 1, 1); + return new (thd->mem_root) Item_int((longlong) 1, 1);
List_iterator_fast<Item_equal> it(cond_equal.current_level); while ((item_equal= it++)) @@ -12833,7 +12835,7 @@ COND *Item_cond_and::build_equal_items(THD *thd, while ((item= li++)) { Item *new_item; - if ((new_item= item->build_equal_items(thd, inherited, FALSE)) + if ((new_item= item->build_equal_items(thd, inherited, false, NULL)) != item) { /* This replacement happens only for standalone equalities */ @@ -12848,19 +12850,23 @@ COND *Item_cond_and::build_equal_items(THD *thd, args->append(&eq_list); args->append((List<Item> *)&cond_equal.current_level); update_used_tables(); + if (cond_equal_ref) + *cond_equal_ref= &m_cond_equal; return this; }
COND *Item_cond::build_equal_items(THD *thd, COND_EQUAL *inherited, - bool link_item_fields) + bool link_item_fields, + COND_EQUAL **cond_equal_ref) { List<Item> *args= argument_list();
List_iterator<Item> li(*args); Item *item;
+ DBUG_ASSERT(!cond_equal_ref || !cond_equal_ref[0]); /* Make replacement of equality predicates for lower levels of the condition expression. @@ -12870,7 +12876,7 @@ COND *Item_cond::build_equal_items(THD *thd, while ((item= li++)) { Item *new_item; - if ((new_item= item->build_equal_items(thd, inherited, FALSE)) + if ((new_item= item->build_equal_items(thd, inherited, false, NULL)) != item) { /* This replacement happens only for standalone equalities */ @@ -12889,11 +12895,14 @@ COND *Item_cond::build_equal_items(THD *thd,
COND *Item_func_eq::build_equal_items(THD *thd, COND_EQUAL *inherited, - bool link_item_fields) + bool link_item_fields, + COND_EQUAL **cond_equal_ref) { COND_EQUAL cond_equal; cond_equal.upper_levels= inherited; List<Item> eq_list; + + DBUG_ASSERT(!cond_equal_ref || !cond_equal_ref[0]); /* If an equality predicate forms the whole and level, we call it standalone equality and it's processed here. @@ -12909,7 +12918,7 @@ COND *Item_func_eq::build_equal_items(THD *thd, Item_equal *item_equal; int n= cond_equal.current_level.elements + eq_list.elements; if (n == 0) - return new Item_int((longlong) 1,1); + return new (thd->mem_root) Item_int((longlong) 1,1); else if (n == 1) { if ((item_equal= cond_equal.current_level.pop())) @@ -12919,10 +12928,14 @@ COND *Item_func_eq::build_equal_items(THD *thd, set_if_bigger(thd->lex->current_select->max_equal_elems, item_equal->n_field_items()); item_equal->upper_levels= inherited; + if (cond_equal_ref) + *cond_equal_ref= new (thd->mem_root) COND_EQUAL(item_equal, + thd->mem_root); return item_equal; } Item *res= eq_list.pop(); res->update_used_tables(); + DBUG_ASSERT(res->type() == FUNC_ITEM); return res; } else @@ -12946,15 +12959,19 @@ COND *Item_func_eq::build_equal_items(THD *thd, cond_equal.current_level= and_cond->m_cond_equal.current_level; args->append((List<Item> *)&cond_equal.current_level); and_cond->update_used_tables(); + if (cond_equal_ref) + *cond_equal_ref= &and_cond->m_cond_equal; return and_cond; } } - return Item_func::build_equal_items(thd, inherited, link_item_fields); + return Item_func::build_equal_items(thd, inherited, link_item_fields, + cond_equal_ref); }
COND *Item_func::build_equal_items(THD *thd, COND_EQUAL *inherited, - bool link_item_fields) + bool link_item_fields, + COND_EQUAL **cond_equal_ref) { /* For each field reference in cond, not from equal item predicates, @@ -12968,6 +12985,20 @@ COND *Item_func::build_equal_items(THD *thd, COND_EQUAL *inherited, &Item::equal_fields_propagator, (uchar *) inherited); cond->update_used_tables(); + DBUG_ASSERT(cond == this); + DBUG_ASSERT(!cond_equal_ref || !cond_equal_ref[0]); + return cond; +} + + +COND *Item_equal::build_equal_items(THD *thd, COND_EQUAL *inherited, + bool link_item_fields, + COND_EQUAL **cond_equal_ref) +{ + COND *cond= Item_func::build_equal_items(thd, inherited, link_item_fields, + cond_equal_ref); + if (cond_equal_ref) + *cond_equal_ref= new (thd->mem_root) COND_EQUAL(this, thd->mem_root); return cond; }
@@ -13049,28 +13080,19 @@ static COND *build_equal_items(JOIN *join, COND *cond, bool link_equal_fields) { THD *thd= join->thd; - COND_EQUAL *cond_equal= 0; + + *cond_equal_ref= NULL;
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(thd, inherited, link_equal_fields, + cond_equal_ref); + if (*cond_equal_ref) { - cond_equal= new COND_EQUAL; - cond_equal->current_level.push_back((Item_equal *) cond); + (*cond_equal_ref)->upper_levels= inherited; + inherited= *cond_equal_ref; } } - if (cond_equal) - { - cond_equal->upper_levels= inherited; - inherited= cond_equal; - } - *cond_equal_ref= cond_equal;
if (join_list && !ignore_on_conds) {
participants (2)
-
Alexander Barkov
-
Sergey Vojtovich