From 6171119bc145a91d94a89458142e087924e4a9c6 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Mon, 17 Apr 2023 15:06:52 +0200 Subject: MDEV-30889: 3 - Item_in_optimizer leak Keep Item_in_optimizer cache always (but only once) in statement memory. --- sql/item.cc | 10 ++++++---- sql/item.h | 11 ++++++++--- sql/item_cmpfunc.cc | 26 +++++++++++++++----------- sql/item_cmpfunc.h | 6 ++---- sql/item_subselect.cc | 4 ++-- 5 files changed, 33 insertions(+), 24 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index be7780cb015..685fdc2b69f 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -10430,7 +10430,8 @@ int Item_cache_str::save_in_field(Field *field, bool no_conversions) bool Item_cache_row::allocate(THD *thd, uint num) { item_count= num; - return (!(values= + return (!values && + !(values= (Item_cache **) thd->calloc(sizeof(Item_cache *)*item_count))); } @@ -10467,10 +10468,11 @@ bool Item_cache_row::setup(THD *thd, Item *item) for (uint i= 0; i < item_count; i++) { Item *el= item->element_index(i); - Item_cache *tmp; - if (!(tmp= values[i]= el->get_cache(thd))) + + if ((!values[i]) && !(values[i]= el->get_cache(thd))) return 1; - tmp->setup(thd, el); + + values[i]->setup(thd, el); } return 0; } diff --git a/sql/item.h b/sql/item.h index 1e0caaa7c83..d04d77da666 100644 --- a/sql/item.h +++ b/sql/item.h @@ -6901,6 +6901,9 @@ public: } virtual void keep_array() {} +#ifndef DBUG_OFF + bool is_array_kept() { return TRUE; } +#endif virtual void print(String *str, enum_query_type query_type); bool eq_def(const Field *field) { @@ -7388,13 +7391,15 @@ public: bool null_inside(); void bring_value(); void keep_array() { save_array= 1; } +#ifndef DBUG_OFF + bool is_array_kept() { return save_array; } +#endif + void cleanup() { DBUG_ENTER("Item_cache_row::cleanup"); Item_cache::cleanup(); - if (save_array) - bzero(values, item_count*sizeof(Item**)); - else + if (!save_array) values= 0; DBUG_VOID_RETURN; } diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 6fbbb79c263..fa96d95adb1 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1298,9 +1298,22 @@ bool Item_in_optimizer::fix_left(THD *thd) ref0= &(((Item_in_subselect *)args[1])->left_expr); args[0]= ((Item_in_subselect *)args[1])->left_expr; } - if ((*ref0)->fix_fields_if_needed(thd, ref0) || - (!cache && !(cache= (*ref0)->get_cache(thd)))) + if ((*ref0)->fix_fields_if_needed(thd, ref0)) DBUG_RETURN(1); + if (!cache) + { + Query_arena *arena, backup; + arena= thd->activate_stmt_arena_if_needed(&backup); + + bool rc= !(cache= (*ref0)->get_cache(thd)); + + if (arena) + thd->restore_active_arena(arena, &backup); + + if (rc) + DBUG_RETURN(1); + cache->keep_array(); + } /* During fix_field() expression could be substituted. So we copy changes before use @@ -1663,19 +1676,10 @@ longlong Item_in_optimizer::val_int() } -void Item_in_optimizer::keep_top_level_cache() -{ - cache->keep_array(); - save_cache= 1; -} - - void Item_in_optimizer::cleanup() { DBUG_ENTER("Item_in_optimizer::cleanup"); Item_bool_func::cleanup(); - if (!save_cache) - cache= 0; expr_cache= 0; DBUG_VOID_RETURN; } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 24f2b35576d..6706c2edf40 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -353,8 +353,7 @@ class Item_in_optimizer: public Item_bool_func protected: Item_cache *cache; Item *expr_cache; - bool save_cache; - /* + /* Stores the value of "NULL IN (SELECT ...)" for uncorrelated subqueries: UNKNOWN - "NULL in (SELECT ...)" has not yet been evaluated FALSE - result is FALSE @@ -364,7 +363,7 @@ protected: public: Item_in_optimizer(THD *thd, Item *a, Item *b): Item_bool_func(thd, a, b), cache(0), expr_cache(0), - save_cache(0), result_for_null_param(UNKNOWN) + result_for_null_param(UNKNOWN) { m_with_subquery= true; } bool fix_fields(THD *, Item **); bool fix_left(THD *thd); @@ -375,7 +374,6 @@ public: enum Functype functype() const { return IN_OPTIMIZER_FUNC; } const char *func_name() const { return ""; } Item_cache **get_cache() { return &cache; } - void keep_top_level_cache(); Item *transform(THD *thd, Item_transformer transformer, uchar *arg); virtual Item *expr_cache_insert_transformer(THD *thd, uchar *unused); bool is_expensive_processor(void *arg); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index eb7988dffe7..f88e1e7e101 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1994,7 +1994,7 @@ Item_in_subselect::single_value_transformer(JOIN *join) thd->lex->current_select= current; /* We will refer to upper level cache array => we have to save it for SP */ - optimizer->keep_top_level_cache(); + DBUG_ASSERT(optimizer->get_cache()[0]->is_array_kept()); /* As far as Item_in_optimizer does not substitute itself on fix_fields @@ -2391,7 +2391,7 @@ Item_in_subselect::row_value_transformer(JOIN *join) } // we will refer to upper level cache array => we have to save it in PS - optimizer->keep_top_level_cache(); + DBUG_ASSERT(optimizer->get_cache()[0]->is_array_kept()); thd->lex->current_select= current; /* -- cgit v1.2.1