diff options
author | Oleksandr Byelkin <sanja@mariadb.com> | 2023-04-17 15:06:52 +0200 |
---|---|---|
committer | Oleksandr Byelkin <sanja@mariadb.com> | 2023-04-17 15:55:00 +0200 |
commit | 74847ddcd56f83e2e41d4c231d02d80e42d16667 (patch) | |
tree | 769c91ab3768208637cfb5294a5c835200e2a0ad | |
parent | 5007b8cbdf5d3100c279297592e3aabaedba09ec (diff) | |
download | mariadb-git-bb-10.3-MDEV-14959.tar.gz |
MDEV-14959: 3 - Item_in_optimizer leakbb-10.3-MDEV-14959
Keep Item_in_optimizer cache always (but only once) in statement memory.
-rw-r--r-- | sql/item.cc | 10 | ||||
-rw-r--r-- | sql/item.h | 11 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 26 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 6 | ||||
-rw-r--r-- | sql/item_subselect.cc | 4 |
5 files changed, 33 insertions, 24 deletions
diff --git a/sql/item.cc b/sql/item.cc index 9ecbefaafb9..54bdce714a7 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -10573,7 +10573,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))); } @@ -10610,10 +10611,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 5ae3d7a3435..5a6c2723991 100644 --- a/sql/item.h +++ b/sql/item.h @@ -6286,6 +6286,9 @@ public: { return Type_handler_hybrid_field_type::type_handler(); } 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) { @@ -6656,13 +6659,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 fe6b8feb4de..27b056b1d5d 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1276,9 +1276,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 @@ -1641,19 +1654,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 671fa52635d..bab9f7fe8c8 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -346,8 +346,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 @@ -357,7 +356,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); @@ -368,7 +367,6 @@ public: enum Functype functype() const { return IN_OPTIMIZER_FUNC; } const char *func_name() const { return "<in_optimizer>"; } 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 6dfe041dfd6..8b87092ec88 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1963,7 +1963,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 @@ -2360,7 +2360,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; /* |