List:Commits« Previous MessageNext Message »
From:Vladislav Vaintroub Date:August 11 2009 3:14am
Subject:bzr commit into connector-net-6.0 branch (vvaintroub:741) Bug#36027
View as plain text  
#At file:///H:/connector_net/6.0/ based on
revid:vvaintroub@stripped

  741 Vladislav Vaintroub	2009-08-11
      Bug #36027 Memory leak when using output parameter in stored procedure
      
      The reason for the memory leak was that we Connector/Net created a 
      session variable with unique name for each stored procedure call. 
      Each session variable takes some memory on the server, hence the leak.
      
      The fix is not using unique names for stored procedure, instead we give 
      all output or inout variables a common prefix.
      
       It would be nice to get rid of the prefix too, however
      1 ) there is a complicated logic inside resolve/bind that makes it not 
      possible at the moment.
      2) stored procedure parameter names could in theory  collide 
      with user variables names.

    modified:
      CHANGES
      MySql.Data/Provider/Source/Statement.cs
      MySql.Data/Provider/Source/StoredProcedure.cs
      MySql.Data/Provider/Source/command.cs
=== modified file 'CHANGES'
--- a/CHANGES	2009-08-05 00:15:23 +0000
+++ b/CHANGES	2009-08-11 01:14:22 +0000
@@ -1,4 +1,6 @@
 Version 6.0.5
+- fixed memory leak in server when calling stored procedure with output parameter many
times 
+  in the same session (bug#36027)
 - workaround for .NET compact framework problems when writing behind the end of
MemoryStream 
 (contributed by Nicholas Piasecki) (bug#43736)
 - added keepalive connection option that can be used to detect network outages faster 

=== modified file 'MySql.Data/Provider/Source/Statement.cs'
--- a/MySql.Data/Provider/Source/Statement.cs	2009-04-21 18:02:13 +0000
+++ b/MySql.Data/Provider/Source/Statement.cs	2009-08-11 01:14:22 +0000
@@ -201,7 +201,7 @@ namespace MySql.Data.MySqlClient
         {
             if (Connection.Settings.AllowUserVariables)
                 return true;
-            if (command.parameterHash != null && parameterName.StartsWith("@" +
command.parameterHash))
+            if (parameterName.StartsWith("@" +StoredProcedure.ParameterPrefix))
                 return true;
             if (parameterName.Length > 1 &&
                 (parameterName[1] == '`' || parameterName[1] == '\''))

=== modified file 'MySql.Data/Provider/Source/StoredProcedure.cs'
--- a/MySql.Data/Provider/Source/StoredProcedure.cs	2009-07-30 01:47:48 +0000
+++ b/MySql.Data/Provider/Source/StoredProcedure.cs	2009-08-11 01:14:22 +0000
@@ -36,12 +36,12 @@ namespace MySql.Data.MySqlClient
         private DataTable parametersTable;
         private string resolvedCommandText;
 
+        // Prefix used for to generate inout or output parameters names
+        internal const string ParameterPrefix = "_cnet_param_";
+
         public StoredProcedure(MySqlCommand cmd, string text)
             : base(cmd, text)
         {
-            // set our parameter hash to something very unique
-            uint code = (uint) DateTime.Now.GetHashCode();
-            cmd.parameterHash = code.ToString();
         }
 
         private string GetReturnParameter()
@@ -51,7 +51,7 @@ namespace MySql.Data.MySqlClient
                     if (p.Direction == ParameterDirection.ReturnValue)
                     {
                         string pName = p.ParameterName.Substring(1);
-                        return command.parameterHash + pName;
+                        return ParameterPrefix + pName;
                     }
             return null;
         }
@@ -136,7 +136,6 @@ namespace MySql.Data.MySqlClient
             // first retrieve the procedure definition from our
             // procedure cache
             string spName = commandText;
-            string parameterHash = command.parameterHash;
             if (spName.IndexOf(".") == -1 &&
!String.IsNullOrEmpty(Connection.Database))
                 spName = Connection.Database + "." + spName;
             spName = FixProcedureName(spName);
@@ -174,7 +173,7 @@ namespace MySql.Data.MySqlClient
                 string basePName = pName;
                 if (pName.StartsWith("@") || pName.StartsWith("?"))
                     basePName = pName.Substring(1);
-                string vName = string.Format("@{0}{1}", parameterHash, basePName);
+                string vName = string.Format("@{0}{1}", ParameterPrefix, basePName);
 
                 // if our parameter doesn't have a leading marker then we need to give it
one
                 pName = p.ParameterName;
@@ -207,7 +206,7 @@ namespace MySql.Data.MySqlClient
             else
             {
                 if (retParm == null)
-                    retParm = parameterHash + "dummy";
+                    retParm = ParameterPrefix + "dummy";
                 else
                     outSelect = String.Format("@{0}", retParm);
                 sqlCmd = String.Format("SET @{0}={1}({2})", retParm, spName, sqlCmd);
@@ -227,11 +226,7 @@ namespace MySql.Data.MySqlClient
 
             MySqlCommand cmd = new MySqlCommand("SELECT " + outSelect, Connection);
 
-            // set the parameter hash for this new command to our current parameter hash
-            // so the inout and out parameters won't cause a problem
-            string parameterHash = command.parameterHash;
-            cmd.parameterHash = parameterHash;
-
+            // Read output parameters
             using (MySqlDataReader reader = cmd.ExecuteReader())
             {
                 // since MySQL likes to return user variables as strings
@@ -241,7 +236,7 @@ namespace MySql.Data.MySqlClient
                 for (int i = 0; i < reader.FieldCount; i++)
                 {
                     string fieldName = reader.GetName(i);
-                    fieldName = fieldName.Remove(0, parameterHash.Length + 1);
+                    fieldName = fieldName.Remove(0, ParameterPrefix.Length + 1);
                     MySqlParameter parameter = Parameters.GetParameterFlexible(fieldName,
true);
                     reader.values[i] = MySqlField.GetIMySqlValue(parameter.MySqlDbType);
                 }
@@ -251,7 +246,7 @@ namespace MySql.Data.MySqlClient
                     for (int i = 0; i < reader.FieldCount; i++)
                     {
                         string fieldName = reader.GetName(i);
-                        fieldName = fieldName.Remove(0, parameterHash.Length + 1);
+                        fieldName = fieldName.Remove(0, ParameterPrefix.Length + 1);
                         MySqlParameter parameter =
Parameters.GetParameterFlexible(fieldName, true);
                         parameter.Value = reader.GetValue(i);
                     }

=== modified file 'MySql.Data/Provider/Source/command.cs'
--- a/MySql.Data/Provider/Source/command.cs	2009-07-31 22:36:40 +0000
+++ b/MySql.Data/Provider/Source/command.cs	2009-08-11 01:14:22 +0000
@@ -58,7 +58,6 @@ namespace MySql.Data.MySqlClient
         private bool resetSqlSelect;
         List<MySqlCommand> batch;
         private string batchableCommandText;
-        internal string parameterHash;
         internal bool EFCrap;
 
 		/// <include file='docs/mysqlcommand.xml' path='docs/ctor1/*'/>


Attachment: [text/bzr-bundle] bzr/vvaintroub@mysql.com-20090811011422-75eyp1rdkzh5dp9f.bundle
Thread
bzr commit into connector-net-6.0 branch (vvaintroub:741) Bug#36027Vladislav Vaintroub11 Aug 2009