diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 07661f9ae5430b14fcccc90a9b9afc142ca77e68..a17c3e4492e613001a3c034314a685811720d7a7 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -1,5 +1,8 @@ use test; drop table if exists t1,t2,t3,t4; +drop view if exists v1; +drop procedure if exists p1; +drop procedure if exists p2; drop function if exists f1; drop function if exists f2; create table t1 ( @@ -6283,6 +6286,73 @@ v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VI DROP VIEW v1; DROP FUNCTION metered; DROP TABLE t1; +SET @p1_p2_cnt= 2; +CREATE TABLE t1 (c1 INT); +CREATE VIEW v1 AS SELECT * FROM t1; +PREPARE s1 FROM 'SELECT c1 FROM v1'; +EXECUTE s1; +c1 +EXECUTE s1; +c1 +CREATE PROCEDURE p1(IN loops BIGINT(19) UNSIGNED) +BEGIN +WHILE loops > 0 DO +SELECT c1 FROM v1; +SET loops = loops - 1; +END WHILE; +END| +CREATE PROCEDURE p2(IN loops BIGINT(19) UNSIGNED) +BEGIN +WHILE loops > 0 DO +SELECT c1 FROM v1; +CALL p1(@p1_p2_cnt); +SET loops = loops - 1; +END WHILE; +END| +CREATE FUNCTION f1(loops INT UNSIGNED) +RETURNS INT +BEGIN +DECLARE tmp INT; +WHILE loops > 0 DO +SELECT c1 INTO tmp FROM v1; +SET loops = loops - 1; +END WHILE; +RETURN loops; +END| +CALL p1(2); +c1 +c1 +CALL p2(2); +c1 +c1 +c1 +c1 +c1 +c1 +SELECT f1(2); +f1(2) +0 +Warnings: +Warning 1329 No data - zero rows fetched, selected, or processed +Warning 1329 No data - zero rows fetched, selected, or processed +PREPARE s1 FROM 'SELECT f1(2)'; +EXECUTE s1; +f1(2) +0 +Warnings: +Warning 1329 No data - zero rows fetched, selected, or processed +Warning 1329 No data - zero rows fetched, selected, or processed +EXECUTE s1; +f1(2) +0 +Warnings: +Warning 1329 No data - zero rows fetched, selected, or processed +Warning 1329 No data - zero rows fetched, selected, or processed +DROP PROCEDURE p1; +DROP PROCEDURE p2; +DROP FUNCTION f1; +DROP VIEW v1; +DROP TABLE t1; drop database if exists mysqltest_db1; create database mysqltest_db1; create procedure mysqltest_db1.sp_bug28551() begin end; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index dfda1b7a6ab895e9635a8e4f6be52ca61a93e570..f834a57c5b129afc1cef10c000d2f02c6ed298f2 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -24,6 +24,9 @@ use test; # --disable_warnings drop table if exists t1,t2,t3,t4; +drop view if exists v1; +drop procedure if exists p1; +drop procedure if exists p2; drop function if exists f1; drop function if exists f2; --enable_warnings @@ -7252,6 +7255,77 @@ DROP VIEW v1; DROP FUNCTION metered; DROP TABLE t1; +# +# Bug#29834: Accessing a view column by name in SP/PS causes a memory leak. +# +# This is leak test. Run with large number assigned to $execute_cnt, +# $p1_cnt, $p2_cnt, @p1_p2_cnt, $f1_normal_cnt or $f1_prep_cnt variables. +# + +let $execute_cnt= 2; +let $p1_cnt= 2; +let $p2_cnt= 2; +SET @p1_p2_cnt= 2; +let $f1_normal_cnt= 2; +let $f1_prep_cnt= 2; + +CREATE TABLE t1 (c1 INT); +CREATE VIEW v1 AS SELECT * FROM t1; + +PREPARE s1 FROM 'SELECT c1 FROM v1'; +while ($execute_cnt) +{ + EXECUTE s1; + dec $execute_cnt; +} + +DELIMITER |; + +CREATE PROCEDURE p1(IN loops BIGINT(19) UNSIGNED) +BEGIN + WHILE loops > 0 DO + SELECT c1 FROM v1; + SET loops = loops - 1; + END WHILE; +END| + +CREATE PROCEDURE p2(IN loops BIGINT(19) UNSIGNED) +BEGIN + WHILE loops > 0 DO + SELECT c1 FROM v1; + CALL p1(@p1_p2_cnt); + SET loops = loops - 1; + END WHILE; +END| + +CREATE FUNCTION f1(loops INT UNSIGNED) + RETURNS INT +BEGIN + DECLARE tmp INT; + WHILE loops > 0 DO + SELECT c1 INTO tmp FROM v1; + SET loops = loops - 1; + END WHILE; + RETURN loops; +END| + +DELIMITER ;| + +eval CALL p1($p1_cnt); +eval CALL p2($p2_cnt); + +eval SELECT f1($f1_normal_cnt); + +eval PREPARE s1 FROM 'SELECT f1($f1_prep_cnt)'; +EXECUTE s1; +EXECUTE s1; + +DROP PROCEDURE p1; +DROP PROCEDURE p2; +DROP FUNCTION f1; +DROP VIEW v1; +DROP TABLE t1; + # # Bug#28551 "The warning 'No database selected' is reported when calling # stored procedures" diff --git a/sql/sql_base.cc b/sql/sql_base.cc index f131901027053d8bf1aef22b6786efede2ac72d0..965106b804f13177011b8c5e2fd67ddb95d75029 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4498,8 +4498,7 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list, table_list->alias, name, item_name, (ulong) ref)); Field_iterator_view field_it; field_it.set(table_list); - Query_arena *arena, backup; - LINT_INIT(arena); + Query_arena *arena= 0, backup; DBUG_ASSERT(table_list->schema_table_reformed || (ref != 0 && table_list->view != 0)); @@ -4508,14 +4507,14 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list, if (!my_strcasecmp(system_charset_info, field_it.name(), name)) { // in PS use own arena or data will be freed after prepare - if (register_tree_change) + if (register_tree_change && thd->stmt_arena->is_stmt_prepare_or_first_sp_execute()) arena= thd->activate_stmt_arena_if_needed(&backup); /* create_item() may, or may not create a new Item, depending on the column reference. See create_view_field() for details. */ Item *item= field_it.create_item(thd); - if (register_tree_change && arena) + if (arena) thd->restore_active_arena(arena, &backup); if (!item)