From ff5d72021e26d1f3cec834c78b183918c4e95baf Mon Sep 17 00:00:00 2001
From: "gshchepa/uchum@gleb.loc" <>
Date: Sat, 28 Jul 2007 23:10:38 +0500
Subject: [PATCH] Fixed bug #29834. Using view columns by their names during an
 execution of a prepared SELECT statement or a SELECT statement inside a SP
 caused a memory leak.

---
 mysql-test/r/sp.result | 71 ++++++++++++++++++++++++++++++++++++++++
 mysql-test/t/sp.test   | 74 ++++++++++++++++++++++++++++++++++++++++++
 sql/sql_base.cc        |  6 ++--
 3 files changed, 148 insertions(+), 3 deletions(-)

diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index b411c65fae..313fdca7f8 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -1,5 +1,9 @@
 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;
 create table t1 (
 id   char(16) not null default '',
 data int not null
@@ -6176,4 +6180,71 @@ 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;
 End of 5.0 tests
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index 2f82482bdf..088ce9b72f 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -23,6 +23,10 @@ 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;
 --enable_warnings
 create table t1 (
 	id   char(16) not null default '',
@@ -7134,5 +7138,75 @@ 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;
 
 --echo End of 5.0 tests
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index ed00671414..deb46f0d93 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -3435,7 +3435,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;  
+  Query_arena *arena= 0, backup;  
   
   DBUG_ASSERT(table_list->schema_table_reformed ||
               (ref != 0 && table_list->view != 0));
@@ -3444,14 +3444,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)
-- 
2.30.9