maria-developers team mailing list archive
-
maria-developers team
-
Mailing list archive
-
Message #08470
MDEV-8024 Remove excessive update_used_tables() calls
Hi Sergei,
Please review a patch for MDEV-8024.
It's needed to as a pre-requisite for
"MDEV-7950 Item_func::type() takes 0.26% in OLTP RO"
Thanks.
diff --git a/sql/item.cc b/sql/item.cc
index e9bbdc7..502b8ae 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -59,6 +59,21 @@ bool cmp_items(Item *a, Item *b)
}
+void
+Used_tables_and_const_cache::
+ used_tables_and_const_cache_update_and_join(List<Item> &list)
+{
+ List_iterator_fast<Item> li(list);
+ Item *item;
+ while ((item=li++))
+ {
+ item->update_used_tables();
+ used_tables_and_const_cache_join(item);
+ }
+}
+
+
+
/*****************************************************************************
** Item functions
*****************************************************************************/
@@ -4730,10 +4745,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
else
{
Item::Type ref_type= (*reference)->type();
- prev_subselect_item->used_tables_cache|=
- (*reference)->used_tables();
- prev_subselect_item->const_item_cache&=
- (*reference)->const_item();
+ prev_subselect_item->used_tables_and_const_cache_join(*reference);
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex, this,
((ref_type == REF_ITEM || ref_type == FIELD_ITEM) ?
@@ -4759,8 +4771,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
if (ref != not_found_item)
{
DBUG_ASSERT(*ref && (*ref)->fixed);
- prev_subselect_item->used_tables_cache|= (*ref)->used_tables();
- prev_subselect_item->const_item_cache&= (*ref)->const_item();
+ prev_subselect_item->used_tables_and_const_cache_join(*ref);
break;
}
}
@@ -6783,8 +6794,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
if (ref != not_found_item)
{
DBUG_ASSERT(*ref && (*ref)->fixed);
- prev_subselect_item->used_tables_cache|= (*ref)->used_tables();
- prev_subselect_item->const_item_cache&= (*ref)->const_item();
+ prev_subselect_item->used_tables_and_const_cache_join(*ref);
break;
}
/*
@@ -6828,10 +6838,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference)
if (from_field == view_ref_found)
{
Item::Type refer_type= (*reference)->type();
- prev_subselect_item->used_tables_cache|=
- (*reference)->used_tables();
- prev_subselect_item->const_item_cache&=
- (*reference)->const_item();
+ prev_subselect_item->used_tables_and_const_cache_join(*reference);
DBUG_ASSERT((*reference)->type() == REF_ITEM);
mark_as_dependent(thd, last_checked_context->select_lex,
context->select_lex, this,
diff --git a/sql/item.h b/sql/item.h
index 5820f11..7e7c573b0 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -3328,6 +3328,63 @@ class Item_args
};
+class Used_tables_and_const_cache
+{
+public:
+ /*
+ In some cases used_tables_cache is not what used_tables() return
+ so the method should be used where one need used tables bit map
+ (even internally in Item_func_* code).
+ */
+ table_map used_tables_cache;
+ bool const_item_cache;
+
+ Used_tables_and_const_cache()
+ :used_tables_cache(0),
+ const_item_cache(true)
+ { }
+ Used_tables_and_const_cache(const Used_tables_and_const_cache *other)
+ :used_tables_cache(other->used_tables_cache),
+ const_item_cache(other->const_item_cache)
+ { }
+ void used_tables_and_const_cache_init()
+ {
+ used_tables_cache= 0;
+ const_item_cache= true;
+ }
+ void used_tables_and_const_cache_copy(const Used_tables_and_const_cache *c)
+ {
+ *this= *c;
+ }
+ void used_tables_and_const_cache_join(const Item *item)
+ {
+ used_tables_cache|= item->used_tables();
+ const_item_cache&= item->const_item();
+ }
+ /*
+ Call update_used_tables() for all items in the array "args"
+ and join with the current cache.
+ "this" must be initialized with a constructor or
+ re-initialized with used_tables_and_const_cache_init().
+ */
+ void used_tables_and_const_cache_update_and_join(uint argc, Item **argv)
+ {
+ for (uint i=0 ; i < argc ; i++)
+ {
+ argv[i]->update_used_tables();
+ used_tables_and_const_cache_join(argv[i]);
+ }
+ }
+ /*
+ Call update_used_tables() for all items in the list
+ and join with the current cache.
+ "this" must be initialized with a constructor or
+ re-initialized with used_tables_and_const_cache_init().
+ */
+ void used_tables_and_const_cache_update_and_join(List<Item> &list);
+};
+
+
/**
An abstract class representing common features of
regular functions and aggregate functions.
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 23676d7..eec99d9 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -1520,9 +1520,8 @@ bool Item_in_optimizer::fix_left(THD *thd)
if (args[1]->fixed)
{
/* to avoid overriding is called to update left expression */
- used_tables_cache|= args[1]->used_tables();
+ used_tables_and_const_cache_join(args[1]);
with_sum_func= with_sum_func || args[1]->with_sum_func;
- const_item_cache= const_item_cache && args[1]->const_item();
}
DBUG_RETURN(0);
}
@@ -1551,8 +1550,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, Item **ref)
with_subselect= 1;
with_sum_func= with_sum_func || args[1]->with_sum_func;
with_field= with_field || args[1]->with_field;
- used_tables_cache|= args[1]->used_tables();
- const_item_cache&= args[1]->const_item();
+ used_tables_and_const_cache_join(args[1]);
fixed= 1;
return FALSE;
}
@@ -2081,11 +2079,10 @@ void Item_func_interval::fix_length_and_dec()
}
maybe_null= 0;
max_length= 2;
- used_tables_cache|= row->used_tables();
+ used_tables_and_const_cache_join(row);
not_null_tables_cache= row->not_null_tables();
with_sum_func= with_sum_func || row->with_sum_func;
with_field= with_field || row->with_field;
- const_item_cache&= row->const_item();
}
@@ -4302,8 +4299,8 @@ Item_cond::fix_fields(THD *thd, Item **ref)
List_iterator<Item> li(list);
Item *item;
uchar buff[sizeof(char*)]; // Max local vars in function
- not_null_tables_cache= used_tables_cache= 0;
- const_item_cache= 1;
+ not_null_tables_cache= 0;
+ used_tables_and_const_cache_init();
/*
and_table_cache is the value that Item_cond_or() returns for
@@ -4453,8 +4450,7 @@ void Item_cond::fix_after_pullout(st_select_lex *new_parent, Item **ref)
List_iterator<Item> li(list);
Item *item;
- used_tables_cache=0;
- const_item_cache=1;
+ used_tables_and_const_cache_init();
and_tables_cache= ~(table_map) 0; // Here and below we do as fix_fields does
not_null_tables_cache= 0;
@@ -4464,8 +4460,7 @@ void Item_cond::fix_after_pullout(st_select_lex *new_parent, Item **ref)
table_map tmp_table_map;
item->fix_after_pullout(new_parent, li.ref());
item= *li.ref();
- used_tables_cache|= item->used_tables();
- const_item_cache&= item->const_item();
+ used_tables_and_const_cache_join(item);
if (item->const_item())
and_tables_cache= (table_map) 0;
@@ -4648,22 +4643,6 @@ Item_cond::used_tables() const
}
-void Item_cond::update_used_tables()
-{
- List_iterator_fast<Item> li(list);
- Item *item;
-
- used_tables_cache=0;
- const_item_cache=1;
- while ((item=li++))
- {
- item->update_used_tables();
- used_tables_cache|= item->used_tables();
- const_item_cache&= item->const_item();
- }
-}
-
-
void Item_cond::print(String *str, enum_query_type query_type)
{
str->append('(');
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 2d039d5..bf388ef 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -1763,7 +1763,11 @@ class Item_cond :public Item_bool_func
enum Type type() const { return COND_ITEM; }
List<Item>* argument_list() { return &list; }
table_map used_tables() const;
- void update_used_tables();
+ void update_used_tables()
+ {
+ used_tables_and_const_cache_init();
+ used_tables_and_const_cache_update_and_join(list);
+ }
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,
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 50bc85f..4007d6b 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -178,8 +178,44 @@ Item_func::fix_fields(THD *thd, Item **ref)
Item **arg,**arg_end;
uchar buff[STACK_BUFF_ALLOC]; // Max argument in function
- used_tables_cache= not_null_tables_cache= 0;
- const_item_cache=1;
+ // used_tables_and_const_cache_init(); // QQ: is it needed, for safety?
+ /*
+ Comments about the commented used_tables_and_const_cache_init() above:
+
+ The "Used_tables_and_const_cache" part of Item_func is initialized in
+ Item_func::Item_func(). So normally, the above initialization is not needed.
+ And it does pass all tests.
+
+ However, in rare cases "fixed" can be set back to "false" after
+ fix_fields() was called for the very first time.
+
+ These functions reset "fixed" to "false":
+ - unfix_fields()
+ - st_select_lex_unit::reinit_exec_mechanism()
+ - make_in_exists_conversion()
+ - convert_join_subqueries_to_semijoins()
+
+ Possible solutions:
+ - Keep the above initialization commented (or just remove it) and hope
+ that everything will work fine :)
+ Adding some DBUG_ASSERTs at least would nice.
+
+ - Uncomment initialization used_tables_and_const_cache_init()
+ (this will give better reliability with slighly worse performance)
+ This is what was before this patch.
+
+ - Make Item::fixed private (or at least protected), add a new method:
+
+ void Item::unfix()
+ {
+ fixed= 0;
+ used_tables_and_const_cache_init();
+ }
+ and use it instead of direct assignment "item->fixed= false;".
+
+ */
+
+ not_null_tables_cache= 0;
/*
Use stack limit of STACK_MIN_SIZE * 2 since
@@ -221,8 +257,7 @@ Item_func::fix_fields(THD *thd, Item **ref)
with_sum_func= with_sum_func || item->with_sum_func;
with_field= with_field || item->with_field;
- used_tables_cache|= item->used_tables();
- const_item_cache&= item->const_item();
+ used_tables_and_const_cache_join(item);
with_subselect|= item->has_subquery();
}
}
@@ -269,8 +304,8 @@ void Item_func::fix_after_pullout(st_select_lex *new_parent, Item **ref)
{
Item **arg,**arg_end;
- used_tables_cache= not_null_tables_cache= 0;
- const_item_cache=1;
+ used_tables_and_const_cache_init();
+ not_null_tables_cache= 0;
if (arg_count)
{
@@ -279,9 +314,8 @@ void Item_func::fix_after_pullout(st_select_lex *new_parent, Item **ref)
(*arg)->fix_after_pullout(new_parent, arg);
Item *item= *arg;
- used_tables_cache|= item->used_tables();
+ used_tables_and_const_cache_join(item);
not_null_tables_cache|= item->not_null_tables();
- const_item_cache&= item->const_item();
}
}
}
@@ -436,19 +470,6 @@ void Item_func::split_sum_func(THD *thd, Item **ref_pointer_array,
}
-void Item_func::update_used_tables()
-{
- used_tables_cache=0;
- const_item_cache=1;
- for (uint i=0 ; i < arg_count ; i++)
- {
- args[i]->update_used_tables();
- used_tables_cache|=args[i]->used_tables();
- const_item_cache&=args[i]->const_item();
- }
-}
-
-
table_map Item_func::used_tables() const
{
return used_tables_cache;
@@ -3503,8 +3524,7 @@ udf_handler::fix_fields(THD *thd, Item_func_or_sum *func,
/* Fix all arguments */
func->maybe_null=0;
- used_tables_cache=0;
- const_item_cache=1;
+ used_tables_and_const_cache_init();
if ((f_args.arg_count=arg_count))
{
@@ -3546,8 +3566,7 @@ udf_handler::fix_fields(THD *thd, Item_func_or_sum *func,
func->with_sum_func= func->with_sum_func || item->with_sum_func;
func->with_field= func->with_field || item->with_field;
func->with_subselect|= item->with_subselect;
- used_tables_cache|=item->used_tables();
- const_item_cache&=item->const_item();
+ used_tables_and_const_cache_join(item);
f_args.arg_type[i]=item->result_type();
}
//TODO: why all following memory is not allocated with 1 call of sql_alloc?
diff --git a/sql/item_func.h b/sql/item_func.h
index 653c08e..c78c585 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -31,7 +31,7 @@ extern "C" /* Bug in BSDI include file */
#endif
-class Item_func :public Item_func_or_sum
+class Item_func :public Item_func_or_sum, public Used_tables_and_const_cache
{
void sync_with_sum_func_and_with_field(List<Item> &list);
protected:
@@ -42,15 +42,8 @@ class Item_func :public Item_func_or_sum
uint allowed_arg_cols;
String *val_str_from_val_str_ascii(String *str, String *str2);
public:
- /*
- In some cases used_tables_cache is not what used_tables() return
- so the method should be used where one need used tables bit map
- (even internally in Item_func_* code).
- */
- table_map used_tables_cache;
table_map not_null_tables_cache;
- bool const_item_cache;
enum Functype { UNKNOWN_FUNC,EQ_FUNC,EQUAL_FUNC,NE_FUNC,LT_FUNC,LE_FUNC,
GE_FUNC,GT_FUNC,FT_FUNC,
LIKE_FUNC,ISNULL_FUNC,ISNOTNULL_FUNC,
@@ -118,11 +111,9 @@ class Item_func :public Item_func_or_sum
}
// Constructor used for Item_cond_and/or (see Item comment)
Item_func(THD *thd, Item_func *item)
- :Item_func_or_sum(thd, item),
+ :Item_func_or_sum(thd, item), Used_tables_and_const_cache(item),
allowed_arg_cols(item->allowed_arg_cols),
- used_tables_cache(item->used_tables_cache),
- not_null_tables_cache(item->not_null_tables_cache),
- const_item_cache(item->const_item_cache)
+ not_null_tables_cache(item->not_null_tables_cache)
{
}
bool fix_fields(THD *, Item **ref);
@@ -130,7 +121,11 @@ class Item_func :public Item_func_or_sum
void quick_fix_field();
table_map used_tables() const;
table_map not_null_tables() const;
- void update_used_tables();
+ void update_used_tables()
+ {
+ used_tables_and_const_cache_init();
+ used_tables_and_const_cache_update_and_join(arg_count, args);
+ }
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; }
@@ -1367,8 +1362,7 @@ class Item_udf_func :public Item_func
{
DBUG_ASSERT(fixed == 0);
bool res= udf.fix_fields(thd, this, arg_count, args);
- used_tables_cache= udf.used_tables_cache;
- const_item_cache= udf.const_item_cache;
+ used_tables_and_const_cache_copy(udf.used_tables_and_const_cache());
fixed= 1;
return res;
}
diff --git a/sql/item_row.cc b/sql/item_row.cc
index 3548a6b..1fc2000 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -39,8 +39,7 @@
*/
Item_row::Item_row(List<Item> &arg):
- Item(), used_tables_cache(0), not_null_tables_cache(0),
- const_item_cache(1), with_null(0)
+ Item(), Used_tables_and_const_cache(), not_null_tables_cache(0), with_null(0)
{
//TODO: think placing 2-3 component items in item (as it done for function)
@@ -126,8 +125,7 @@ void Item_row::cleanup()
Item::cleanup();
/* Reset to the original values */
- used_tables_cache= 0;
- const_item_cache= 1;
+ used_tables_and_const_cache_init();
with_null= 0;
DBUG_VOID_RETURN;
@@ -143,29 +141,14 @@ void Item_row::split_sum_func(THD *thd, Item **ref_pointer_array,
}
-void Item_row::update_used_tables()
-{
- used_tables_cache= 0;
- const_item_cache= 1;
- for (uint i= 0; i < arg_count; i++)
- {
- items[i]->update_used_tables();
- used_tables_cache|= items[i]->used_tables();
- const_item_cache&= items[i]->const_item();
- }
-}
-
-
void Item_row::fix_after_pullout(st_select_lex *new_parent, Item **ref)
{
- used_tables_cache= 0;
- const_item_cache= 1;
+ used_tables_and_const_cache_init();
not_null_tables_cache= 0;
for (uint i= 0; i < arg_count; i++)
{
items[i]->fix_after_pullout(new_parent, &items[i]);
- used_tables_cache|= items[i]->used_tables();
- const_item_cache&= items[i]->const_item();
+ used_tables_and_const_cache_join(items[i]);
not_null_tables_cache|= items[i]->not_null_tables();
}
}
diff --git a/sql/item_row.h b/sql/item_row.h
index aa56068..31efc01 100644
--- a/sql/item_row.h
+++ b/sql/item_row.h
@@ -17,22 +17,20 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
-class Item_row: public Item
+class Item_row: public Item, private Used_tables_and_const_cache
{
Item **items;
- table_map used_tables_cache, not_null_tables_cache;
+ table_map not_null_tables_cache;
uint arg_count;
- bool const_item_cache;
bool with_null;
public:
Item_row(List<Item> &);
Item_row(Item_row *item):
Item(),
+ Used_tables_and_const_cache(item),
items(item->items),
- used_tables_cache(item->used_tables_cache),
not_null_tables_cache(0),
arg_count(item->arg_count),
- const_item_cache(item->const_item_cache),
with_null(0)
{}
@@ -71,7 +69,11 @@ class Item_row: public Item
bool const_item() const { return const_item_cache; };
enum Item_result result_type() const { return ROW_RESULT; }
Item_result cmp_type() const { return ROW_RESULT; }
- void update_used_tables();
+ void update_used_tables()
+ {
+ used_tables_and_const_cache_init();
+ used_tables_and_const_cache_update_and_join(arg_count, items);
+ }
table_map not_null_tables() const { return not_null_tables_cache; }
virtual void print(String *str, enum_query_type query_type);
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 32d6362..496cb11 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -49,8 +49,9 @@ const char *exists_outer_expr_name= "<exists outer expr>";
int check_and_do_in_subquery_rewrites(JOIN *join);
Item_subselect::Item_subselect():
- Item_result_field(), value_assigned(0), own_engine(0), thd(0), old_engine(0),
- used_tables_cache(0), have_to_be_excluded(0), const_item_cache(1),
+ Item_result_field(), Used_tables_and_const_cache(),
+ value_assigned(0), own_engine(0), thd(0), old_engine(0),
+ have_to_be_excluded(0),
inside_first_fix_fields(0), done_first_fix_fields(FALSE),
expr_cache(0), forced_const(FALSE), substitution(0), engine(0), eliminated(FALSE),
changed(0), is_correlated(FALSE)
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index add2e0b..47a143e 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -44,7 +44,8 @@ class Cached_item;
/* base class for subselects */
-class Item_subselect :public Item_result_field
+class Item_subselect :public Item_result_field,
+ protected Used_tables_and_const_cache
{
bool value_assigned; /* value already assigned to subselect */
bool own_engine; /* the engine was not taken from other Item_subselect */
@@ -53,16 +54,12 @@ class Item_subselect :public Item_result_field
THD *thd;
/* old engine if engine was changed */
subselect_engine *old_engine;
- /* cache of used external tables */
- table_map used_tables_cache;
/* allowed number of columns (1 for single value subqueries) */
uint max_columns;
/* where subquery is placed */
enum_parsing_place parsing_place;
/* work with 'substitution' */
bool have_to_be_excluded;
- /* cache of constant state */
- bool const_item_cache;
bool inside_first_fix_fields;
bool done_first_fix_fields;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 20a829e..e8cce56 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -12770,7 +12770,9 @@ static bool check_equality(THD *thd, Item *item, COND_EQUAL *cond_equal,
@param inherited path to all inherited multiple equality items
@return
- pointer to the transformed condition
+ pointer to the transformed condition,
+ whose Used_tables_and_const_cache is up to date,
+ so no additional update_used_tables() is needed on the result.
*/
static COND *build_equal_items_for_cond(THD *thd, COND *cond,
@@ -12784,9 +12786,9 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
if (cond->type() == Item::COND_ITEM)
{
List<Item> eq_list;
- bool and_level= ((Item_cond*) cond)->functype() ==
- Item_func::COND_AND_FUNC;
- List<Item> *args= ((Item_cond*) cond)->argument_list();
+ Item_cond *cond_item= (Item_cond*) cond;
+ bool and_level= cond_item->functype() == Item_func::COND_AND_FUNC;
+ List<Item> *args= cond_item->argument_list();
List_iterator<Item> li(*args);
Item *item;
@@ -12837,8 +12839,10 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
/*
Make replacement of equality predicates for lower levels
of the condition expression.
+ Update used_tables_cache and const_item_cache on the way.
*/
li.rewind();
+ cond_item->used_tables_and_const_cache_init();
while ((item= li++))
{
Item *new_item;
@@ -12853,12 +12857,27 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
*/
li.replace(new_item);
}
+ cond_item->used_tables_and_const_cache_join(new_item);
}
if (and_level)
{
args->append(&eq_list);
args->append((List<Item> *)&cond_equal.current_level);
+ /*
+ QQ: perhaps we could do this:
+
+ cond_item->used_tables_and_const_cache_update_and_join(eq_list);
+ cond_item->used_tables_and_const_cache_update_and_join(
+ *(List<Item> *) &cond_equal.current_level);
+
+ instead of the cond_item->update_used_tables() call below.
+ But initializing 2 iterators will probably be even slower than
+ redundant iterations over the topmost elements in "args",
+ which were already processed in the "while" loop above.
+ */
+ cond_item->update_used_tables();
}
+ return cond_item;
}
else if (cond->type() == Item::FUNC_ITEM ||
cond->real_item()->type() == Item::FIELD_ITEM)
@@ -12890,8 +12909,9 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
item_equal->upper_levels= inherited;
return item_equal;
}
-
- return eq_list.pop();
+ Item *res= eq_list.pop();
+ res->update_used_tables();
+ return res;
}
else
{
@@ -12913,7 +12933,7 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
and_cond->cond_equal.copy(cond_equal);
cond_equal.current_level= and_cond->cond_equal.current_level;
args->append((List<Item> *)&cond_equal.current_level);
-
+ and_cond->update_used_tables();
return and_cond;
}
}
@@ -12928,8 +12948,8 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
&is_subst_valid,
&Item::equal_fields_propagator,
(uchar *) inherited);
- cond->update_used_tables();
}
+ cond->update_used_tables();
return cond;
}
@@ -13016,7 +13036,6 @@ static COND *build_equal_items(JOIN *join, COND *cond,
if (cond)
{
cond= build_equal_items_for_cond(thd, cond, inherited, link_equal_fields);
- cond->update_used_tables();
if (cond->type() == Item::COND_ITEM &&
((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
cond_equal= &((Item_cond_and*) cond)->cond_equal;
diff --git a/sql/sql_udf.h b/sql/sql_udf.h
index 076c544..161bd7a 100644
--- a/sql/sql_udf.h
+++ b/sql/sql_udf.h
@@ -52,7 +52,7 @@ typedef struct st_udf_func
class Item_result_field;
-class udf_handler :public Sql_alloc
+class udf_handler :public Sql_alloc, private Used_tables_and_const_cache
{
protected:
udf_func *u_d;
@@ -65,8 +65,6 @@ class udf_handler :public Sql_alloc
Item **args;
public:
- table_map used_tables_cache;
- bool const_item_cache;
bool not_original;
udf_handler(udf_func *udf_arg) :u_d(udf_arg), buffers(0), error(0),
is_null(0), initialized(0), not_original(0)
@@ -79,6 +77,10 @@ class udf_handler :public Sql_alloc
bool fix_fields(THD *thd, Item_func_or_sum *item,
uint arg_count, Item **args);
void cleanup();
+ const Used_tables_and_const_cache *used_tables_and_const_cache() const
+ {
+ return this;
+ }
double val(my_bool *null_value)
{
is_null= 0;
Follow ups