Bug #26904 MySqlParameterCollection fails to add MySqlParameter that previously removed
Submitted: 7 Mar 2007 7:03 Modified: 7 Mar 2007 15:37
Reporter: [ name withheld ] Email Updates:
Status: Closed Impact on me:
None 
Category:Connector / NET Severity:S3 (Non-critical)
Version:5.0.3 OS:Windows (Windows XP)
Assigned to: CPU Architecture:Any
Tags: add, ArgumentException, exception, hash, MySqlCommand, MySqlParameter, MySqlParameterCollection, Parameter, remove

[7 Mar 2007 7:03] [ name withheld ]
Description:
When you add a MySqlParameter to a MySqlParameterCollection (of a MySqlCommand) than remove it than re-add it, MySqlParameterCollection throws an ArgumentException. This situation occurs in a DataBinded Grid depending on use. ArgumentException is like this:

System.ArgumentException was unhandled
  Message="Item has already been added. Key in dictionary: '?p1'  Key being added: '?p1'"
  Source="mscorlib"
  StackTrace:
       at System.Collections.Hashtable.Insert(Object key, Object nvalue, Boolean add)
       at System.Collections.Hashtable.Add(Object key, Object value)
       at MySql.Data.MySqlClient.MySqlParameterCollection.Add(MySqlParameter value)
       at WindowsApplication8.Program.Main() in C:\Documents and Settings\Administrator\Belgelerim\Visual Studio 2005\Projects\WindowsApplication8\WindowsApplication8\Program.cs:line 26
       at System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()

How to repeat:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using MySql.Data.MySqlClient;
using System.Data;

namespace WindowsApplication8
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            MySqlCommand cmd = new 
            MySqlCommand("Insert into sometable(s1, s2) values(?p1, ?p2)");

            MySqlParameter param1 = cmd.CreateParameter();
            param1.ParameterName = "?p1";
            param1.DbType = DbType.String;
            param1.Value = "Ali Gel";

            cmd.Parameters.Add(param1);
            cmd.Parameters.RemoveAt(0);
            cmd.Parameters.Add(param1);
        }
    }
}

Suggested fix:
I found the cause and the fix. This exception occurs because when a parameter added to the parametercollection, the parameter also added to the hash and cihash member HashTables but doesn't removed from them when removed from parametercollection. So when you try to re-add that removed parameter, an exception occurs because the item is already in the HashTable. The fix is to remove parameter from HashTables when removed from parametercollection. I provide the fixed versions of three Remove methods below:

public override void Remove(object value)
{
 items.Remove(value);
 DbParameter p = (DbParameter)value;
 hash.Remove(p.ParameterName);
 ciHash.Remove(p.ParameterName);
}

public override void RemoveAt(string name)
{
 DbParameter p = GetParameter(name);
 items.Remove(p);
 hash.Remove(p.ParameterName);
 ciHash.Remove(p.ParameterName);
}

public override void RemoveAt(int index)
{
 DbParameter p = GetParameter(index);
 items.RemoveAt(index);
 hash.Remove(p.ParameterName);
 ciHash.Remove(p.ParameterName);
}
[7 Mar 2007 15:37] Reggie Burnett
This issue has already been fixed in release 5.0.5 which is currently available for download.