Description:
I have discovered problem with implementation of MySql.Data.MySqlClient.PreparedStatement.
In method Execute there is MySqlParameterCollection parameters parameter.
this parameter is converted into BitArray and then into byte[]
In case parameters.Count == 0 problem occurs with
nullMap.CopyTo( nullMapBytes, 0 );
nullMap is BitArray of Length = 0
and CopyTo (if implemented properly -> found in MSDN specs and in Mono too)
fails with ArgumentException as index (0) is >= Destination array length.
MS .NET (1.1, 2.0) ignores this, but Mono doesn't and my question about it was answered as: "Should we simulate this bug?"
How to repeat:
This is testing piece of code for that bug. It doesn't use MySql.Data, but it simulates the problem:
using System;
using System.Collections;
namespace BitArrTest
{
/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
ArrayList al = new ArrayList();
//al.Add(1);
//al.Add(0);
BitArray ba = new BitArray(al.Count);
for(int i = 0; i < al.Count; i++)
if((int)al[i] != 0)
ba[i] = true;
else
ba[i] = false;
byte[] bya = new byte[(al.Count+7)/8];
ba.CopyTo(bya, 0);
Console.WriteLine("Done");
}
}
}
And this is piece of code inside MySql.Data.MySqlClient.PreparedStatement:
public CommandResult Execute( MySqlParameterCollection parameters )
{
if (parameters.Count < paramList.Length)
throw new MySqlException( "Invalid number of parameters for statement execute" );
PacketWriter packet = new PacketWriter();
packet.Driver = (NativeDriver)driver;
//TODO: support long data here
// create our null bitmap
BitArray nullMap = new BitArray( parameters.Count ); //metaData.Length );
for (int x=0; x < parameters.Count; x++)
{
if (parameters[x].Value == DBNull.Value)
nullMap[x] = true;
}
byte[] nullMapBytes = new byte[ (parameters.Count + 7)/8 ];
nullMap.CopyTo( nullMapBytes, 0 );
As you can see it is almost the same.
Suggested fix:
Well, how to fix it. I suggest following update:
public CommandResult Execute( MySqlParameterCollection parameters )
{
if (parameters.Count < paramList.Length)
throw new MySqlException( "Invalid number of parameters for statement execute" );
PacketWriter packet = new PacketWriter();
packet.Driver = (NativeDriver)driver;
//TODO: support long data here
// create our null bitmap
BitArray nullMap = new BitArray( parameters.Count ); //metaData.Length );
for (int x=0; x < parameters.Count; x++)
{
if (parameters[x].Value == DBNull.Value)
nullMap[x] = true;
}
byte[] nullMapBytes = new byte[ (parameters.Count + 7)/8 ];
if(nullMapBytes.Length > 0) // This fix problem with ArgumentException and nullMapBytes is already created and in case of length=0 there is no data to copy...
nullMap.CopyTo( nullMapBytes, 0 );
Very simple and now it follows .NET specifications and works with Mono.