summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/subselect.result26
-rw-r--r--mysql-test/t/subselect.test26
-rw-r--r--sql/mysql_priv.h3
-rw-r--r--sql/sql_delete.cc2
-rw-r--r--sql/sql_select.cc40
-rw-r--r--sql/sql_select.h15
-rw-r--r--sql/sql_table.cc2
-rw-r--r--sql/sql_update.cc2
8 files changed, 104 insertions, 12 deletions
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result
index 2e3ca9b71f0..8027981db38 100644
--- a/mysql-test/r/subselect.result
+++ b/mysql-test/r/subselect.result
@@ -3393,3 +3393,29 @@ id select_type table type possible_keys key key_len ref rows Extra
4 UNION t12 system NULL NULL NULL NULL 0 const row not found
NULL UNION RESULT <union2,4> ALL NULL NULL NULL NULL NULL
DROP TABLE t1;
+CREATE TABLE t1 (a VARCHAR(250), b INT auto_increment, PRIMARY KEY (b));
+insert into t1 (a) values (FLOOR(rand() * 100));
+insert into t1 (a) select FLOOR(rand() * 100) from t1;
+insert into t1 (a) select FLOOR(rand() * 100) from t1;
+insert into t1 (a) select FLOOR(rand() * 100) from t1;
+insert into t1 (a) select FLOOR(rand() * 100) from t1;
+insert into t1 (a) select FLOOR(rand() * 100) from t1;
+insert into t1 (a) select FLOOR(rand() * 100) from t1;
+insert into t1 (a) select FLOOR(rand() * 100) from t1;
+insert into t1 (a) select FLOOR(rand() * 100) from t1;
+insert into t1 (a) select FLOOR(rand() * 100) from t1;
+insert into t1 (a) select FLOOR(rand() * 100) from t1;
+insert into t1 (a) select FLOOR(rand() * 100) from t1;
+insert into t1 (a) select FLOOR(rand() * 100) from t1;
+insert into t1 (a) select FLOOR(rand() * 100) from t1;
+SELECT a,
+(SELECT REPEAT(' ',250) FROM t1 i1
+WHERE i1.b=t1.a ORDER BY RAND() LIMIT 1) AS a
+FROM t1 ORDER BY a LIMIT 5;
+a a
+0 NULL
+0 NULL
+0 NULL
+0 NULL
+0 NULL
+DROP TABLE t1;
diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test
index 740cb08c5bd..eefec96203a 100644
--- a/mysql-test/t/subselect.test
+++ b/mysql-test/t/subselect.test
@@ -2306,3 +2306,29 @@ explain select * from t1 where not exists
((select t11.i from t1 t11) union (select t12.i from t1 t12));
DROP TABLE t1;
+
+#
+# Bug#21798: memory leak during query execution with subquery in column
+# list using a function
+#
+CREATE TABLE t1 (a VARCHAR(250), b INT auto_increment, PRIMARY KEY (b));
+insert into t1 (a) values (FLOOR(rand() * 100));
+insert into t1 (a) select FLOOR(rand() * 100) from t1;
+insert into t1 (a) select FLOOR(rand() * 100) from t1;
+insert into t1 (a) select FLOOR(rand() * 100) from t1;
+insert into t1 (a) select FLOOR(rand() * 100) from t1;
+insert into t1 (a) select FLOOR(rand() * 100) from t1;
+insert into t1 (a) select FLOOR(rand() * 100) from t1;
+insert into t1 (a) select FLOOR(rand() * 100) from t1;
+insert into t1 (a) select FLOOR(rand() * 100) from t1;
+insert into t1 (a) select FLOOR(rand() * 100) from t1;
+insert into t1 (a) select FLOOR(rand() * 100) from t1;
+insert into t1 (a) select FLOOR(rand() * 100) from t1;
+insert into t1 (a) select FLOOR(rand() * 100) from t1;
+insert into t1 (a) select FLOOR(rand() * 100) from t1;
+
+SELECT a,
+ (SELECT REPEAT(' ',250) FROM t1 i1
+ WHERE i1.b=t1.a ORDER BY RAND() LIMIT 1) AS a
+FROM t1 ORDER BY a LIMIT 5;
+DROP TABLE t1;
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 620992b8cc7..ab32ef1badf 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -708,7 +708,8 @@ bool mysql_xa_recover(THD *thd);
bool check_simple_select();
-SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length);
+SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length,
+ SORT_FIELD *sortorder);
int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
List<Item> &fields, List <Item> &all_fields, ORDER *order);
int setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index e420022b8a1..33b46080696 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -167,7 +167,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
MYF(MY_FAE | MY_ZEROFILL));
if (!(sortorder= make_unireg_sortorder((ORDER*) order->first,
- &length)) ||
+ &length, NULL)) ||
(table->sort.found_records = filesort(thd, table, sortorder, length,
select, HA_POS_ERROR,
&examined_rows))
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 4d2b3cac254..8f169a9d390 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1574,6 +1574,7 @@ JOIN::exec()
{
DBUG_VOID_RETURN;
}
+ sortorder= curr_join->sortorder;
}
thd->proc_info="Copying to group table";
@@ -1783,6 +1784,7 @@ JOIN::exec()
(select_options & OPTION_FOUND_ROWS ?
HA_POS_ERROR : unit->select_limit_cnt)))
DBUG_VOID_RETURN;
+ sortorder= curr_join->sortorder;
}
}
/* XXX: When can we have here thd->net.report_error not zero? */
@@ -4949,9 +4951,28 @@ make_simple_join(JOIN *join,TABLE *tmp_table)
JOIN_TAB *join_tab;
DBUG_ENTER("make_simple_join");
- if (!(tableptr=(TABLE**) join->thd->alloc(sizeof(TABLE*))) ||
- !(join_tab=(JOIN_TAB*) join->thd->alloc(sizeof(JOIN_TAB))))
- DBUG_RETURN(TRUE);
+ /*
+ Reuse TABLE * and JOIN_TAB if already allocated by a previous call
+ to this function through JOIN::exec (may happen for sub-queries).
+ */
+ if (!join->table_cache)
+ {
+ if (!(join->table_cache= (TABLE**) join->thd->alloc(sizeof(TABLE*))))
+ DBUG_RETURN(TRUE); /* purecov: inspected */
+ if (join->tmp_join)
+ join->tmp_join->table_cache= join->table_cache;
+ }
+ if (!join->join_tab_cache)
+ {
+ if (!(join->join_tab_cache=
+ (JOIN_TAB*) join->thd->alloc(sizeof(JOIN_TAB))))
+ DBUG_RETURN(TRUE); /* purecov: inspected */
+ if (join->tmp_join)
+ join->tmp_join->join_tab_cache= join->join_tab_cache;
+ }
+ tableptr= join->table_cache;
+ join_tab= join->join_tab_cache;
+
join->join_tab=join_tab;
join->table=tableptr; tableptr[0]=tmp_table;
join->tables=1;
@@ -11971,7 +11992,6 @@ static int
create_sort_index(THD *thd, JOIN *join, ORDER *order,
ha_rows filesort_limit, ha_rows select_limit)
{
- SORT_FIELD *sortorder;
uint length;
ha_rows examined_rows;
TABLE *table;
@@ -11987,7 +12007,8 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
if (test_if_skip_sort_order(tab,order,select_limit,0))
DBUG_RETURN(0);
- if (!(sortorder=make_unireg_sortorder(order,&length)))
+ if (!(join->sortorder=
+ make_unireg_sortorder(order,&length,join->sortorder)))
goto err; /* purecov: inspected */
/* It's not fatal if the following alloc fails */
table->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
@@ -12034,7 +12055,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
if (table->s->tmp_table)
table->file->info(HA_STATUS_VARIABLE); // Get record count
- table->sort.found_records=filesort(thd, table,sortorder, length,
+ table->sort.found_records=filesort(thd, table,join->sortorder, length,
select, filesort_limit, &examined_rows);
tab->records= table->sort.found_records; // For SQL_CALC_ROWS
if (select)
@@ -12381,7 +12402,8 @@ err:
}
-SORT_FIELD *make_unireg_sortorder(ORDER *order, uint *length)
+SORT_FIELD *make_unireg_sortorder(ORDER *order, uint *length,
+ SORT_FIELD *sortorder)
{
uint count;
SORT_FIELD *sort,*pos;
@@ -12390,7 +12412,9 @@ SORT_FIELD *make_unireg_sortorder(ORDER *order, uint *length)
count=0;
for (ORDER *tmp = order; tmp; tmp=tmp->next)
count++;
- pos=sort=(SORT_FIELD*) sql_alloc(sizeof(SORT_FIELD)*(count+1));
+ if (!sortorder)
+ sortorder= (SORT_FIELD*) sql_alloc(sizeof(SORT_FIELD)*(count+1));
+ pos=sort=sortorder;
if (!pos)
return 0;
diff --git a/sql/sql_select.h b/sql/sql_select.h
index d5a1bf82bc8..e1ae8677a6e 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -282,6 +282,18 @@ public:
bool union_part; // this subselect is part of union
bool optimized; // flag to avoid double optimization in EXPLAIN
+ /*
+ storage for caching buffers allocated during query execution.
+ These buffers allocations need to be cached as the thread memory pool is
+ cleared only at the end of the execution of the whole query and not caching
+ allocations that occur in repetition at execution time will result in
+ excessive memory usage.
+ */
+ SORT_FIELD *sortorder; // make_unireg_sortorder()
+ TABLE **table_cache; // make_simple_join()
+ JOIN_TAB *join_tab_cache; // make_simple_join()
+ /* end of allocation caching storage */
+
JOIN(THD *thd_arg, List<Item> &fields_arg, ulonglong select_options_arg,
select_result *result_arg)
:fields_list(fields_arg)
@@ -307,6 +319,9 @@ public:
examined_rows= 0;
exec_tmp_table1= 0;
exec_tmp_table2= 0;
+ sortorder= 0;
+ table_cache= 0;
+ join_tab_cache= 0;
thd= thd_arg;
sum_funcs= sum_funcs2= 0;
procedure= 0;
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index e065a32c2e8..08c7e03693e 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -4044,7 +4044,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
if (thd->lex->select_lex.setup_ref_array(thd, order_num) ||
setup_order(thd, thd->lex->select_lex.ref_pointer_array,
&tables, fields, all_fields, order) ||
- !(sortorder=make_unireg_sortorder(order, &length)) ||
+ !(sortorder=make_unireg_sortorder(order, &length, NULL)) ||
(from->sort.found_records = filesort(thd, from, sortorder, length,
(SQL_SELECT *) 0, HA_POS_ERROR,
&examined_rows)) ==
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 84b22c56cf9..4a6249410a7 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -311,7 +311,7 @@ int mysql_update(THD *thd,
table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
MYF(MY_FAE | MY_ZEROFILL));
- if (!(sortorder=make_unireg_sortorder(order, &length)) ||
+ if (!(sortorder=make_unireg_sortorder(order, &length, NULL)) ||
(table->sort.found_records = filesort(thd, table, sortorder, length,
select, limit,
&examined_rows))