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-17 15:55:00 +0200
commit74847ddcd56f83e2e41d4c231d02d80e42d16667 (patch)
tree769c91ab3768208637cfb5294a5c835200e2a0ad
parent5007b8cbdf5d3100c279297592e3aabaedba09ec (diff)
downloadmariadb-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.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 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;
/*