Bug #18186 Problem with implementation of PreparedStatement
Submitted: 13 Mar 2006 10:34 Modified: 6 Nov 2006 14:20
Reporter: Radek Stastny Email Updates:
Status: Closed Impact on me:
None 
Category:Connector / NET Severity:S2 (Serious)
Version:1.0.4, 1.0.7 OS:Linux (Linux, Win (Mono, .NET))
Assigned to: Reggie Burnett CPU Architecture:Any

[13 Mar 2006 10:34] Radek Stastny
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.
[13 Mar 2006 10:37] Radek Stastny
Patched version of PreparedStatement

Attachment: PreparedStatement.cs (text/plain), 3.65 KiB.

[30 Oct 2006 21:51] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/14583
[30 Oct 2006 21:56] Reggie Burnett
Fixed in 1.0.9 and 5.0.2
[30 Oct 2006 21:56] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/14584
[6 Nov 2006 14:20] MC Brown
A note has been added to the 1.0.9 and 5.0.2 changelogs.