diff options
-rw-r--r-- | mysql-test/r/subselect.result | 26 | ||||
-rw-r--r-- | mysql-test/t/subselect.test | 26 | ||||
-rw-r--r-- | sql/mysql_priv.h | 3 | ||||
-rw-r--r-- | sql/sql_delete.cc | 2 | ||||
-rw-r--r-- | sql/sql_select.cc | 40 | ||||
-rw-r--r-- | sql/sql_select.h | 15 | ||||
-rw-r--r-- | sql/sql_table.cc | 2 | ||||
-rw-r--r-- | sql/sql_update.cc | 2 |
8 files changed, 104 insertions, 12 deletions
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index abe840e96d9..57d6199675d 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -3458,6 +3458,32 @@ 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; CREATE TABLE t1 (a INT, b INT); CREATE TABLE t2 (a INT); INSERT INTO t2 values (1); diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 7811301a9bc..6d5082c360b 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -2371,6 +2371,32 @@ explain select * from t1 where not exists 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; + +# # Bug #21540: Subqueries with no from and aggregate functions return # wrong results CREATE TABLE t1 (a INT, b INT); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 1cee013852e..ea3b3a9bd83 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -714,7 +714,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 c95fb5d5973..3e3378542aa 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 3935029190b..2e959560f2f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1575,6 +1575,7 @@ JOIN::exec() { DBUG_VOID_RETURN; } + sortorder= curr_join->sortorder; } thd->proc_info="Copying to group table"; @@ -1784,6 +1785,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? */ @@ -4950,9 +4952,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; @@ -11982,7 +12003,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; @@ -12004,7 +12024,8 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, !(join->select_options & SELECT_BIG_RESULT)) && 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 */ table->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE), @@ -12051,7 +12072,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) @@ -12398,7 +12419,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; @@ -12407,7 +12429,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 9ce5084c34f..8864cf3c8bc 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4095,7 +4095,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 a5a767b6ebc..f81ee3abdca 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)) |