summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOleksandr Byelkin <sanja@mariadb.com>2023-04-17 15:06:52 +0200
committerOleksandr Byelkin <sanja@mariadb.com>2023-04-26 16:15:29 +0200
commit6171119bc145a91d94a89458142e087924e4a9c6 (patch)
treef3072ba12e5b817ae5d614f738b01a6eaf43c6d5
parent45d4f6b97b4811b1b7783dcd19526be1dbb196dc (diff)
downloadmariadb-git-6171119bc145a91d94a89458142e087924e4a9c6.tar.gz
MDEV-30889: 3 - Item_in_optimizer leak
Keep Item_in_optimizer cache always (but only once) in statement memory.
-rw-r--r--sql/item.cc10
-rw-r--r--sql/item.h11
-rw-r--r--sql/item_cmpfunc.cc26
-rw-r--r--sql/item_cmpfunc.h6
-rw-r--r--sql/item_subselect.cc4
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 "<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 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;
/*