#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 memoryon the server, hence the leak.
The fix is not using unique names for stored procedure, instead we give all output
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 might collide with user
variables names.
modified:
MySql.Data/Provider/Source/Statement.cs
MySql.Data/Provider/Source/StoredProcedure.cs
MySql.Data/Provider/Source/command.cs
=== 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 00:59:23 +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 00:59:23 +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 00:59:23 +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-20090811005923-n8mxfxq02qep7v70.bundle
| Thread |
|---|
| • bzr commit into connector-net-6.0 branch (vvaintroub:741) Bug#36027 | Vladislav Vaintroub | 11 Aug |