#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#36027 | Vladislav Vaintroub | 11 Aug 2009 |