Просмотр исходного кода

Resyncing ByteFX.Data with latest from ByteFX

svn path=/trunk/mcs/; revision=18644
Reggie Burnett 22 лет назад
Родитель
Сommit
463a885e90
47 измененных файлов с 7079 добавлено и 4256 удалено
  1. 58 58
      mcs/class/ByteFX.Data/AssemblyInfo.cs
  2. 20 6
      mcs/class/ByteFX.Data/ByteFX.Data.dll.sources
  3. 226 22
      mcs/class/ByteFX.Data/ChangeLog.txt
  4. 53 54
      mcs/class/ByteFX.Data/Common/BitStream.cs
  5. 233 0
      mcs/class/ByteFX.Data/Common/DBConnectionString.cs
  6. 59 0
      mcs/class/ByteFX.Data/Common/DBParametersEditor.cs
  7. 51 47
      mcs/class/ByteFX.Data/Common/Field.cs
  8. 76 76
      mcs/class/ByteFX.Data/Common/HuffmanTree.cs
  9. 37 37
      mcs/class/ByteFX.Data/Common/Inflater.cs
  10. 208 208
      mcs/class/ByteFX.Data/Common/NamedPipeStream.cs
  11. 25 0
      mcs/class/ByteFX.Data/Common/Security.cs
  12. 244 0
      mcs/class/ByteFX.Data/Common/SqlCommandEditorDlg.cs
  13. 105 0
      mcs/class/ByteFX.Data/Common/SqlCommandEditorDlg.resx
  14. 63 0
      mcs/class/ByteFX.Data/Common/SqlCommandTextEditor.cs
  15. 64 0
      mcs/class/ByteFX.Data/Common/StringUtility.cs
  16. 51 0
      mcs/class/ByteFX.Data/Common/Version.cs
  17. 5 1
      mcs/class/ByteFX.Data/Makefile
  18. 88 0
      mcs/class/ByteFX.Data/mysqlclient/CharSetMap.cs
  19. 382 374
      mcs/class/ByteFX.Data/mysqlclient/CommandBuilder.cs
  20. 338 257
      mcs/class/ByteFX.Data/mysqlclient/Connection.cs
  21. 42 42
      mcs/class/ByteFX.Data/mysqlclient/Connection.resx
  22. 108 0
      mcs/class/ByteFX.Data/mysqlclient/ConnectionInternal.cs
  23. 55 0
      mcs/class/ByteFX.Data/mysqlclient/ConnectionString.cs
  24. 310 0
      mcs/class/ByteFX.Data/mysqlclient/Designers/EditConnectionString.cs
  25. 102 0
      mcs/class/ByteFX.Data/mysqlclient/Designers/EditConnectionString.resx
  26. 55 0
      mcs/class/ByteFX.Data/mysqlclient/Designers/MySqlConnectionDesign.cs
  27. BIN
      mcs/class/ByteFX.Data/mysqlclient/Designers/command.bmp
  28. BIN
      mcs/class/ByteFX.Data/mysqlclient/Designers/connection.bmp
  29. BIN
      mcs/class/ByteFX.Data/mysqlclient/Designers/dataadapter.bmp
  30. 540 697
      mcs/class/ByteFX.Data/mysqlclient/Driver.cs
  31. 48 40
      mcs/class/ByteFX.Data/mysqlclient/Exception.cs
  32. 392 400
      mcs/class/ByteFX.Data/mysqlclient/Field.cs
  33. 229 0
      mcs/class/ByteFX.Data/mysqlclient/MySqlHelper.cs
  34. 112 0
      mcs/class/ByteFX.Data/mysqlclient/MySqlPool.cs
  35. 63 0
      mcs/class/ByteFX.Data/mysqlclient/MySqlPoolManager.cs
  36. 187 0
      mcs/class/ByteFX.Data/mysqlclient/MySqlStream.cs
  37. 126 121
      mcs/class/ByteFX.Data/mysqlclient/MysqlDefs.cs
  38. 228 0
      mcs/class/ByteFX.Data/mysqlclient/Packet.cs
  39. 468 478
      mcs/class/ByteFX.Data/mysqlclient/command.cs
  40. 42 42
      mcs/class/ByteFX.Data/mysqlclient/command.resx
  41. 193 186
      mcs/class/ByteFX.Data/mysqlclient/dataadapter.cs
  42. 535 464
      mcs/class/ByteFX.Data/mysqlclient/datareader.cs
  43. 493 287
      mcs/class/ByteFX.Data/mysqlclient/parameter.cs
  44. 212 210
      mcs/class/ByteFX.Data/mysqlclient/parameter_collection.cs
  45. 26 26
      mcs/class/ByteFX.Data/mysqlclient/todo.txt
  46. 86 86
      mcs/class/ByteFX.Data/mysqlclient/transcaction.cs
  47. 41 37
      mcs/class/ByteFX.Data/readme.txt

+ 58 - 58
mcs/class/ByteFX.Data/AssemblyInfo.cs

@@ -1,58 +1,58 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-
-//
-// General Information about an assembly is controlled through the following 
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-//
-[assembly: AssemblyTitle("ByteFX.Data.dll")]
-[assembly: AssemblyDescription("ADO.Net drivers for MySQL & PostgreSQL")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("ByteFX, Inc.")]
-[assembly: AssemblyProduct("")]
-[assembly: AssemblyCopyright("Copyright 2002, ByteFX, Inc.")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]		
-
-//
-// Version information for an assembly consists of the following four values:
-//
-//      Major Version
-//      Minor Version 
-//      Build Number
-//      Revision
-//
-// You can specify all the values or you can default the Revision and Build Numbers 
-// by using the '*' as shown below:
-
-[assembly: AssemblyVersion("0.6.5.*")]
-
-//
-// In order to sign your assembly you must specify a key to use. Refer to the 
-// Microsoft .NET Framework documentation for more information on assembly signing.
-//
-// Use the attributes below to control which key is used for signing. 
-//
-// Notes: 
-//   (*) If no key is specified, the assembly is not signed.
-//   (*) KeyName refers to a key that has been installed in the Crypto Service
-//       Provider (CSP) on your machine. KeyFile refers to a file which contains
-//       a key.
-//   (*) If the KeyFile and the KeyName values are both specified, the 
-//       following processing occurs:
-//       (1) If the KeyName can be found in the CSP, that key is used.
-//       (2) If the KeyName does not exist and the KeyFile does exist, the key 
-//           in the KeyFile is installed into the CSP and used.
-//   (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
-//       When specifying the KeyFile, the location of the KeyFile should be
-//       relative to the project output directory which is
-//       %Project Directory%\obj\<configuration>. For example, if your KeyFile is
-//       located in the project directory, you would specify the AssemblyKeyFile 
-//       attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
-//   (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
-//       documentation for more information on this.
-//
-[assembly: AssemblyDelaySign(false)]
-[assembly: AssemblyKeyFile("")]
-[assembly: AssemblyKeyName("")]
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+//
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly: AssemblyTitle("ByteFX.Data.dll")]
+[assembly: AssemblyDescription("ADO.Net drivers for MySql & PostgreSQL")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("ByteFX, Inc.")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("Copyright 2002-2003, ByteFX, Inc.")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]		
+
+//
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers 
+// by using the '*' as shown below:
+
+[assembly: AssemblyVersion("0.7.2.*")]
+
+//
+// In order to sign your assembly you must specify a key to use. Refer to the 
+// Microsoft .NET Framework documentation for more information on assembly signing.
+//
+// Use the attributes below to control which key is used for signing. 
+//
+// Notes: 
+//   (*) If no key is specified, the assembly is not signed.
+//   (*) KeyName refers to a key that has been installed in the Crypto Service
+//       Provider (CSP) on your machine. KeyFile refers to a file which contains
+//       a key.
+//   (*) If the KeyFile and the KeyName values are both specified, the 
+//       following processing occurs:
+//       (1) If the KeyName can be found in the CSP, that key is used.
+//       (2) If the KeyName does not exist and the KeyFile does exist, the key 
+//           in the KeyFile is installed into the CSP and used.
+//   (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
+//       When specifying the KeyFile, the location of the KeyFile should be
+//       relative to the project output directory which is
+//       %Project Directory%\obj\<configuration>. For example, if your KeyFile is
+//       located in the project directory, you would specify the AssemblyKeyFile 
+//       attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
+//   (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
+//       documentation for more information on this.
+//
+[assembly: AssemblyDelaySign(false)]
+[assembly: AssemblyKeyFile("..\\..\\bytefx.snk")]
+[assembly: AssemblyKeyName("")]

+ 20 - 6
mcs/class/ByteFX.Data/ByteFX.Data.dll.sources

@@ -1,20 +1,34 @@
 ./AssemblyInfo.cs
 ./Common/BitStream.cs
-./Common/Connection.cs
-./Common/ConnectionString.cs
+./Common/DBConnectionString.cs
+./Common/DBParametersEditor.cs
 ./Common/Field.cs
 ./Common/HuffmanTree.cs
-./Common/Inflater.cs
 ./Common/NamedPipeStream.cs
+./Common/Security.cs
+./Common/SqlCommandEditorDlg.cs
+./Common/SqlCommandTextEditor.cs
+./Common/StringUtility.cs
+./Common/Version.cs
+./mysqlclient/CharSetMap.cs
 ./mysqlclient/CommandBuilder.cs
+./mysqlclient/command.cs
 ./mysqlclient/Connection.cs
+./mysqlclient/ConnectionInternal.cs
+./mysqlclient/ConnectionString.cs
+./mysqlclient/dataadapter.cs
+./mysqlclient/datareader.cs
 ./mysqlclient/Driver.cs
 ./mysqlclient/Exception.cs
 ./mysqlclient/Field.cs
 ./mysqlclient/MysqlDefs.cs
-./mysqlclient/command.cs
-./mysqlclient/dataadapter.cs
-./mysqlclient/datareader.cs
+./mysqlclient/MySqlHelper.cs
+./mysqlclient/MySqlPool.cs
+./mysqlclient/MySqlPoolManager.cs
+./mysqlclient/MySqlStream.cs
+./mysqlclient/Packet.cs
 ./mysqlclient/parameter.cs
 ./mysqlclient/parameter_collection.cs
 ./mysqlclient/transcaction.cs
+./mysqlclient/Designers/EditConnectionString.cs
+./mysqlclient/Designers/MySqlConnectionDesign.cs

+ 226 - 22
mcs/class/ByteFX.Data/ChangeLog.txt

@@ -1,22 +1,226 @@
-0.65
-====================
-* MySQLCommandBuilder now implemented
-* Transaction support now implemented (not all table types support this)
-* GetSchemaTable fixed to not use xsd (for Mono)
-* Driver is now Mono-compatible!!
-* TIME data type now supported
-* More work to improve Timestamp data type handling
-* Changed signatures of all classes to match corresponding SqlClient classes
-
-0.60
-======================
-* Protocol compression  using SharpZipLib (www.icsharpcode.net)
-* Named pipes on Windows now working properly
-* Work done to improve Timestamp data type handling
-* Implemented IEnumerable on DataReader so DataGrid would work
- 
-0.50
-======================
-* Speed increased dramatically by removing bugging network sync code
-* Driver no longer buffers rows of data (more ADO.Net compliant)
-* Conversion bugs related to TIMESTAMP and DATETIME fields fixed
+10/3/2003
+MySql - Added InternalConnection class, changes to pooling
+Common - Implemented Persist Security Info
+
+9/26/2003
+Common - Added security.cs and version.cs to project
+
+9/25/2003
+MySql - Fixed DateTime handling in Parameter.cs (thanks Burkhard Perkens-Golomb)
+MySql - Fixed parameter serialization where some types would throw a cast exception
+MySql - Fixed DataReader to convert all returned values to prevent casting errors (thanks Keith Murray)
+MySql - Added code to Command.ExecuteReader to return null if the initial SQL command throws an exception (thanks Burkhard Perkens-Golomb)
+
+9/24/2003
+MySql - Fixed ExecuteScalar bug introduced with restructure
+
+9/23/2003
+MySql - Restructure to allow for LOCAL DATA INFILE and better sequencing of packets
+MySql - Fixed several bugs related to restructure.
+
+9/10/2003
+MySql - Early work done to support more secure passwords in Mysql 4.1.  Old passwords in 4.1 not supported yet
+
+8/22/2003
+MySql- Parameters appearing after system parameters are now handled correctly (Adam M. (adammil))
+MySql - strings can now be assigned directly to blob fields (Adam M.)
+
+8/20/2003
+MySql - Fixed float parameters (thanks Pent)
+
+8/7/2003
+MySql - Improved Parameter ctor and ParameterCollection.Add methods to better match SqlClient (thx Joshua Mouch )
+MySql - Corrected Connection.CreateCommand to return a MySqlCommand type
+MySql - Fixed connection string designer dialog box problem (thanks Abraham Guyt)
+
+7/24/2003
+MySql - Fixed problem with sending commands not always reading the response packet (thanks Joshua Mouch )
+MySql - Fixed parameter serialization where some blobs types were not being handled (thanks Sean McGinnis )
+
+7/22/2003
+MySql - Removed spurious MessageBox.show from DataReader code (thanks Joshua Mouch )
+
+7/17/2003
+MySql - Fixed a nasty bug in the split sql code (thanks everyone! :-) )
+
+*************Released 0.71***********************
+7/15/2003
+MySql - Fixed bug in MySqlStream where too much data could attempt to be read (thanks Peter Belbin)
+
+7/11/2003
+MySql - Implemented HasRows (thanks Nash Pherson)
+MySql - Fixed bug where tables with more than 252 columns cause an exception ( thanks Joshua Kessler )
+MySql - Fixed bug where SQL statements ending in ; would cause a problem ( thanks Shane Krueger )
+MySql - Fixed bug in driver where error messsages were getting truncated by 1 character (thanks Shane Krueger)
+
+7/6/2003
+========MySql===============
+* Made MySqlException serializable (thanks Mathias Hasselmann)
+
+========PgSql===============
+* Made PgSqlException serializable (thanks Mathias Hasselmann)
+
+***********Released 0.70*********************
+
+6/25/2003
+========MySql===============
+* Updated some of the character code pages to be more accurate
+* Fixed problem where readers could be opened on connections that had readers open
+* Release of 0.70
+
+6/20/2003
+========MySql===============
+* Moved test to separate assembly MySqlClientTests
+
+6/19/2003
+========MySql===============
+* Fixed stupid problem in driver with sequence out of order (Thanks Peter Belbin)
+
+6/18/2003
+========MySql===============
+* Added some pipe tests
+* Increased default max pool size to 50
+* Compiles with Mono 0-24
+
+6/17/2003
+========MySql===============
+* Fixed connection and data reader dispose problems
+* Added String datatype handling to parameter serialization
+
+6/13/2003
+========MySql===============
+* Fixed sequence problem in driver that occured after thrown exception
+  (thanks Burkhard Perkens-Golomb)
+
+6/10/2003
+========MySql===============
+* Added support for CommandBehavior.SingleRow to DataReader
+* Fixed command sql processing so quotes are better handled (thanks Theo Spears)
+
+6/9/2003
+========MySQL===============
+* Fixed parsing of double, single, and decimal values to account for non-English separators.
+  You still have to use the right syntax if you using hard coded sql, but if you use parameters
+  the code will convert floating point types to use '.' appropriately internal both into the server
+  and out.
+  [ Thanks anonymous ]
+* Added MySqlStream class to simplify timeOuts and driver coding.
+* Fixed DataReader so that it is closed properly when the associated connection is closed.  
+  [thanks smishra]
+* Made client more SqlClient compliant so that DataReaders have to be closed before the connection
+  can be used to run another command
+* Improved DBNull.Value handling in the fields
+* Added several unit tests
+* Fixed MySqlException so that the base class is actually called  :-o
+* Improved driver coding
+
+=============PgSql=================
+* Too many changes to document. Still basic structuring of driver.  Driver not really usable yet.
+
+
+
+5/28/2003
+* Fixed bug where NextResult was returning false on the last resultset
+* Added more tests for MySQL
+* Improved casting problems by equating unsigned 32bit values to Int64 and usigned 16bit values to Int32, etc
+
+5/6/2003
+* Added new ctor for MySqlParameter for (name, type, size, srccol)
+* Fixed bug in MySqlDataReader where it didn't check for null fieldlist before returning field count
+
+4/23/2003
+* Started adding MySqlClient unit tests (added MySqlClient/Tests folder and some test cases)
+* Fixed some things in Connection String handling
+
+4/7/2003
+* Moved INIT_DB to MySqlPool.  I may move it again, this is in preparation of the conference.
+
+4/6/2003
+* Fixed bug inside CommandBuilder that prevented inserts from happening properly
+* Reworked some of the internals so that all three execute methods of Command worked properly
+* FIxed many small bugs found during benchmarking
+
+4/5/2003
+* The first cut of CoonectionPooling is working. "min pool size" and "max pool size" are respected.
+
+4/3/2003
+* Work to enable multiple resultsets to be returned
+* Character sets are handled much more intelligently now.  The driver queries MySQL at startup for the default character set.
+  That character set is then used for conversions if that code page can be loaded.  If not, then the default code
+  page for the current OS is used.  
+
+3/31/2003
+* Added code to save the inferred type in the name,value ctor of Parameter
+* Also, inferred type if value of null parameter is changed using Value property
+* Converted all files to use proper Camel case.  MySQL is now MySql in all files.  PgSQL is now PgSql
+* Added attribute to PgSql code to prevent designer from trying to show
+
+3/17/2003
+* Added MySQLDbType property to Parameter object and added proper conversion code to convert from DbType to MySQLDbType)
+* Removed unused ObjectToString method from MySQLParameter.cs
+* Fixed Add(..) method in ParameterCollection so that it doesn't use Add(name, value) instead.
+* Fixed IndexOf and Contains in ParameterCollection to be aware that parameter names are now stored without @ 
+* Fixed Command.ConvertSQLToBytes so it only allows characters that can be in MySQL variable names
+* Fixed DataReader and Field so that blob fields read their data from Field.cs and GetBytes works right
+* Added simple query builder editor to CommandText property of MySQLCommand
+* Fixed CommandBuilder and Parameter serialization to account for Parameters not storing @ in their names
+* Removed MySQLFieldType enum from Field.cs.  Now using MySQLDbType enum
+
+3/15/2003
+* Added Designer attribute to several classes to prevent designer view when using VS.Net
+
+3/13/2003
+* Fixed Initial catalog typo in ConnectionString designer
+* Removed 3 parameter ctor for MySQLParameter that conflicted with (name, type, value)
+* changed MySQLParameter so paramName is now stored without leading @ (this fixed null inserts when using designer)
+* Changed TypeConverter for MySQLParameter to use the ctor with all properties
+
+0.68
+========================================================================
+Note that this build has not been checked out with Mono.  
+
+3/10/2003
+* Fixed sequence issue in driver
+
+3/9/2003
+* Added DbParametersEditor to make parameter editing more like SqlClient
+* Fixed Command class so that parameters can be edited using the designer
+
+3/7/2003
+* Update connection string designer to support Use Compression flag
+
+2/15/2003
+* Fixed string encoding so that European characters like ä will work correctly
+
+2/9/2003
+* Creating base classes to aid in building new data providers
+* Added support for UID key in connection string
+
+2/10/2003
+* Field, parameter, command now using DBNull.Value instead of null
+* CommandBuilder using DBNull.Value
+* CommandBuilder now builds insert command correctly when an auto_insert field is not present
+* Field now uses typeof keyword to return System.Types (performance)
+
+0.65
+====================
+* MySQLCommandBuilder now implemented
+* Transaction support now implemented (not all table types support this)
+* GetSchemaTable fixed to not use xsd (for Mono)
+* Driver is now Mono-compatible!!
+* TIME data type now supported
+* More work to improve Timestamp data type handling
+* Changed signatures of all classes to match corresponding SqlClient classes
+
+0.60
+======================
+* Protocol compression  using SharpZipLib (www.icsharpcode.net)
+* Named pipes on Windows now working properly
+* Work done to improve Timestamp data type handling
+* Implemented IEnumerable on DataReader so DataGrid would work
+ 
+0.50
+======================
+* Speed increased dramatically by removing bugging network sync code
+* Driver no longer buffers rows of data (more ADO.Net compliant)
+* Conversion bugs related to TIMESTAMP and DATETIME fields fixed

+ 53 - 54
mcs/class/ByteFX.Data/Common/BitStream.cs

@@ -1,54 +1,53 @@
-using System;
-using System.IO;
-
-namespace ByteFX.Data.Common
-{
-	/// <summary>
-	/// Summary description for BitStream.
-	/// </summary>
-	public class BitStream : MemoryStream
-	{
-		private byte[]	_input;
-		private int		_start;
-		private int		_end;
-		private int		_bitindex;
-		private uint	_bitbuffer;
-		private int		_bits_in_buffer;
-
-		public BitStream(byte[] input, int index, int len)
-		{
-			_bitindex = 0;
-			_bitbuffer = 0;
-			_bits_in_buffer = 0;
-			_input = input;
-			_start = index;
-			_end = _start + len;
-		}
-
-		public int GetBits(int numbits)
-		{
-			return 0;
-		}
-
-		public int PeekBits(int numbits)
-		{
-			int val=0;
-			int numbytes=0;
-
-			int index=_start;
-			while (numbits > 0)
-			{
-				val = (val << 8) | _input[index++];
-				numbits -= 8;
-			}
-
-			while (_bits_in_buffer < numbits)
-			{
-				if (_start == _end)
-					throw new Exception("Out of bits");
-				byte b = _input[_start++];
-			}
-			return 0;
-		}
-	}
-}
+using System;
+using System.IO;
+
+namespace ByteFX.Data.Common
+{
+	/// <summary>
+	/// Summary description for BitStream.
+	/// </summary>
+	public class BitStream : MemoryStream
+	{
+		private byte[]	_input;
+		private int		_start;
+		private int		_end;
+		private int		_bitindex;
+		private uint	_bitbuffer;
+		private int		_bits_in_buffer;
+
+		public BitStream(byte[] input, int index, int len)
+		{
+			_bitindex = 0;
+			_bitbuffer = 0;
+			_bits_in_buffer = 0;
+			_input = input;
+			_start = index;
+			_end = _start + len;
+		}
+
+		public int GetBits(int numbits)
+		{
+			return 0;
+		}
+
+		public int PeekBits(int numbits)
+		{
+			int val=0;
+
+			int index=_start;
+			while (numbits > 0)
+			{
+				val = (val << 8) | _input[index++];
+				numbits -= 8;
+			}
+
+			while (_bits_in_buffer < numbits)
+			{
+				if (_start == _end)
+					throw new Exception("Out of bits");
+				byte b = _input[_start++];
+			}
+			return 0;
+		}
+	}
+}

+ 233 - 0
mcs/class/ByteFX.Data/Common/DBConnectionString.cs

@@ -0,0 +1,233 @@
+// ByteFX.Data data access components for .Net
+// Copyright (C) 2002-2003  ByteFX, Inc.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+using System;
+using System.Collections;
+using System.Text;
+
+namespace ByteFX.Data.Common
+{
+	/// <summary>
+	/// Summary description for Utility.
+	/// </summary>
+	internal class DBConnectionString
+	{
+		protected Hashtable	keyValues = new Hashtable();
+		protected string	connectString;
+		protected string	host;
+		protected string	username;
+		protected string	password;
+		protected string	database;
+		protected int		connectTimeout;
+		protected int		port;
+		protected int		maxPoolSize;
+		protected int		minPoolSize;
+		protected int		connectLifetime;
+		protected bool		pooling;
+		protected bool		persistSecurityInfo;
+
+		public DBConnectionString()
+		{	
+			persistSecurityInfo = false;
+		}
+
+		public DBConnectionString(string connectString) : this()
+		{
+			this.connectString = connectString;
+		}
+
+		#region Properties
+		public string Host 
+		{
+			get { return host; }
+		}
+
+		public string Username 
+		{
+			get { return username; }
+		}
+
+		public string Password 
+		{
+			get { return password; }
+		}
+
+		public int ConnectTimeout
+		{
+			get { return connectTimeout; }
+		}
+		
+		public string Database 
+		{
+			get { return database; }
+		}
+
+		public int Port 
+		{
+			get { return port; }
+		}
+
+		public int MaxPoolSize 
+		{
+			get { return maxPoolSize; }
+		}
+
+		public int MinPoolSize 
+		{
+			get { return minPoolSize; }
+		}
+
+		public bool Pooling 
+		{
+			get { return pooling; }
+		}
+
+		public int ConnectionLifetime 
+		{
+			get { return connectLifetime; }
+		}
+
+		public string ConnectString 
+		{
+			get { return GetConnectionString(); }
+			set { connectString = value; Parse(); }
+		}
+
+		#endregion
+
+		private string GetConnectionString()
+		{
+			StringBuilder str = new StringBuilder();
+
+			foreach ( string key in keyValues.Keys)
+			{
+				if ((key.ToLower() == "pwd" || key.ToLower() == "password") &&
+					!persistSecurityInfo) continue;
+				str.AppendFormat("{0}={1};", key, keyValues[key]);
+			}
+			str.Remove( str.Length-1, 1 );
+			return str.ToString();
+		}
+
+		protected virtual void ConnectionParameterParsed(string key, string value)
+		{
+			switch (key.ToLower()) 
+			{
+				case "persist security info":
+					persistSecurityInfo = bool.Parse(value);
+					break;
+
+				case "uid":
+				case "username":
+				case "user id":
+				case "user name": 
+					username = value.ToLower();
+					break;
+
+				case "password": 
+				case "pwd":
+					password = value.ToLower();
+					break;
+
+				case "host":
+				case "server":
+				case "data source":
+				case "datasource":
+				case "address":
+				case "addr":
+				case "network address":
+					host = value.ToLower();
+					break;
+				
+				case "initial catalog":
+				case "database":
+					database = value.ToLower();
+					break;
+
+				case "connection timeout":
+				case "connect timeout":
+					connectTimeout = Int32.Parse( value );
+					break;
+
+				case "port":
+					port = Int32.Parse( value );
+					break;
+
+				case "pooling":
+					pooling = Boolean.Parse( value );
+					break;
+
+				case "min pool size":
+					minPoolSize = Int32.Parse(value);
+					break;
+
+				case "max pool size":
+					maxPoolSize = Int32.Parse(value);
+					break;
+
+				case "connection lifetime":
+					connectLifetime = Int32.Parse(value);
+					break;
+			}
+		}
+
+		protected void Parse() 
+		{
+			String[] keyvalues = connectString.Split( ';' );
+			String[] newkeyvalues = new String[keyvalues.Length];
+			int		 x = 0;
+
+			// first run through the array and check for any keys that
+			// have ; in their value
+			foreach (String keyvalue in keyvalues) 
+			{
+				// check for trailing ; at the end of the connection string
+				if (keyvalue.Length == 0) continue;
+
+				// this value has an '=' sign so we are ok
+				if (keyvalue.IndexOf('=') >= 0) 
+				{
+					newkeyvalues[x++] = keyvalue;
+				}
+				else 
+				{
+					newkeyvalues[x-1] += ";";
+					newkeyvalues[x-1] += keyvalue;
+				}
+			}
+
+			// now we run through our normalized key-values, splitting on equals
+			for (int y=0; y < x; y++) 
+			{
+				String[] parts = newkeyvalues[y].Split( '=' );
+
+				// first trim off any space and lowercase the key
+				parts[0] = parts[0].Trim().ToLower();
+				parts[1] = parts[1].Trim();
+
+				// we also want to clear off any quotes
+				parts[0] = parts[0].Trim('\'', '"');
+				parts[1] = parts[1].Trim('\'', '"');
+
+				ConnectionParameterParsed( parts[0], parts[1] );
+				keyValues.Add( parts[0], parts[1] );
+			}
+		}
+
+
+	}
+}

+ 59 - 0
mcs/class/ByteFX.Data/Common/DBParametersEditor.cs

@@ -0,0 +1,59 @@
+// ByteFX.Data data access components for .Net
+// Copyright (C) 2002-2003  ByteFX, Inc.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+using System;
+using System.ComponentModel.Design;
+using ByteFX.Data.MySqlClient;
+
+namespace ByteFX.Data.Common
+{
+	/// <summary>
+	/// Summary description for DBParametersEditor.
+	/// </summary>
+	public class DBParametersEditor : CollectionEditor
+	{
+		public DBParametersEditor(Type t) : base(t)
+		{
+		}
+
+		protected override object CreateInstance(Type itemType)
+		{
+			object[] items = base.GetItems(null);
+
+			int i = 1;
+			while (true) 
+			{
+				bool found = false;
+				foreach (object obj in items) 
+				{
+					MySqlParameter p = (MySqlParameter)obj;
+					if (p.ParameterName.Equals( "parameter" + i )) 
+					{
+						found = true;
+						break;
+					}
+				}
+				if (! found) break;
+				i ++;
+			}
+
+			MySqlParameter parm = new MySqlParameter("parameter"+i, MySqlDbType.VarChar);
+			return parm;
+		}
+
+	}
+}

+ 51 - 47
mcs/class/ByteFX.Data/Common/Field.cs

@@ -1,47 +1,51 @@
-using System;
-using System.Data;
-using System.Data.SqlTypes;
-
-namespace ByteFX.Data.Common
-{
-	/// <summary>
-	/// Summary description for Field.
-	/// </summary>
-	internal class Field
-	{
-		protected	SqlDateTime	m_DateTime;
-		protected	SqlString	m_StringValue;
-		protected	SqlInt64	m_IntValue;
-		protected	SqlDouble	m_DoubleValue;
-		protected	SqlSingle	m_SingleValue;
-		protected	SqlMoney	m_MoneyValue;
-		protected	SqlDecimal	m_DecimalValue;
-		protected	SqlBinary	m_BinaryValue;
-
-		protected	string		m_TableName;
-		protected	string		m_ColName;
-		protected	int			m_ColLen;
-		protected	DbType		m_DbType;
-		protected	bool		m_HasValue;
-
-		public Field()
-		{
-			m_HasValue = false;
-		}
-
-		public string ColumnName 
-		{
-			get { return m_ColName; }
-		}
-
-		public int ColumnLength
-		{
-			get { return m_ColLen; }
-		}
-
-		public string TableName 
-		{
-			get { return m_TableName; }
-		}
-	}
-}
+using System;
+using System.Data;
+using System.Data.SqlTypes;
+
+namespace ByteFX.Data.Common
+{
+	/// <summary>
+	/// Summary description for Field.
+	/// </summary>
+	internal class Field
+	{
+/*		protected	SqlByte		byteValue;
+		protected	SqlDateTime	dateValue;
+		protected	SqlString	stringValue;
+		protected	SqlInt32	int32Value;
+		protected	SqlInt64	int64Value;
+		protected	SqlDouble	doubleValue;
+		protected	SqlSingle	singleValue;
+		protected	SqlMoney	moneyValue;
+		protected	SqlDecimal	decimalValue;
+		protected	SqlBinary	binaryValue;*/
+		protected	object		value;
+
+		protected	string		tableName;
+		protected	string		colName;
+		protected	int			colLen;
+		protected	DbType		dbType;
+		protected	bool		hasValue;
+
+		public Field()
+		{
+			hasValue = false;
+		}
+
+		public string ColumnName 
+		{
+			get { return colName; }
+		}
+
+		public int ColumnLength
+		{
+			get { return colLen; }
+		}
+
+		public string TableName 
+		{
+			get { return tableName; }
+		}
+
+	}
+}

+ 76 - 76
mcs/class/ByteFX.Data/Common/HuffmanTree.cs

@@ -1,76 +1,76 @@
-using System;
-
-namespace ByteFX.Data.Common
-{
-	/// <summary>
-	/// Summary description for HuffmanTree.
-	/// </summary>
-	public class HuffmanTree
-	{
-		const int MAX_BITS = 15;
-		int[]	codes;
-
-		public HuffmanTree(bool lit)
-		{
-			if (lit)
-				BuildLitTree();
-			else
-				BuildLenTree();
-		}
-
-		private void BuildLitTree()
-		{
-			codes = new int[288];
-
-			// fill the code slots with code lengths first
-			for (int x=0; x < 144; x++)
-				codes[x] = 8;
-			for (int x=144; x < 256; x++)
-				codes[x] = 9;
-			for (int x=256; x < 280; x++)
-				codes[x] = 7;
-			for (int x=280; x < 288; x++)
-				codes[x] = 8;
-
-			BuildTreeCommon();
-		}
-
-
-		private void BuildLenTree()
-		{
-			BuildTreeCommon();
-		}
-
-		private void BuildTreeCommon()
-		{
-			int[] codecounts = new int[MAX_BITS];
-			int[] codebase = new int[MAX_BITS];
-
-			for (int i = 0; i < codes.Length; i++) 
-			{
-				int bit_len = codes[i];
-				if (bit_len > 0)
-					codecounts[bit_len]++;
-			}
-
-			// now we compute the intial value for each code length
-			int code = 0;
-			codecounts[0] = 0;
-			for (int bits = 1; bits <= MAX_BITS; bits++) 
-			{
-				code = (code + codecounts[bits-1]) << 1;
-				codebase[bits] = code;
-			}
-
-			// next we assign numerical values to each code
-			for (int x=0;  x <= codes.Length; x++) 
-			{
-				if (codes[x] == 0) continue;
-				int blen = codes[x];
-				codes[x] = codebase[ blen ];
-				codebase[ blen ] ++;
-			}
-		}
-
-	}
-}
+using System;
+
+namespace ByteFX.Data.Common
+{
+	/// <summary>
+	/// Summary description for HuffmanTree.
+	/// </summary>
+	public class HuffmanTree
+	{
+		const int MAX_BITS = 15;
+		int[]	codes;
+
+		public HuffmanTree(bool lit)
+		{
+			if (lit)
+				BuildLitTree();
+			else
+				BuildLenTree();
+		}
+
+		private void BuildLitTree()
+		{
+			codes = new int[288];
+
+			// fill the code slots with code lengths first
+			for (int x=0; x < 144; x++)
+				codes[x] = 8;
+			for (int x=144; x < 256; x++)
+				codes[x] = 9;
+			for (int x=256; x < 280; x++)
+				codes[x] = 7;
+			for (int x=280; x < 288; x++)
+				codes[x] = 8;
+
+			BuildTreeCommon();
+		}
+
+
+		private void BuildLenTree()
+		{
+			BuildTreeCommon();
+		}
+
+		private void BuildTreeCommon()
+		{
+			int[] codecounts = new int[MAX_BITS];
+			int[] codebase = new int[MAX_BITS];
+
+			for (int i = 0; i < codes.Length; i++) 
+			{
+				int bit_len = codes[i];
+				if (bit_len > 0)
+					codecounts[bit_len]++;
+			}
+
+			// now we compute the intial value for each code length
+			int code = 0;
+			codecounts[0] = 0;
+			for (int bits = 1; bits <= MAX_BITS; bits++) 
+			{
+				code = (code + codecounts[bits-1]) << 1;
+				codebase[bits] = code;
+			}
+
+			// next we assign numerical values to each code
+			for (int x=0;  x <= codes.Length; x++) 
+			{
+				if (codes[x] == 0) continue;
+				int blen = codes[x];
+				codes[x] = codebase[ blen ];
+				codebase[ blen ] ++;
+			}
+		}
+
+	}
+}

+ 37 - 37
mcs/class/ByteFX.Data/Common/Inflater.cs

@@ -1,37 +1,37 @@
-using System;
-using System.IO;
-
-namespace ByteFX.Data.Common
-{
-	/// <summary>
-	/// Summary description for Inflater.
-	/// </summary>
-	public class Inflater
-	{
-		private BitStream _input;
-
-		public Inflater()
-		{
-		}
-
-		public void SetInput(byte[] input, int offset, int len)
-		{
-			_input = new BitStream(input, offset, len);
-		}
-
-		public void Inflate(byte[] output, int offset, int size)
-		{
-			byte cmf = (byte)_input.GetBits(8);
-			byte flag = (byte)_input.GetBits(8);
-
-			if ((cmf & 0x0f) != 8)
-				throw new Exception("Only deflate format data is supported");
-
-			if (((cmf*256+flag) % 31) != 0)
-				throw new Exception("Data is not in proper deflate format");
-
-
-
-		}
-	}
-}
+using System;
+using System.IO;
+
+namespace ByteFX.Data.Common
+{
+	/// <summary>
+	/// Summary description for Inflater.
+	/// </summary>
+	public class Inflater
+	{
+		private BitStream _input;
+
+		public Inflater()
+		{
+		}
+
+		public void SetInput(byte[] input, int offset, int len)
+		{
+			_input = new BitStream(input, offset, len);
+		}
+
+		public void Inflate(byte[] output, int offset, int size)
+		{
+			byte cmf = (byte)_input.GetBits(8);
+			byte flag = (byte)_input.GetBits(8);
+
+			if ((cmf & 0x0f) != 8)
+				throw new Exception("Only deflate format data is supported");
+
+			if (((cmf*256+flag) % 31) != 0)
+				throw new Exception("Data is not in proper deflate format");
+
+
+
+		}
+	}
+}

+ 208 - 208
mcs/class/ByteFX.Data/Common/NamedPipeStream.cs

@@ -1,208 +1,208 @@
-// ByteFX.Data data access components for .Net
-// Copyright (C) 2002-2003  ByteFX, Inc.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-using System;
-using System.IO;
-using System.Runtime.InteropServices;
-
-
-namespace ByteFX.Data.Common
-{
-	/// <summary>
-	/// Summary description for API.
-	/// </summary>
-	public class NamedPipeStream : Stream
-	{
-		[DllImport("kernel32.dll", EntryPoint="CreateFile", SetLastError=true)]
-		private static extern IntPtr CreateFile(String lpFileName, 
-			UInt32 dwDesiredAccess, UInt32 dwShareMode,
-			IntPtr lpSecurityAttributes, UInt32 dwCreationDisposition, 
-			UInt32 dwFlagsAndAttributes,
-			IntPtr hTemplateFile);
-		[DllImport("kernel32.dll", EntryPoint="PeekNamedPipe", SetLastError=true)]
-		private static extern bool PeekNamedPipe( IntPtr handle,
-			byte[] buffer, uint nBufferSize, ref uint bytesRead,
-			ref uint bytesAvail, ref uint BytesLeftThisMessage);
-		[DllImport("kernel32.dll", SetLastError=true)]
-		private static extern bool ReadFile( IntPtr handle,
-			byte[] buffer, uint toRead, ref uint read, IntPtr lpOverLapped);
-		[DllImport("kernel32.dll", SetLastError=true)]
-		private static extern bool WriteFile( IntPtr handle,
-			byte[] buffer, uint count, ref uint written, IntPtr lpOverlapped );
-		[DllImport("kernel32.dll", SetLastError=true)]
-		private static extern bool CloseHandle( IntPtr handle );
-		[DllImport("kernel32.dll", SetLastError=true)]
-		private static extern bool FlushFileBuffers( IntPtr handle );
-
-		//Constants for dwDesiredAccess:
-		private const UInt32 GENERIC_READ = 0x80000000;
-		private const UInt32 GENERIC_WRITE = 0x40000000;
-
-		//Constants for return value:
-		private const Int32 INVALID_HANDLE_VALUE = -1;
-
-		//Constants for dwFlagsAndAttributes:
-		private const UInt32 FILE_FLAG_OVERLAPPED = 0x40000000;
-		private const UInt32 FILE_FLAG_NO_BUFFERING = 0x20000000;
-
-		//Constants for dwCreationDisposition:
-		private const UInt32 OPEN_EXISTING = 3;
-
-		IntPtr		_handle;
-		FileAccess	_mode;
-
-		public NamedPipeStream(string host, FileAccess mode)
-		{
-			_handle = IntPtr.Zero;
-			Open(host, mode);
-		}
-
-		public void Open( string host, FileAccess mode )
-		{
-			_mode = mode;
-			uint pipemode = 0;
-
-			if ((mode & FileAccess.Read) > 0)
-				pipemode |= GENERIC_READ;
-			if ((mode & FileAccess.Write) > 0)
-				pipemode |= GENERIC_WRITE;
-			_handle = CreateFile( host, pipemode,
-				0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero );
-		}
-
-		public bool DataAvailable
-		{
-			get 
-			{
-				uint bytesRead=0, avail=0, thismsg=0;
-
-				bool result = PeekNamedPipe( _handle, 
-					null, 0, ref bytesRead, ref avail, ref thismsg );
-				return (result == true && avail > 0);
-			}
-	}
-
-		public override bool CanRead
-		{
-			get { return (_mode & FileAccess.Read) > 0; }
-		}
-
-		public override bool CanWrite
-		{
-			get { return (_mode & FileAccess.Write) > 0; }
-		}
-
-		public override bool CanSeek
-		{
-			get { throw new NotSupportedException("NamedPipeStream does not support seeking"); }
-		}
-
-		public override long Length
-		{
-			get { throw new NotSupportedException("NamedPipeStream does not support seeking"); }
-		}
-
-		public override long Position 
-		{
-			get { throw new NotSupportedException("NamedPipeStream does not support seeking"); }
-			set { }
-		}
-
-		public override void Flush() 
-		{
-			if (_handle == IntPtr.Zero)
-				throw new ObjectDisposedException("NamedPipeStream", "The stream has already been closed");
-			FlushFileBuffers(_handle);
-		}
-
-		public override int Read(byte[] buffer, int offset, int count)
-		{
-			if (buffer == null) 
-				throw new ArgumentNullException("buffer", "The buffer to read into cannot be null");
-			if (buffer.Length < (offset + count))
-				throw new ArgumentException("Buffer is not large enough to hold requested data", "buffer");
-			if (offset < 0) 
-				throw new ArgumentOutOfRangeException("offset", offset, "Offset cannot be negative");
-			if (count < 0)
-				throw new ArgumentOutOfRangeException("count", count, "Count cannot be negative");
-			if (! CanRead)
-				throw new NotSupportedException("The stream does not support reading");
-			if (_handle == IntPtr.Zero)
-				throw new ObjectDisposedException("NamedPipeStream", "The stream has already been closed");
-
-			// first read the data into an internal buffer since ReadFile cannot read into a buf at
-			// a specified offset
-			uint read=0;
-			byte[] buf = new Byte[count];
-			ReadFile( _handle, buf, (uint)count, ref read, IntPtr.Zero );
-			
-			for (int x=0; x < read; x++) 
-			{
-				buffer[offset+x] = buf[x];
-			}
-			return (int)read;
-		}
-
-		public override void Close()
-		{
-			CloseHandle(_handle);
-			_handle = IntPtr.Zero;
-		}
-
-		public override void SetLength(long length)
-		{
-			throw new NotSupportedException("NamedPipeStream doesn't support SetLength");
-		}
-
-		public override void Write(byte[] buffer, int offset, int count)
-		{
-			if (buffer == null) 
-				throw new ArgumentNullException("buffer", "The buffer to write into cannot be null");
-			if (buffer.Length < (offset + count))
-				throw new ArgumentException("Buffer does not contain amount of requested data", "buffer");
-			if (offset < 0) 
-				throw new ArgumentOutOfRangeException("offset", offset, "Offset cannot be negative");
-			if (count < 0)
-				throw new ArgumentOutOfRangeException("count", count, "Count cannot be negative");
-			if (! CanWrite)
-				throw new NotSupportedException("The stream does not support writing");
-			if (_handle == IntPtr.Zero)
-				throw new ObjectDisposedException("NamedPipeStream", "The stream has already been closed");
-			
-			// copy data to internal buffer to allow writing from a specified offset
-			byte[] buf = new Byte[count];
-			for (int x=0; x < count; x++) 
-			{
-				buf[x] = buffer[offset+x];
-			}
-			uint written=0;
-			bool result = WriteFile( _handle, buf, (uint)count, ref written, IntPtr.Zero );
-
-			if (! result)
-				throw new IOException("Writing to the stream failed");
-			if (written < count)
-				throw new IOException("Unable to write entire buffer to stream");
-		}
-
-		public override long Seek( long offset, SeekOrigin origin )
-		{
-			throw new NotSupportedException("NamedPipeStream doesn't support seeking");
-		}
-	}
-}
-
-
+// ByteFX.Data data access components for .Net
+// Copyright (C) 2002-2003  ByteFX, Inc.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+
+
+namespace ByteFX.Data.Common
+{
+	/// <summary>
+	/// Summary description for API.
+	/// </summary>
+	public class NamedPipeStream : Stream
+	{
+		[DllImport("kernel32.dll", EntryPoint="CreateFile", SetLastError=true)]
+		private static extern IntPtr CreateFile(String lpFileName, 
+			UInt32 dwDesiredAccess, UInt32 dwShareMode,
+			IntPtr lpSecurityAttributes, UInt32 dwCreationDisposition, 
+			UInt32 dwFlagsAndAttributes,
+			IntPtr hTemplateFile);
+		[DllImport("kernel32.dll", EntryPoint="PeekNamedPipe", SetLastError=true)]
+		private static extern bool PeekNamedPipe( IntPtr handle,
+			byte[] buffer, uint nBufferSize, ref uint bytesRead,
+			ref uint bytesAvail, ref uint BytesLeftThisMessage);
+		[DllImport("kernel32.dll", SetLastError=true)]
+		private static extern bool ReadFile( IntPtr handle,
+			byte[] buffer, uint toRead, ref uint read, IntPtr lpOverLapped);
+		[DllImport("kernel32.dll", SetLastError=true)]
+		private static extern bool WriteFile( IntPtr handle,
+			byte[] buffer, uint count, ref uint written, IntPtr lpOverlapped );
+		[DllImport("kernel32.dll", SetLastError=true)]
+		private static extern bool CloseHandle( IntPtr handle );
+		[DllImport("kernel32.dll", SetLastError=true)]
+		private static extern bool FlushFileBuffers( IntPtr handle );
+
+		//Constants for dwDesiredAccess:
+		private const UInt32 GENERIC_READ = 0x80000000;
+		private const UInt32 GENERIC_WRITE = 0x40000000;
+
+		//Constants for return value:
+		private const Int32 INVALID_HANDLE_VALUE = -1;
+
+		//Constants for dwFlagsAndAttributes:
+		private const UInt32 FILE_FLAG_OVERLAPPED = 0x40000000;
+		private const UInt32 FILE_FLAG_NO_BUFFERING = 0x20000000;
+
+		//Constants for dwCreationDisposition:
+		private const UInt32 OPEN_EXISTING = 3;
+
+		IntPtr		_handle;
+		FileAccess	_mode;
+
+		public NamedPipeStream(string host, FileAccess mode)
+		{
+			_handle = IntPtr.Zero;
+			Open(host, mode);
+		}
+
+		public void Open( string host, FileAccess mode )
+		{
+			_mode = mode;
+			uint pipemode = 0;
+
+			if ((mode & FileAccess.Read) > 0)
+				pipemode |= GENERIC_READ;
+			if ((mode & FileAccess.Write) > 0)
+				pipemode |= GENERIC_WRITE;
+			_handle = CreateFile( host, pipemode,
+				0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero );
+		}
+
+		public bool DataAvailable
+		{
+			get 
+			{
+				uint bytesRead=0, avail=0, thismsg=0;
+
+				bool result = PeekNamedPipe( _handle, 
+					null, 0, ref bytesRead, ref avail, ref thismsg );
+				return (result == true && avail > 0);
+			}
+	}
+
+		public override bool CanRead
+		{
+			get { return (_mode & FileAccess.Read) > 0; }
+		}
+
+		public override bool CanWrite
+		{
+			get { return (_mode & FileAccess.Write) > 0; }
+		}
+
+		public override bool CanSeek
+		{
+			get { throw new NotSupportedException("NamedPipeStream does not support seeking"); }
+		}
+
+		public override long Length
+		{
+			get { throw new NotSupportedException("NamedPipeStream does not support seeking"); }
+		}
+
+		public override long Position 
+		{
+			get { throw new NotSupportedException("NamedPipeStream does not support seeking"); }
+			set { }
+		}
+
+		public override void Flush() 
+		{
+			if (_handle == IntPtr.Zero)
+				throw new ObjectDisposedException("NamedPipeStream", "The stream has already been closed");
+			FlushFileBuffers(_handle);
+		}
+
+		public override int Read(byte[] buffer, int offset, int count)
+		{
+			if (buffer == null) 
+				throw new ArgumentNullException("buffer", "The buffer to read into cannot be null");
+			if (buffer.Length < (offset + count))
+				throw new ArgumentException("Buffer is not large enough to hold requested data", "buffer");
+			if (offset < 0) 
+				throw new ArgumentOutOfRangeException("offset", offset, "Offset cannot be negative");
+			if (count < 0)
+				throw new ArgumentOutOfRangeException("count", count, "Count cannot be negative");
+			if (! CanRead)
+				throw new NotSupportedException("The stream does not support reading");
+			if (_handle == IntPtr.Zero)
+				throw new ObjectDisposedException("NamedPipeStream", "The stream has already been closed");
+
+			// first read the data into an internal buffer since ReadFile cannot read into a buf at
+			// a specified offset
+			uint read=0;
+			byte[] buf = new Byte[count];
+			ReadFile( _handle, buf, (uint)count, ref read, IntPtr.Zero );
+			
+			for (int x=0; x < read; x++) 
+			{
+				buffer[offset+x] = buf[x];
+			}
+			return (int)read;
+		}
+
+		public override void Close()
+		{
+			CloseHandle(_handle);
+			_handle = IntPtr.Zero;
+		}
+
+		public override void SetLength(long length)
+		{
+			throw new NotSupportedException("NamedPipeStream doesn't support SetLength");
+		}
+
+		public override void Write(byte[] buffer, int offset, int count)
+		{
+			if (buffer == null) 
+				throw new ArgumentNullException("buffer", "The buffer to write into cannot be null");
+			if (buffer.Length < (offset + count))
+				throw new ArgumentException("Buffer does not contain amount of requested data", "buffer");
+			if (offset < 0) 
+				throw new ArgumentOutOfRangeException("offset", offset, "Offset cannot be negative");
+			if (count < 0)
+				throw new ArgumentOutOfRangeException("count", count, "Count cannot be negative");
+			if (! CanWrite)
+				throw new NotSupportedException("The stream does not support writing");
+			if (_handle == IntPtr.Zero)
+				throw new ObjectDisposedException("NamedPipeStream", "The stream has already been closed");
+			
+			// copy data to internal buffer to allow writing from a specified offset
+			byte[] buf = new Byte[count];
+			for (int x=0; x < count; x++) 
+			{
+				buf[x] = buffer[offset+x];
+			}
+			uint written=0;
+			bool result = WriteFile( _handle, buf, (uint)count, ref written, IntPtr.Zero );
+
+			if (! result)
+				throw new IOException("Writing to the stream failed");
+			if (written < count)
+				throw new IOException("Unable to write entire buffer to stream");
+		}
+
+		public override long Seek( long offset, SeekOrigin origin )
+		{
+			throw new NotSupportedException("NamedPipeStream doesn't support seeking");
+		}
+	}
+}
+
+

+ 25 - 0
mcs/class/ByteFX.Data/Common/Security.cs

@@ -0,0 +1,25 @@
+using System;
+
+namespace ByteFX.Data.Common
+{
+	/// <summary>
+	/// Summary description for Security.
+	/// </summary>
+	public class Security
+	{
+		public Security()
+		{
+		}
+
+		public static void ArrayCrypt( byte[] src, int srcoff, byte[] dst, int dstoff, byte[] key, int length )
+		{
+			int idx = 0;
+
+			while ( (idx+srcoff) < src.Length && idx < length )
+			{
+				dst[idx+dstoff] = (byte)(src[idx+srcoff] ^ key[idx]);
+				idx++;
+			}
+		}
+	}
+}

+ 244 - 0
mcs/class/ByteFX.Data/Common/SqlCommandEditorDlg.cs

@@ -0,0 +1,244 @@
+// ByteFX.Data data access components for .Net
+// Copyright (C) 2002-2003  ByteFX, Inc.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+using System;
+using System.Windows.Forms;
+using System.Data;
+using ByteFX.Data.MySqlClient;
+
+namespace ByteFX.Data.Common
+{
+	/// <summary>
+	/// Summary description for SqlCommandEditorDlg.
+	/// </summary>
+	internal class SqlCommandEditorDlg : System.Windows.Forms.Form
+	{
+		private System.Windows.Forms.TextBox		sqlText;
+		private System.Windows.Forms.Button			CancelBtn;
+		private System.Windows.Forms.Button			OKBtn;
+		private System.Windows.Forms.Panel			panel1;
+		private System.Windows.Forms.Splitter		splitter1;
+		private System.Windows.Forms.DataGrid		dataGrid;
+		private System.Windows.Forms.ContextMenu	sqlMenu;
+		private System.Windows.Forms.MenuItem		runMenuItem;
+		private	IDbCommand							command;
+		private System.Windows.Forms.DataGridTableStyle dataGridTableStyle1;
+
+		/// <summary>
+		/// Required designer variable.
+		/// </summary>
+		private System.ComponentModel.Container components = null;
+
+		public SqlCommandEditorDlg(object o)
+		{
+			command = (IDbCommand)o;
+
+			InitializeComponent();
+		}
+
+		/// <summary>
+		/// Clean up any resources being used.
+		/// </summary>
+		protected override void Dispose( bool disposing )
+		{
+			if( disposing )
+			{
+				if(components != null)
+				{
+					components.Dispose();
+				}
+			}
+			base.Dispose( disposing );
+		}
+
+		public string SQL 
+		{
+			get { return sqlText.Text; }
+			set { sqlText.Text = value; }
+		}
+
+		#region Windows Form Designer generated code
+		/// <summary>
+		/// Required method for Designer support - do not modify
+		/// the contents of this method with the code editor.
+		/// </summary>
+		private void InitializeComponent()
+		{
+			this.sqlText = new System.Windows.Forms.TextBox();
+			this.sqlMenu = new System.Windows.Forms.ContextMenu();
+			this.runMenuItem = new System.Windows.Forms.MenuItem();
+			this.CancelBtn = new System.Windows.Forms.Button();
+			this.OKBtn = new System.Windows.Forms.Button();
+			this.panel1 = new System.Windows.Forms.Panel();
+			this.splitter1 = new System.Windows.Forms.Splitter();
+			this.dataGrid = new System.Windows.Forms.DataGrid();
+			this.dataGridTableStyle1 = new System.Windows.Forms.DataGridTableStyle();
+			this.panel1.SuspendLayout();
+			((System.ComponentModel.ISupportInitialize)(this.dataGrid)).BeginInit();
+			this.SuspendLayout();
+			// 
+			// sqlText
+			// 
+			this.sqlText.ContextMenu = this.sqlMenu;
+			this.sqlText.Dock = System.Windows.Forms.DockStyle.Top;
+			this.sqlText.Location = new System.Drawing.Point(10, 10);
+			this.sqlText.Multiline = true;
+			this.sqlText.Name = "sqlText";
+			this.sqlText.Size = new System.Drawing.Size(462, 144);
+			this.sqlText.TabIndex = 0;
+			this.sqlText.Text = "";
+			// 
+			// sqlMenu
+			// 
+			this.sqlMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
+																					this.runMenuItem});
+			// 
+			// runMenuItem
+			// 
+			this.runMenuItem.Index = 0;
+			this.runMenuItem.Text = "Run";
+			this.runMenuItem.Click += new System.EventHandler(this.runMenuItem_Click);
+			// 
+			// CancelBtn
+			// 
+			this.CancelBtn.Anchor = (System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right);
+			this.CancelBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+			this.CancelBtn.Location = new System.Drawing.Point(400, 350);
+			this.CancelBtn.Name = "CancelBtn";
+			this.CancelBtn.TabIndex = 3;
+			this.CancelBtn.Text = "Cancel";
+			this.CancelBtn.Click += new System.EventHandler(this.CancelBtn_Click);
+			// 
+			// OKBtn
+			// 
+			this.OKBtn.Anchor = (System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right);
+			this.OKBtn.DialogResult = System.Windows.Forms.DialogResult.OK;
+			this.OKBtn.Location = new System.Drawing.Point(316, 350);
+			this.OKBtn.Name = "OKBtn";
+			this.OKBtn.TabIndex = 4;
+			this.OKBtn.Text = "OK";
+			this.OKBtn.Click += new System.EventHandler(this.OKBtn_Click);
+			// 
+			// panel1
+			// 
+			this.panel1.Anchor = (((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
+				| System.Windows.Forms.AnchorStyles.Left) 
+				| System.Windows.Forms.AnchorStyles.Right);
+			this.panel1.Controls.AddRange(new System.Windows.Forms.Control[] {
+																				 this.splitter1,
+																				 this.dataGrid,
+																				 this.sqlText});
+			this.panel1.DockPadding.Bottom = 10;
+			this.panel1.DockPadding.Left = 10;
+			this.panel1.DockPadding.Right = 14;
+			this.panel1.DockPadding.Top = 10;
+			this.panel1.Location = new System.Drawing.Point(2, 2);
+			this.panel1.Name = "panel1";
+			this.panel1.Size = new System.Drawing.Size(486, 344);
+			this.panel1.TabIndex = 5;
+			// 
+			// splitter1
+			// 
+			this.splitter1.Dock = System.Windows.Forms.DockStyle.Top;
+			this.splitter1.Location = new System.Drawing.Point(10, 154);
+			this.splitter1.Name = "splitter1";
+			this.splitter1.Size = new System.Drawing.Size(462, 3);
+			this.splitter1.TabIndex = 3;
+			this.splitter1.TabStop = false;
+			// 
+			// dataGrid
+			// 
+			this.dataGrid.CaptionVisible = false;
+			this.dataGrid.DataMember = "";
+			this.dataGrid.Dock = System.Windows.Forms.DockStyle.Fill;
+			this.dataGrid.HeaderForeColor = System.Drawing.SystemColors.ControlText;
+			this.dataGrid.Location = new System.Drawing.Point(10, 154);
+			this.dataGrid.Name = "dataGrid";
+			this.dataGrid.Size = new System.Drawing.Size(462, 180);
+			this.dataGrid.TabIndex = 2;
+			this.dataGrid.TableStyles.AddRange(new System.Windows.Forms.DataGridTableStyle[] {
+																								 this.dataGridTableStyle1});
+			// 
+			// dataGridTableStyle1
+			// 
+			this.dataGridTableStyle1.AllowSorting = false;
+			this.dataGridTableStyle1.DataGrid = this.dataGrid;
+			this.dataGridTableStyle1.HeaderForeColor = System.Drawing.SystemColors.ControlText;
+			this.dataGridTableStyle1.MappingName = "";
+			// 
+			// SqlCommandEditorDlg
+			// 
+			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
+			this.ClientSize = new System.Drawing.Size(486, 384);
+			this.ControlBox = false;
+			this.Controls.AddRange(new System.Windows.Forms.Control[] {
+																		  this.panel1,
+																		  this.OKBtn,
+																		  this.CancelBtn});
+			this.DockPadding.Bottom = 10;
+			this.DockPadding.Left = 10;
+			this.DockPadding.Right = 12;
+			this.DockPadding.Top = 10;
+			this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+			this.Name = "SqlCommandEditorDlg";
+			this.Text = "Query Builder";
+			this.panel1.ResumeLayout(false);
+			((System.ComponentModel.ISupportInitialize)(this.dataGrid)).EndInit();
+			this.ResumeLayout(false);
+
+		}
+		#endregion
+
+		private void CancelBtn_Click(object sender, System.EventArgs e)
+		{
+			this.Close();
+		}
+
+		private void OKBtn_Click(object sender, System.EventArgs e)
+		{
+			this.Close();
+		}
+
+		private void runMenuItem_Click(object sender, System.EventArgs e)
+		{
+			if (command is MySqlCommand)
+			{
+				RunMySql(); 
+			}
+		}
+
+		private void RunMySql() 
+		{
+			try 
+			{
+				MySqlDataAdapter da = new MySqlDataAdapter((MySqlCommand)command);
+				command.CommandText = sqlText.Text;
+				command.Connection.Open();
+				DataTable dt = new DataTable();
+				da.Fill(dt);
+				dataGrid.DataSource = dt;
+				command.Connection.Close();
+				dataGrid.Expand(-1);
+			}
+			catch (Exception ex) 
+			{
+				MessageBox.Show(ex.Message);
+			}
+		}
+
+	}
+}

+ 105 - 0
mcs/class/ByteFX.Data/Common/SqlCommandEditorDlg.resx

@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+            Microsoft ResX Schema 
+        
+            Version 1.3
+                
+            The primary goals of this format is to allow a simple XML format 
+            that is mostly human readable. The generation and parsing of the 
+            various data types are done through the TypeConverter classes 
+            associated with the data types.
+        
+            Example:
+        
+                ... ado.net/XML headers & schema ...
+                <resheader name="resmimetype">text/microsoft-resx</resheader>
+                <resheader name="version">1.3</resheader>
+                <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+                <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+                <data name="Name1">this is my long string</data>
+                <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+                <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+                    [base64 mime encoded serialized .NET Framework object]
+                </data>
+                <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+                    [base64 mime encoded string representing a byte array form of the .NET Framework object]
+                </data>
+        
+            There are any number of "resheader" rows that contain simple 
+            name/value pairs.
+            
+            Each data row contains a name, and value. The row also contains a 
+            type or mimetype. Type corresponds to a .NET class that support 
+            text/value conversion through the TypeConverter architecture. 
+            Classes that don't support this are serialized and stored with the 
+            mimetype set.
+                     
+            The mimetype is used for serialized objects, and tells the 
+            ResXResourceReader how to depersist the object. This is currently not 
+            extensible. For a given mimetype the value must be set accordingly:
+        
+            Note - application/x-microsoft.net.object.binary.base64 is the format 
+                   that the ResXResourceWriter will generate, however the reader can 
+                   read any of the formats listed below.
+        
+            mimetype: application/x-microsoft.net.object.binary.base64
+            value   : The object must be serialized with 
+                    : System.Serialization.Formatters.Binary.BinaryFormatter
+                    : and then encoded with base64 encoding.
+        
+            mimetype: application/x-microsoft.net.object.soap.base64
+            value   : The object must be serialized with 
+                    : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+                    : and then encoded with base64 encoding.
+            mimetype: application/x-microsoft.net.object.bytearray.base64
+            value   : The object must be serialized into a byte array 
+                    : using a System.ComponentModel.TypeConverter
+                    : and then encoded with base64 encoding.
+        -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>1.3</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <data name="sqlMenu.Location" type="System.Drawing.Point, System.Drawing, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>17, 17</value>
+  </data>
+  <data name="$this.Name">
+    <value>SqlCommandEditorDlg</value>
+  </data>
+</root>

+ 63 - 0
mcs/class/ByteFX.Data/Common/SqlCommandTextEditor.cs

@@ -0,0 +1,63 @@
+// ByteFX.Data data access components for .Net
+// Copyright (C) 2002-2003  ByteFX, Inc.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+#if WINDOWS
+using System;
+using System.Windows.Forms;
+using System.Drawing.Design;
+
+namespace ByteFX.Data.Common
+{
+	/// <summary>
+	/// Summary description for MySqlConnectionDesign.
+	/// </summary>
+	public class SqlCommandTextEditor : UITypeEditor
+	{
+		public override System.Drawing.Design.UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
+		{
+			return System.Drawing.Design.UITypeEditorEditStyle.Modal;
+		}
+
+		public override bool GetPaintValueSupported(System.ComponentModel.ITypeDescriptorContext context)
+		{
+			return false;
+		}
+
+		public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, System.IServiceProvider provider, object value)
+		{
+			System.Data.IDbCommand command = (System.Data.IDbCommand)context.Instance;
+
+			if (command.Connection == null) 
+			{
+				MessageBox.Show("Connection property not set to a valid connection.\n"+
+					"Please set and try again", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+				return value;
+			}
+
+			SqlCommandEditorDlg dlg = new SqlCommandEditorDlg( command );
+
+			dlg.SQL = (string)value;
+			if(dlg.ShowDialog() == DialogResult.OK)
+			{
+				return dlg.SQL;
+			}
+			else
+				return value;
+		}
+	}
+}
+#endif

+ 64 - 0
mcs/class/ByteFX.Data/Common/StringUtility.cs

@@ -0,0 +1,64 @@
+// ByteFX.Data data access components for .Net
+// Copyright (C) 2002-2003  ByteFX, Inc.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+using System;
+using System.Text;
+using System.Collections;
+using System.Collections.Specialized;
+
+namespace ByteFX.Data.Common
+{
+	/// <summary>
+	/// Summary description for StringUtility.
+	/// </summary>
+	public class StringUtility
+	{
+		public StringUtility()
+		{
+		}
+
+		public static string[] Split( string src, char delimiter, char[] quotedelims )
+		{
+			ArrayList		strings = new ArrayList();
+			StringBuilder	sb = new StringBuilder();
+			ArrayList		ar = new ArrayList(quotedelims);
+			char			quote_open = Char.MinValue;
+
+			src += ";";
+			foreach (char c in src) 
+			{
+				if (c == delimiter && quote_open == Char.MinValue) 
+				{
+					strings.Add( sb.ToString() );
+					sb.Remove( 0, sb.Length );
+				}
+					
+				else if (ar.Contains(c)) 
+				{
+					if (quote_open == Char.MinValue)
+						quote_open = c;
+					else if (quote_open == c)
+						quote_open = Char.MinValue;
+					sb.Append(c);
+				}
+				else
+					sb.Append( c );
+			}
+			return (string[])strings.ToArray(typeof(System.String));
+		}
+	}
+}

+ 51 - 0
mcs/class/ByteFX.Data/Common/Version.cs

@@ -0,0 +1,51 @@
+using System;
+
+namespace ByteFX.Data.Common
+{
+	/// <summary>
+	/// Summary description for Version.
+	/// </summary>
+	public struct Version
+	{
+		private int	major;
+		private int minor;
+		private int build;
+
+		public Version( int major, int minor, int build)
+		{
+			this.major = major;
+			this.minor = minor;
+			this.build = build;
+		}
+
+		public static Version Parse( string versionString )
+		{
+			int start = 0;
+			int index = versionString.IndexOf('.', start);
+			if (index == -1) throw new Exception("Version string not in acceptable format");
+			int major = Convert.ToInt32( versionString.Substring(start, index-start).Trim());
+
+			start = index+1;
+			index = versionString.IndexOf('.', start);
+			if (index == -1) throw new Exception("Version string not in acceptable format");
+			int minor = Convert.ToInt32( versionString.Substring(start, index-start).Trim());
+
+			start = index+1;
+			int i = start;
+			while (i < versionString.Length && Char.IsDigit( versionString, i ))
+				i++;
+			int build = Convert.ToInt32( versionString.Substring(start, i-start).Trim());
+
+			return new Version( major, minor, build );
+		}
+
+		public bool isAtLeast(int major, int minor, int build)
+		{
+			if (major > this.major) return false;
+			if (minor > this.minor) return false;
+			if (build > this.build) return false;
+			return true;
+		}
+
+	}
+}

+ 5 - 1
mcs/class/ByteFX.Data/Makefile

@@ -4,7 +4,11 @@ include ../../build/rules.make
 
 LIBRARY = ByteFX.Data.dll
 LIB_MCS_FLAGS = /r:$(corlib) /r:System.dll /r:System.Xml.dll \
-	/r:System.Data.dll /r:ICSharpCode.SharpZipLib.dll
+	/r:System.Data.dll /r:ICSharpCode.SharpZipLib.dll \
+	/r:System.Design.dll /r:System.Drawing.dll /r:System.Windows.Forms.dll \
+	/res:mysqlclient/Designers/command.bmp \
+	/res:mysqlclient/Designers/connection.bmp \
+	/res:mysqlclient/Designers/dataadapter.bmp
 NO_TEST = yes
 EXTRA_DISTFILES = ChangeLog.txt lgpl.txt readme.txt
 

+ 88 - 0
mcs/class/ByteFX.Data/mysqlclient/CharSetMap.cs

@@ -0,0 +1,88 @@
+using System;
+using System.Text;
+using System.Collections;
+
+namespace ByteFX.Data.MySqlClient
+{
+	/// <summary>
+	/// Summary description for CharSetMap.
+	/// </summary>
+	public class CharSetMap
+	{
+		private static Hashtable mapping;
+
+		/// <summary>
+		/// 
+		/// </summary>
+		/// <param name="MySqlCharSetName"></param>
+		/// <returns></returns>
+		public static Encoding GetEncoding( string MySqlCharSetName ) 
+		{
+			if (mapping == null )
+				InitializeMapping();
+			try 
+			{
+				int cpid = (int)mapping[ MySqlCharSetName ];
+				return Encoding.GetEncoding( cpid );
+			}
+			catch (System.NotSupportedException) 
+			{
+				return Encoding.GetEncoding(0);
+			}
+		}
+
+		/// <summary>
+		/// 
+		/// </summary>
+		private static void InitializeMapping() 
+		{
+			mapping = new Hashtable();
+
+			// relatively sure about
+			mapping.Add( "default", 0 );
+			mapping.Add( "big5", 950 );			// Traditional Chinese
+			mapping.Add( "latin1", 28591 );		// Latin alphabet #1
+			mapping.Add( "utf8", 65001 );
+			mapping.Add( "ucs2", 1200 );
+			mapping.Add( "latin2", 28592 );
+			mapping.Add( "latin4", 28594 );
+			mapping.Add( "latin3", 28593 );
+			mapping.Add( "latin5", 1254 );
+			mapping.Add( "cp1251", 1251 );		// Russian
+			mapping.Add( "win1251", 1251 );
+			mapping.Add( "hebrew", 1255 );		// Hebrew
+			mapping.Add( "greek", 1253 );		// Greek
+			mapping.Add( "sjis", 932 );			// Shift-JIS
+			mapping.Add( "gbk", 936 );			// Simplified Chinese
+			mapping.Add( "cp866", 866 );
+			mapping.Add( "euc_kr", 949 );
+
+			// maybe, maybe not...
+			mapping.Add( "win1250", 1250 );		// Central Eurpoe
+			mapping.Add( "win1251ukr", 1251 );
+			mapping.Add( "latin1_de", 1252 );	// Latin1 German
+			mapping.Add( "german1", 1252 );		// German
+			mapping.Add( "danish", 1252 );		// Danish
+			mapping.Add( "dos", 437 );			// Dos
+			mapping.Add( "pclatin2", 852 );		
+			mapping.Add( "win1250ch", 1250 );
+			mapping.Add( "cp1257", 1257 );
+			mapping.Add( "usa7", 646 );
+			mapping.Add( "czech", 912 );
+			mapping.Add( "hungarian", 912 );
+			mapping.Add( "croat", 912 );
+
+/*			("gb2312", "EUC_CN");
+			("ujis", "EUC_JP");
+			("latvian", "ISO8859_13");
+			("latvian1", "ISO8859_13");
+			("estonia", "ISO8859_13");
+			("koi8_ru", "KOI8_R");
+			("tis620", "TIS620");
+			("macroman", "MacRoman");
+			("macce", "MacCentralEurope");
+*/
+
+		}
+	}
+}

+ 382 - 374
mcs/class/ByteFX.Data/mysqlclient/CommandBuilder.cs

@@ -1,374 +1,382 @@
-// ByteFX.Data data access components for .Net
-// Copyright (C) 2002-2003  ByteFX, Inc.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-using System;
-using System.ComponentModel;
-using System.Data;
-using System.Text;
-
-namespace ByteFX.Data.MySQLClient
-{
-	/// <summary>
-	/// Summary description for CommandBuilder.
-	/// </summary>
-	[ToolboxItem(false)]
-	public sealed class MySQLCommandBuilder : Component
-	{
-		private MySQLDataAdapter	_adapter;
-		private string				_QuotePrefix;
-		private string				_QuoteSuffix;
-		private DataTable			_schema;
-		private string				_tableName;
-
-		private	MySQLCommand		_updateCmd;
-		private MySQLCommand		_insertCmd;
-		private MySQLCommand		_deleteCmd;
-
-		#region Constructors
-		public MySQLCommandBuilder()
-		{
-		}
-
-		public MySQLCommandBuilder( MySQLDataAdapter adapter )
-		{
-			_adapter = adapter;
-			_adapter.RowUpdating += new MySQLRowUpdatingEventHandler( OnRowUpdating );
-		}
-		#endregion
-
-		#region Properties
-		public MySQLDataAdapter DataAdapter 
-		{
-			get { return _adapter; }
-			set 
-			{ 
-				if (_adapter != null) 
-				{
-					_adapter.RowUpdating -= new MySQLRowUpdatingEventHandler( OnRowUpdating );
-				}
-				_adapter = value; 
-			}
-		}
-
-		public string QuotePrefix 
-		{
-			get { return _QuotePrefix; }
-			set { _QuotePrefix = value; }
-		}
-
-		public string QuoteSuffix
-		{
-			get { return _QuoteSuffix; }
-			set { _QuoteSuffix = value; }
-		}
-
-		#endregion
-
-		#region Public Methods
-		public static void DeriveParameters(MySQLCommand command)
-		{
-			throw new MySQLException("DeriveParameters is not supported (due to MySQL not supporting SP)");
-		}
-
-		public MySQLCommand GetDeleteCommand()
-		{
-			if (_schema == null)
-				GenerateSchema();
-			return CreateDeleteCommand();
-		}
-
-		public MySQLCommand GetInsertCommand()
-		{
-			if (_schema == null)
-				GenerateSchema();
-			return CreateInsertCommand();
-		}
-
-		public MySQLCommand GetUpdateCommand() 
-		{
-			if (_schema == null)
-				GenerateSchema();
-			return CreateUpdateCommand();
-		}
-
-		public void RefreshSchema()
-		{
-			_schema = null;
-			_insertCmd = null;
-			_deleteCmd = null;
-			_updateCmd = null;
-		}
-		#endregion
-
-		#region Private Methods
-
-		private void GenerateSchema()
-		{
-			if (_adapter == null)
-				throw new MySQLException("Improper MySQLCommandBuilder state: adapter is null");
-			if (_adapter.SelectCommand == null)
-				throw new MySQLException("Improper MySQLCommandBuilder state: adapter's SelectCommand is null");
-
-			MySQLDataReader dr = _adapter.SelectCommand.ExecuteReader(CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo);
-			_schema = dr.GetSchemaTable();
-			dr.Close();
-
-			// make sure we got at least one unique or key field and count base table names
-			bool   hasKeyOrUnique=false;
-
-			foreach (DataRow row in _schema.Rows)
-			{
-				if (true == (bool)row["IsKey"] || true == (bool)row["IsUnique"])
-					hasKeyOrUnique=true;
-				if (_tableName == null)
-					_tableName = (string)row["BaseTableName"];
-				else if (_tableName != (string)row["BaseTableName"])
-					throw new InvalidOperationException("MySQLCommandBuilder does not support multi-table statements");
-			}
-			if (! hasKeyOrUnique)
-				throw new InvalidOperationException("MySQLCommandBuilder cannot operate on tables with no unique or key columns");
-		}
-
-		private string Quote(string table_or_column)
-		{
-			if (_QuotePrefix == null || _QuoteSuffix == null)
-				return table_or_column;
-			return _QuotePrefix + table_or_column + _QuoteSuffix;
-		}
-
-		private MySQLParameter CreateParameter(DataRow row, bool Original)
-		{
-			MySQLParameter p;
-			if (Original)
-				p = new MySQLParameter( "@Original_" + (string)row["ColumnName"], (MySQLDbType)row["ProviderType"],
-					ParameterDirection.Input, (string)row["ColumnName"], DataRowVersion.Original, null );
-			else
-				p = new MySQLParameter( "@" + (string)row["ColumnName"], (MySQLDbType)row["ProviderType"],
-					(string)row["ColumnName"]);
-			return p;
-		}
-
-		private MySQLCommand CreateBaseCommand()
-		{
-			MySQLCommand cmd = new MySQLCommand();
-			cmd.Connection = _adapter.SelectCommand.Connection;
-			cmd.CommandTimeout = _adapter.SelectCommand.CommandTimeout;
-			cmd.Transaction = _adapter.SelectCommand.Transaction;
-			return cmd;
-		}
-
-		private MySQLCommand CreateDeleteCommand()
-		{
-			if (_deleteCmd != null) return _deleteCmd;
-
-			MySQLCommand cmd = CreateBaseCommand();
-
-			cmd.CommandText = "DELETE FROM " + Quote(_tableName) + 
-				" WHERE " + CreateOriginalWhere(cmd);
-
-			_deleteCmd = cmd;
-			return cmd;
-		}
-
-		private string CreateFinalSelect(bool forinsert)
-		{
-			StringBuilder sel = new StringBuilder();
-			StringBuilder where = new StringBuilder();
-
-			foreach (DataRow row in _schema.Rows)
-			{
-				string colname = (string)row["ColumnName"];
-				if (sel.Length > 0)
-					sel.Append(", ");
-				sel.Append( colname );
-				if ((bool)row["IsKey"] == false) continue;
-				if (where.Length > 0)
-					where.Append(" AND ");
-				where.Append( "(" + colname + "=" );
-				if ((bool)row["IsAutoIncrement"] && forinsert)
-					where.Append("last_insert_id()");
-				else
-					where.Append("@Original_" + colname);
-				where.Append(")");
-			}
-			return "SELECT " + sel.ToString() + " FROM " + Quote(_tableName) +
-				   " WHERE " + where.ToString();
-		}
-
-		private string CreateOriginalWhere(MySQLCommand cmd)
-		{
-			StringBuilder wherestr = new StringBuilder();
-
-			foreach (DataRow row in _schema.Rows)
-			{
-				if (! IncludedInWhereClause(row)) continue;
-
-				// first update the where clause since it will contain all parameters
-				if (wherestr.Length > 0)
-					wherestr.Append(" AND ");
-				string colname = Quote((string)row["ColumnName"]);
-
-				MySQLParameter op = CreateParameter(row, true);
-				cmd.Parameters.Add(op);
-
-				wherestr.Append( "(" + colname + "=" + op.ParameterName);
-				if ((bool)row["AllowDBNull"] == true) 
-					wherestr.Append( " or " + colname + " is null and " + op.ParameterName + " is null");
-				wherestr.Append(")");
-			}
-			return wherestr.ToString();
-		}
-
-		private MySQLCommand CreateUpdateCommand()
-		{
-			if (_updateCmd != null) return _updateCmd; 
-
-			MySQLCommand cmd = CreateBaseCommand();
-
-			StringBuilder setstr = new StringBuilder();
-		
-			foreach (DataRow schemaRow in _schema.Rows)
-			{
-				string colname = Quote((string)schemaRow["ColumnName"]);
-
-				if (! IncludedInUpdate(schemaRow)) continue;
-
-				if (setstr.Length > 0) 
-					setstr.Append(", ");
-
-				MySQLParameter p = CreateParameter(schemaRow, false);
-				cmd.Parameters.Add(p);
-
-				setstr.Append( colname + "=" + p.ParameterName );
-			}
-
-			cmd.CommandText = "UPDATE " + Quote(_tableName) + " SET " + setstr.ToString() + 
-							  " WHERE " + CreateOriginalWhere(cmd);
-			cmd.CommandText += "; " + CreateFinalSelect(false);
-
-			_updateCmd = cmd;
-			return cmd;
-		}
-
-		private MySQLCommand CreateInsertCommand()
-		{
-			if (_insertCmd != null) return _insertCmd;
-
-			MySQLCommand cmd = CreateBaseCommand();
-
-			StringBuilder setstr = new StringBuilder();
-			StringBuilder valstr = new StringBuilder();
-			foreach (DataRow schemaRow in _schema.Rows)
-			{
-				string colname = Quote((string)schemaRow["ColumnName"]);
-
-				if (!IncludedInInsert(schemaRow)) continue;
-
-				if (setstr.Length > 0) 
-				{
-					setstr.Append(", ");
-					valstr.Append(", ");
-				}
-
-				MySQLParameter p = CreateParameter(schemaRow, false);
-				cmd.Parameters.Add(p);
-
-				setstr.Append( colname );
-				valstr.Append( p.ParameterName );
-			}
-
-			cmd.CommandText = "INSERT INTO " + Quote(_tableName) + " (" + setstr.ToString() + ") " +
-				" VALUES (" + valstr.ToString() + ")";
-			cmd.CommandText += "; " + CreateFinalSelect(true);
-
-			_insertCmd = cmd;
-			return cmd;
-		}
-
-		private bool IncludedInInsert (DataRow schemaRow)
-		{
-			// If the parameter has one of these properties, then we don't include it in the insert:
-			// AutoIncrement, Hidden, Expression, RowVersion, ReadOnly
-
-			if ((bool) schemaRow ["IsAutoIncrement"])
-				return false;
-/*			if ((bool) schemaRow ["IsHidden"])
-				return false;
-			if ((bool) schemaRow ["IsExpression"])
-				return false;*/
-			if ((bool) schemaRow ["IsRowVersion"])
-				return false;
-			if ((bool) schemaRow ["IsReadOnly"])
-				return false;
-			return true;
-		}
-
-		private bool IncludedInUpdate (DataRow schemaRow)
-		{
-			// If the parameter has one of these properties, then we don't include it in the insert:
-			// AutoIncrement, Hidden, RowVersion
-
-			if ((bool) schemaRow ["IsAutoIncrement"])
-				return false;
-//			if ((bool) schemaRow ["IsHidden"])
-//				return false;
-			if ((bool) schemaRow ["IsRowVersion"])
-				return false;
-			return true;
-		}
-
-		private bool IncludedInWhereClause (DataRow schemaRow)
-		{
-			if ((bool) schemaRow ["IsLong"])
-				return false;
-			return true;
-		}
-
-		private void SetParameterValues(MySQLCommand cmd, DataRow dataRow)
-		{
-			foreach (MySQLParameter p in cmd.Parameters)
-			{
-				if (p.ParameterName.Length >= 9 && p.ParameterName.Substring(0, 9).Equals("@Original"))
-					p.Value = dataRow[ p.SourceColumn, DataRowVersion.Original ];
-				else
-					p.Value = dataRow[ p.SourceColumn, DataRowVersion.Current ];
-			}
-		}
-
-		private void OnRowUpdating(object sender, MySQLRowUpdatingEventArgs args)
-		{
-			// make sure we are still to proceed
-			if (args.Status != UpdateStatus.Continue) return;
-
-			if (_schema == null)
-				GenerateSchema();
-
-			if (StatementType.Delete == args.StatementType)
-				args.Command = CreateDeleteCommand();
-			else if (StatementType.Update == args.StatementType)
-				args.Command = CreateUpdateCommand();
-			else if (StatementType.Insert == args.StatementType)
-				args.Command = CreateInsertCommand();
-			else if (StatementType.Select == args.StatementType)
-				return;
-
-			SetParameterValues(args.Command, args.Row);
-		}
-		#endregion
-
-	}
-}
+// ByteFX.Data data access components for .Net
+// Copyright (C) 2002-2003  ByteFX, Inc.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+using System;
+using System.ComponentModel;
+using System.Data;
+using System.Text;
+
+namespace ByteFX.Data.MySqlClient
+{
+	/// <summary>
+	/// Summary description for CommandBuilder.
+	/// </summary>
+	[ToolboxItem(false)]
+	[System.ComponentModel.DesignerCategory("Code")]
+	public sealed class MySqlCommandBuilder : Component
+	{
+		private MySqlDataAdapter	_adapter;
+		private string				_QuotePrefix;
+		private string				_QuoteSuffix;
+		private DataTable			_schema;
+		private string				_tableName;
+
+		private	MySqlCommand		_updateCmd;
+		private MySqlCommand		_insertCmd;
+		private MySqlCommand		_deleteCmd;
+
+		#region Constructors
+		public MySqlCommandBuilder()
+		{
+		}
+
+		public MySqlCommandBuilder( MySqlDataAdapter adapter )
+		{
+			_adapter = adapter;
+			_adapter.RowUpdating += new MySqlRowUpdatingEventHandler( OnRowUpdating );
+		}
+		#endregion
+
+		#region Properties
+		public MySqlDataAdapter DataAdapter 
+		{
+			get { return _adapter; }
+			set 
+			{ 
+				if (_adapter != null) 
+				{
+					_adapter.RowUpdating -= new MySqlRowUpdatingEventHandler( OnRowUpdating );
+				}
+				_adapter = value; 
+			}
+		}
+
+		public string QuotePrefix 
+		{
+			get { return _QuotePrefix; }
+			set { _QuotePrefix = value; }
+		}
+
+		public string QuoteSuffix
+		{
+			get { return _QuoteSuffix; }
+			set { _QuoteSuffix = value; }
+		}
+
+		#endregion
+
+		#region Public Methods
+		public static void DeriveParameters(MySqlCommand command)
+		{
+			throw new MySqlException("DeriveParameters is not supported (due to MySql not supporting SP)");
+		}
+
+		public MySqlCommand GetDeleteCommand()
+		{
+			if (_schema == null)
+				GenerateSchema();
+			return CreateDeleteCommand();
+		}
+
+		public MySqlCommand GetInsertCommand()
+		{
+			if (_schema == null)
+				GenerateSchema();
+			return CreateInsertCommand();
+		}
+
+		public MySqlCommand GetUpdateCommand() 
+		{
+			if (_schema == null)
+				GenerateSchema();
+			return CreateUpdateCommand();
+		}
+
+		public void RefreshSchema()
+		{
+			_schema = null;
+			_insertCmd = null;
+			_deleteCmd = null;
+			_updateCmd = null;
+		}
+		#endregion
+
+		#region Private Methods
+
+		private void GenerateSchema()
+		{
+			if (_adapter == null)
+				throw new MySqlException("Improper MySqlCommandBuilder state: adapter is null");
+			if (_adapter.SelectCommand == null)
+				throw new MySqlException("Improper MySqlCommandBuilder state: adapter's SelectCommand is null");
+
+			MySqlDataReader dr = _adapter.SelectCommand.ExecuteReader(CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo);
+			_schema = dr.GetSchemaTable();
+			dr.Close();
+
+			// make sure we got at least one unique or key field and count base table names
+			bool   hasKeyOrUnique=false;
+
+			foreach (DataRow row in _schema.Rows)
+			{
+				if (true == (bool)row["IsKey"] || true == (bool)row["IsUnique"])
+					hasKeyOrUnique=true;
+				if (_tableName == null)
+					_tableName = (string)row["BaseTableName"];
+				else if (_tableName != (string)row["BaseTableName"])
+					throw new InvalidOperationException("MySqlCommandBuilder does not support multi-table statements");
+			}
+			if (! hasKeyOrUnique)
+				throw new InvalidOperationException("MySqlCommandBuilder cannot operate on tables with no unique or key columns");
+		}
+
+		private string Quote(string table_or_column)
+		{
+			if (_QuotePrefix == null || _QuoteSuffix == null)
+				return table_or_column;
+			return _QuotePrefix + table_or_column + _QuoteSuffix;
+		}
+
+		private MySqlParameter CreateParameter(DataRow row, bool Original)
+		{
+			MySqlParameter p;
+			if (Original)
+				p = new MySqlParameter( "@Original_" + (string)row["ColumnName"], (MySqlDbType)row["ProviderType"],
+					ParameterDirection.Input, (string)row["ColumnName"], DataRowVersion.Original, DBNull.Value );
+			else
+				p = new MySqlParameter( "@" + (string)row["ColumnName"], (MySqlDbType)row["ProviderType"],
+					ParameterDirection.Input, (string)row["ColumnName"], DataRowVersion.Current, DBNull.Value );
+			return p;
+		}
+
+		private MySqlCommand CreateBaseCommand()
+		{
+			MySqlCommand cmd = new MySqlCommand();
+			cmd.Connection = _adapter.SelectCommand.Connection;
+			cmd.CommandTimeout = _adapter.SelectCommand.CommandTimeout;
+			cmd.Transaction = _adapter.SelectCommand.Transaction;
+			return cmd;
+		}
+
+		private MySqlCommand CreateDeleteCommand()
+		{
+			if (_deleteCmd != null) return _deleteCmd;
+
+			MySqlCommand cmd = CreateBaseCommand();
+
+			cmd.CommandText = "DELETE FROM " + Quote(_tableName) + 
+				" WHERE " + CreateOriginalWhere(cmd);
+
+			_deleteCmd = cmd;
+			return cmd;
+		}
+
+		private string CreateFinalSelect(bool forinsert)
+		{
+			StringBuilder sel = new StringBuilder();
+			StringBuilder where = new StringBuilder();
+
+			foreach (DataRow row in _schema.Rows)
+			{
+				string colname = (string)row["ColumnName"];
+				if (sel.Length > 0)
+					sel.Append(", ");
+				sel.Append( colname );
+				if ((bool)row["IsKey"] == false) continue;
+				if (where.Length > 0)
+					where.Append(" AND ");
+				where.Append( "(" + colname + "=" );
+				if (forinsert) 
+				{
+					if ((bool)row["IsAutoIncrement"])
+						where.Append("last_insert_id()");
+					else if ((bool)row["IsKey"])
+						where.Append("@" + colname);
+				}
+				else 
+				{
+					where.Append("@Original_" + colname);
+				}
+				where.Append(")");
+			}
+			return "SELECT " + sel.ToString() + " FROM " + Quote(_tableName) +
+				   " WHERE " + where.ToString();
+		}
+
+		private string CreateOriginalWhere(MySqlCommand cmd)
+		{
+			StringBuilder wherestr = new StringBuilder();
+
+			foreach (DataRow row in _schema.Rows)
+			{
+				if (! IncludedInWhereClause(row)) continue;
+
+				// first update the where clause since it will contain all parameters
+				if (wherestr.Length > 0)
+					wherestr.Append(" AND ");
+				string colname = Quote((string)row["ColumnName"]);
+
+				MySqlParameter op = CreateParameter(row, true);
+				cmd.Parameters.Add(op);
+
+				wherestr.Append( "(" + colname + "=@" + op.ParameterName);
+				if ((bool)row["AllowDBNull"] == true) 
+					wherestr.Append( " or (" + colname + " IS NULL and @" + op.ParameterName + " IS NULL)");
+				wherestr.Append(")");
+			}
+			return wherestr.ToString();
+		}
+
+		private MySqlCommand CreateUpdateCommand()
+		{
+			if (_updateCmd != null) return _updateCmd; 
+
+			MySqlCommand cmd = CreateBaseCommand();
+
+			StringBuilder setstr = new StringBuilder();
+		
+			foreach (DataRow schemaRow in _schema.Rows)
+			{
+				string colname = Quote((string)schemaRow["ColumnName"]);
+
+				if (! IncludedInUpdate(schemaRow)) continue;
+
+				if (setstr.Length > 0) 
+					setstr.Append(", ");
+
+				MySqlParameter p = CreateParameter(schemaRow, false);
+				cmd.Parameters.Add(p);
+
+				setstr.Append( colname + "=@" + p.ParameterName );
+			}
+
+			cmd.CommandText = "UPDATE " + Quote(_tableName) + " SET " + setstr.ToString() + 
+							  " WHERE " + CreateOriginalWhere(cmd);
+			cmd.CommandText += "; " + CreateFinalSelect(false);
+
+			_updateCmd = cmd;
+			return cmd;
+		}
+
+		private MySqlCommand CreateInsertCommand()
+		{
+			if (_insertCmd != null) return _insertCmd;
+
+			MySqlCommand cmd = CreateBaseCommand();
+
+			StringBuilder setstr = new StringBuilder();
+			StringBuilder valstr = new StringBuilder();
+			foreach (DataRow schemaRow in _schema.Rows)
+			{
+				string colname = Quote((string)schemaRow["ColumnName"]);
+
+				if (!IncludedInInsert(schemaRow)) continue;
+
+				if (setstr.Length > 0) 
+				{
+					setstr.Append(", ");
+					valstr.Append(", ");
+				}
+
+				MySqlParameter p = CreateParameter(schemaRow, false);
+				cmd.Parameters.Add(p);
+
+				setstr.Append( colname );
+				valstr.Append( "@" + p.ParameterName );
+			}
+
+			cmd.CommandText = "INSERT INTO " + Quote(_tableName) + " (" + setstr.ToString() + ") " +
+				" VALUES (" + valstr.ToString() + ")";
+			cmd.CommandText += "; " + CreateFinalSelect(true);
+
+			_insertCmd = cmd;
+			return cmd;
+		}
+
+		private bool IncludedInInsert (DataRow schemaRow)
+		{
+			// If the parameter has one of these properties, then we don't include it in the insert:
+			// AutoIncrement, Hidden, Expression, RowVersion, ReadOnly
+
+			if ((bool) schemaRow ["IsAutoIncrement"])
+				return false;
+/*			if ((bool) schemaRow ["IsHidden"])
+				return false;
+			if ((bool) schemaRow ["IsExpression"])
+				return false;*/
+			if ((bool) schemaRow ["IsRowVersion"])
+				return false;
+			if ((bool) schemaRow ["IsReadOnly"])
+				return false;
+			return true;
+		}
+
+		private bool IncludedInUpdate (DataRow schemaRow)
+		{
+			// If the parameter has one of these properties, then we don't include it in the insert:
+			// AutoIncrement, Hidden, RowVersion
+
+			if ((bool) schemaRow ["IsAutoIncrement"])
+				return false;
+//			if ((bool) schemaRow ["IsHidden"])
+//				return false;
+			if ((bool) schemaRow ["IsRowVersion"])
+				return false;
+			return true;
+		}
+
+		private bool IncludedInWhereClause (DataRow schemaRow)
+		{
+//			if ((bool) schemaRow ["IsLong"])
+//				return false;
+			return true;
+		}
+
+		private void SetParameterValues(MySqlCommand cmd, DataRow dataRow)
+		{
+			foreach (MySqlParameter p in cmd.Parameters)
+			{
+				if (p.ParameterName.Length >= 8 && p.ParameterName.Substring(0, 8).Equals("Original"))
+					p.Value = dataRow[ p.SourceColumn, DataRowVersion.Original ];
+				else
+					p.Value = dataRow[ p.SourceColumn, DataRowVersion.Current ];
+			}
+		}
+
+		private void OnRowUpdating(object sender, MySqlRowUpdatingEventArgs args)
+		{
+			// make sure we are still to proceed
+			if (args.Status != UpdateStatus.Continue) return;
+
+			if (_schema == null)
+				GenerateSchema();
+
+			if (StatementType.Delete == args.StatementType)
+				args.Command = CreateDeleteCommand();
+			else if (StatementType.Update == args.StatementType)
+				args.Command = CreateUpdateCommand();
+			else if (StatementType.Insert == args.StatementType)
+				args.Command = CreateInsertCommand();
+			else if (StatementType.Select == args.StatementType)
+				return;
+
+			SetParameterValues(args.Command, args.Row);
+		}
+		#endregion
+
+	}
+}

+ 338 - 257
mcs/class/ByteFX.Data/mysqlclient/Connection.cs

@@ -1,257 +1,338 @@
-// ByteFX.Data data access components for .Net
-// Copyright (C) 2002-2003  ByteFX, Inc.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-using System;
-using System.Data;
-using System.Collections.Specialized;
-using System.ComponentModel;
-
-namespace ByteFX.Data.MySQLClient
-{
-	/// <summary>
-	/// Summary description for MySQLConnection.
-	/// </summary>
-#if WINDOWS
-	[System.Drawing.ToolboxBitmap( typeof(MySQLConnection), "Designers.connection.bmp")]
-#endif
-	[ToolboxItem(true)]
-	public sealed class MySQLConnection : Common.Connection, IDbConnection, ICloneable
-	{
-		Driver				m_Driver;
-
-		// Always have a default constructor.
-		public MySQLConnection()
-		{
-			ConnectionString = "data source=localhost;user id=root;pwd=;database=mysql";
-		}
-
-		public MySQLConnection(System.ComponentModel.IContainer container)
-		{
-			ConnectionString = "data source=localhost;user id=root;pwd=;database=mysql";
-		}
-    
-
-		// Have a constructor that takes a connection string.
-		public MySQLConnection(string sConnString)
-		{
-			ConnectionString = sConnString;
-			Init();
-		}
-
-		public new void Dispose()
-		{
-			base.Dispose();
-			if (m_State == ConnectionState.Open)
-				Close();
-		}
-
-		internal Driver Driver
-		{
-			get { return m_Driver; }
-		}
-
-		#region Properties
-		/// <summary>
-		/// Gets a string containing the version of the of the server to which the client is connected.
-		/// </summary>
-		[Browsable(false)]
-		public string ServerVersion 
-		{
-			get
-			{
-				return m_Driver.ServerVersion;
-			}
-		}
-
-		[Browsable(false)]
-		public bool UseCompression
-		{
-			get 
-			{
-				String s = m_ConnSettings["use compression"];
-				if (s == null) return false;
-				return s.ToLower() == "true" || s.ToLower() == "yes";
-			}
-		}
-		
-		[Browsable(false)]
-		public int Port
-		{
-			get
-			{
-				if (m_ConnSettings["port"] == null)
-					return 3306;
-				else
-					return Convert.ToInt32(m_ConnSettings["port"]);
-			}
-		}
-
-#if WINDOWS
-		[Editor(typeof(Designers.ConnectionStringEditor), typeof(System.Drawing.Design.UITypeEditor))]
-#endif
-		[Browsable(true)]
-		[Category("Data")]
-		public string ConnectionString
-		{
-			get
-			{
-				// Always return exactly what the user set.
-				// Security-sensitive information may be removed.
-				return m_ConnString;
-			}
-			set
-			{
-				m_ConnString = value;
-				m_ConnSettings = Common.ConnectionString.ParseConnectString( m_ConnString );
-			}
-		}
-
-		#endregion
-
-		#region Transactions
-		/// <summary>
-		/// 
-		/// </summary>
-		/// <returns></returns>
-		public MySQLTransaction BeginTransaction()
-		{
-			MySQLTransaction t = new MySQLTransaction();
-			t.Connection = this;
-			m_Driver.SendCommand( DBCmd.QUERY, "BEGIN");
-			return t;
-		}
-
-		/// <summary>
-		/// 
-		/// </summary>
-		IDbTransaction IDbConnection.BeginTransaction()
-		{
-			return BeginTransaction();
-		}
-
-		/// <summary>
-		/// 
-		/// </summary>
-		/// <param name="level"></param>
-		/// <returns></returns>
-		public MySQLTransaction BeginTransaction(IsolationLevel level)
-		{
-			MySQLTransaction t = new MySQLTransaction();
-			t.Connection = this;
-			t.IsolationLevel = level;
-			string cmd = "SET SESSION TRANSACTION ISOLATION LEVEL ";
-			switch (level) 
-			{
-				case IsolationLevel.ReadCommitted:
-					cmd += "READ COMMITTED"; break;
-				case IsolationLevel.ReadUncommitted:
-					cmd += "READ UNCOMMITTED"; break;
-				case IsolationLevel.RepeatableRead:
-					cmd += "REPEATABLE READ"; break;
-				case IsolationLevel.Serializable:
-					cmd += "SERIALIZABLE"; break;
-				case IsolationLevel.Chaos:
-					throw new NotSupportedException("Chaos isolation level is not supported");
-			}
-			m_Driver.SendCommand( DBCmd.QUERY, cmd );
-			m_Driver.SendCommand( DBCmd.QUERY, "BEGIN");
-			return t;
-		}
-
-		/// <summary>
-		/// 
-		/// </summary>
-		/// <param name="level"></param>
-		/// <returns></returns>
-		IDbTransaction IDbConnection.BeginTransaction(IsolationLevel level)
-		{
-			return BeginTransaction(level);
-		}
-		#endregion
-
-		/// <summary>
-		/// 
-		/// </summary>
-		/// <param name="dbName"></param>
-		public void ChangeDatabase(string dbName)
-		{
-			/*
-			* Change the database setting on the back-end. Note that it is a method
-			* and not a property because the operation requires an expensive
-			* round trip.
-			*/
-			m_ConnSettings["database"] = dbName;
-
-			m_Driver.SendCommand( DBCmd.INIT_DB, m_ConnSettings["database"] );
-		}
-
-		public void Open()
-		{
-			/*
-			* Open the database connection and set the ConnectionState
-			* property. If the underlying connection to the server is 
-			* expensive to obtain, the implementation should provide
-			* implicit pooling of that connection.
-			* 
-			* If the provider also supports automatic enlistment in 
-			* distributed transactions, it should enlist during Open().
-			*/
-			m_State = ConnectionState.Connecting;
-			if (m_Driver == null)
-				m_Driver = new Driver(ConnectionTimeout);
-			m_Driver.Open( DataSource, Port, User, Password, UseCompression );
-
-			//m_Driver.SendCommand( DBCmd.QUERY, "use " + m_Settings["database"] );
-			m_Driver.SendCommand( DBCmd.INIT_DB, m_ConnSettings["database"] );
-			m_State = ConnectionState.Open;
-		}
-
-
-		public void Close()
-		{
-			// this shouldn't happen, but it is!
-			if (m_State == ConnectionState.Closed) return;
-
-			m_Driver.SendCommand( DBCmd.QUIT, null );
-			m_Driver.Close();
-			/*
-			* Close the database connection and set the ConnectionState
-			* property. If the underlying connection to the server is
-			* being pooled, Close() will release it back to the pool.
-			*/
-			m_State = ConnectionState.Closed;
-		}
-
-		public IDbCommand CreateCommand()
-		{
-			// Return a new instance of a command object.
-			MySQLCommand c = new MySQLCommand();
-			c.Connection = this;
-			return c;
-		}
-
-		#region ICloneable
-		public object Clone()
-		{
-			MySQLConnection clone = new MySQLConnection();
-			clone.ConnectionString = this.ConnectionString;
-			//TODO:  how deep should this go?
-			return clone;
-		}
-		#endregion
-  }
-}
+// ByteFX.Data data access components for .Net
+// Copyright (C) 2002-2003  ByteFX, Inc.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+using System;
+using System.Data;
+using System.Collections.Specialized;
+using System.Text;
+using System.ComponentModel;
+using System.Globalization;
+using ByteFX.Data.Common;
+
+namespace ByteFX.Data.MySqlClient
+{
+	/// <summary>
+	/// Summary description for MySqlConnection.
+	/// </summary>
+	[System.Drawing.ToolboxBitmap( typeof(MySqlConnection), "Designers.connection.bmp")]
+	[System.ComponentModel.DesignerCategory("Code")]
+	[ToolboxItem(true)]
+	public sealed class MySqlConnection : IDbConnection, ICloneable
+	{
+		public ConnectionState			state;
+		private MySqlInternalConnection	internalConnection;
+		private MySqlDataReader			dataReader;
+		private NumberFormatInfo		numberFormat;
+		private MySqlConnectionString	settings;
+
+		public event StateChangeEventHandler	StateChange;
+
+
+		// Always have a default constructor.
+		public MySqlConnection()
+		{
+			settings = new MySqlConnectionString();
+		}
+
+		public MySqlConnection(System.ComponentModel.IContainer container)
+		{
+			settings = new MySqlConnectionString();
+		}
+    
+
+		// Have a constructor that takes a connection string.
+		public MySqlConnection(string connectString)
+		{
+			settings = new MySqlConnectionString(connectString);
+		}
+
+		#region Properties
+		[Browsable(true)]
+		public string DataSource
+		{
+			get { return settings.Host; }
+		}
+
+		[Browsable(false)]
+		public string User
+		{
+			get { return settings.Username; }
+		}
+
+		[Browsable(false)]
+		public string Password
+		{
+			get { return settings.Password; }
+		}
+
+		[Browsable(true)]
+		public int ConnectionTimeout
+		{
+			get { return settings.ConnectTimeout; }
+		}
+		
+		[Browsable(true)]
+		public string Database
+		{
+			get	{ return settings.Database; }
+		}
+
+		[Browsable(false)]
+		public bool UseCompression
+		{
+			get { return settings.UseCompression; }
+		}
+		
+		[Browsable(false)]
+		public int Port
+		{
+			get	{ return settings.Port; }
+		}
+
+		[Browsable(false)]
+		public ConnectionState State
+		{
+			get { return state; }
+		}
+
+		internal MySqlDataReader Reader
+		{
+			get { return dataReader; }
+			set { dataReader = value; }
+		}
+
+		internal MySqlInternalConnection InternalConnection
+		{
+			get { return internalConnection; }
+		}
+
+		internal NumberFormatInfo NumberFormat
+		{
+			get 
+			{
+				if (numberFormat == null)
+				{
+					numberFormat = new NumberFormatInfo();
+					numberFormat = (NumberFormatInfo)NumberFormatInfo.InvariantInfo.Clone();
+					numberFormat.NumberDecimalSeparator = ".";
+				}
+				return numberFormat;
+			}
+		}
+
+		/// <summary>
+		/// Gets a string containing the version of the of the server to which the client is connected.
+		/// </summary>
+		[Browsable(false)]
+		public string ServerVersion 
+		{
+			get { return ""; } //internalConnection.GetServerVersion(); }
+		}
+
+		internal Encoding Encoding 
+		{
+			get 
+			{
+//TODO				if (encoding == null)
+					return System.Text.Encoding.Default;
+//				else 
+//					return encoding;
+			}
+		}
+
+
+#if WINDOWS
+		[Editor(typeof(Designers.ConnectionStringEditor), typeof(System.Drawing.Design.UITypeEditor))]
+#endif
+		[Browsable(true)]
+		[Category("Data")]
+		public string ConnectionString
+		{
+			get
+			{
+				// Always return exactly what the user set.
+				// Security-sensitive information may be removed.
+				return settings.ConnectString;
+			}
+			set
+			{
+				settings.ConnectString = value;
+				if (internalConnection != null)
+					internalConnection.Settings = settings;
+			}
+		}
+
+		#endregion
+
+		#region Transactions
+		/// <summary>
+		/// 
+		/// </summary>
+		/// <returns></returns>
+		public MySqlTransaction BeginTransaction()
+		{
+			if (state != ConnectionState.Open)
+				throw new MySqlException("Invalid operation: The connection is closed");
+
+			MySqlTransaction t = new MySqlTransaction();
+			t.Connection = this;
+			InternalConnection.Driver.SendCommand( DBCmd.QUERY, "BEGIN");
+			return t;
+		}
+
+		/// <summary>
+		/// 
+		/// </summary>
+		IDbTransaction IDbConnection.BeginTransaction()
+		{
+			return BeginTransaction();
+		}
+
+		/// <summary>
+		/// 
+		/// </summary>
+		/// <param name="level"></param>
+		/// <returns></returns>
+		public MySqlTransaction BeginTransaction(IsolationLevel level)
+		{
+			if (state != ConnectionState.Open)
+				throw new MySqlException("Invalid operation: The connection is closed");
+
+			MySqlTransaction t = new MySqlTransaction();
+			t.Connection = this;
+			t.IsolationLevel = level;
+			string cmd = "SET SESSION TRANSACTION ISOLATION LEVEL ";
+			switch (level) 
+			{
+				case IsolationLevel.ReadCommitted:
+					cmd += "READ COMMITTED"; break;
+				case IsolationLevel.ReadUncommitted:
+					cmd += "READ UNCOMMITTED"; break;
+				case IsolationLevel.RepeatableRead:
+					cmd += "REPEATABLE READ"; break;
+				case IsolationLevel.Serializable:
+					cmd += "SERIALIZABLE"; break;
+				case IsolationLevel.Chaos:
+					throw new NotSupportedException("Chaos isolation level is not supported");
+			}
+			InternalConnection.Driver.SendCommand( DBCmd.QUERY, cmd );
+			InternalConnection.Driver.SendCommand( DBCmd.QUERY, "BEGIN");
+			return t;
+		}
+
+		/// <summary>
+		/// 
+		/// </summary>
+		/// <param name="level"></param>
+		/// <returns></returns>
+		IDbTransaction IDbConnection.BeginTransaction(IsolationLevel level)
+		{
+			return BeginTransaction(level);
+		}
+		#endregion
+
+		/// <summary>
+		/// 
+		/// </summary>
+		/// <param name="dbName"></param>
+		public void ChangeDatabase(string dbName)
+		{
+			if (state != ConnectionState.Open)
+				throw new MySqlException("Invalid operation: The connection is closed");
+
+			//TODOinternalConnection.ChangeDatabase( dbName );
+			InternalConnection.Driver.SendCommand( DBCmd.INIT_DB, dbName );
+		}
+
+		internal void SetState( ConnectionState newState ) 
+		{
+			ConnectionState oldState = state;
+			state = newState;
+			if (this.StateChange != null)
+				StateChange(this, new StateChangeEventArgs( oldState, newState ));
+		}
+
+		public void Open()
+		{
+			if (state == ConnectionState.Open)
+				throw new MySqlException("error connecting: The connection is already Open (state=Open).");
+
+			SetState( ConnectionState.Connecting );
+
+			if (settings.Pooling) 
+			{
+				internalConnection = MySqlPoolManager.GetConnection( settings );
+			}
+			else
+			{
+				internalConnection = new MySqlInternalConnection( settings );
+				internalConnection.Open();
+			}
+
+			SetState( ConnectionState.Open );
+			internalConnection.SetServerVariables(this);
+			ChangeDatabase( settings.Database );
+		}
+
+
+		public void Close()
+		{
+			if (state == ConnectionState.Closed) return;
+
+			if (dataReader != null)
+				dataReader.Close();
+
+			if (settings.Pooling)
+				MySqlPoolManager.ReleaseConnection( internalConnection );
+			else
+				internalConnection.Close();
+
+			SetState( ConnectionState.Closed );
+		}
+
+		IDbCommand IDbConnection.CreateCommand()
+		{
+			return CreateCommand();
+		}
+
+		public MySqlCommand CreateCommand()
+		{
+			// Return a new instance of a command object.
+			MySqlCommand c = new MySqlCommand();
+			c.Connection = this;
+			return c;
+		}
+
+		#region ICloneable
+		public object Clone()
+		{
+			MySqlConnection clone = new MySqlConnection();
+			clone.ConnectionString = this.ConnectionString;
+			//TODO:  how deep should this go?
+			return clone;
+		}
+		#endregion
+
+		#region IDisposeable
+		public void Dispose() 
+		{
+			if (State == ConnectionState.Open)
+				Close();
+		}
+		#endregion
+  }
+}

+ 42 - 42
mcs/class/ByteFX.Data/mysqlclient/Connection.resx

@@ -1,42 +1,42 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<root>
-	<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
-		<xsd:element name="root" msdata:IsDataSet="true">
-			<xsd:complexType>
-				<xsd:choice maxOccurs="unbounded">
-					<xsd:element name="data">
-						<xsd:complexType>
-							<xsd:sequence>
-								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-								<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
-							</xsd:sequence>
-							<xsd:attribute name="name" type="xsd:string" />
-							<xsd:attribute name="type" type="xsd:string" />
-							<xsd:attribute name="mimetype" type="xsd:string" />
-						</xsd:complexType>
-					</xsd:element>
-					<xsd:element name="resheader">
-						<xsd:complexType>
-							<xsd:sequence>
-								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-							</xsd:sequence>
-							<xsd:attribute name="name" type="xsd:string" use="required" />
-						</xsd:complexType>
-					</xsd:element>
-				</xsd:choice>
-			</xsd:complexType>
-		</xsd:element>
-	</xsd:schema>
-	<resheader name="ResMimeType">
-		<value>text/microsoft-resx</value>
-	</resheader>
-	<resheader name="Version">
-		<value>1.0.0.0</value>
-	</resheader>
-	<resheader name="Reader">
-		<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.3102.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-	</resheader>
-	<resheader name="Writer">
-		<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.3102.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-	</resheader>
-</root>
+<?xml version="1.0" encoding="utf-8" ?>
+<root>
+	<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+		<xsd:element name="root" msdata:IsDataSet="true">
+			<xsd:complexType>
+				<xsd:choice maxOccurs="unbounded">
+					<xsd:element name="data">
+						<xsd:complexType>
+							<xsd:sequence>
+								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+								<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+							</xsd:sequence>
+							<xsd:attribute name="name" type="xsd:string" />
+							<xsd:attribute name="type" type="xsd:string" />
+							<xsd:attribute name="mimetype" type="xsd:string" />
+						</xsd:complexType>
+					</xsd:element>
+					<xsd:element name="resheader">
+						<xsd:complexType>
+							<xsd:sequence>
+								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+							</xsd:sequence>
+							<xsd:attribute name="name" type="xsd:string" use="required" />
+						</xsd:complexType>
+					</xsd:element>
+				</xsd:choice>
+			</xsd:complexType>
+		</xsd:element>
+	</xsd:schema>
+	<resheader name="ResMimeType">
+		<value>text/microsoft-resx</value>
+	</resheader>
+	<resheader name="Version">
+		<value>1.0.0.0</value>
+	</resheader>
+	<resheader name="Reader">
+		<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.3102.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+	</resheader>
+	<resheader name="Writer">
+		<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.3102.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+	</resheader>
+</root>

+ 108 - 0
mcs/class/ByteFX.Data/mysqlclient/ConnectionInternal.cs

@@ -0,0 +1,108 @@
+using System;
+using ByteFX.Data.Common;
+
+namespace ByteFX.Data.MySqlClient
+{
+	/// <summary>
+	/// 
+	/// </summary>
+	internal sealed class MySqlInternalConnection
+	{
+		MySqlConnectionString	settings;
+		Driver					driver;
+		DateTime				createTime;
+		bool					serverVariablesSet;
+
+		public MySqlInternalConnection( MySqlConnectionString connectString )
+		{
+			settings = connectString;
+			serverVariablesSet = false;
+		}
+
+		#region Properties
+		public MySqlConnectionString Settings 
+		{
+			get { return settings; }
+			set { settings = value; }
+		}
+
+		internal Driver Driver 
+		{
+			get { return driver; }
+		}
+
+		#endregion
+
+		#region Methods
+
+		public bool IsAlive() 
+		{
+			Packet packet;
+			try 
+			{
+				packet = driver.SendSql( "show status like 'uptime'" );
+				// we have to read for two last packets since MySql sends
+				// us a last packet after schema and again after rows
+				// I will likely change this later to have the driver just
+				// return schema in one very large packet.
+				while (packet.Type != PacketType.Last)
+					packet = driver.ReadPacket();
+			}
+			catch
+			{
+				return false;
+			}
+			
+			return true;
+		}
+
+		public bool IsTooOld() 
+		{
+			TimeSpan ts = DateTime.Now.Subtract( createTime );
+			if (ts.Seconds > settings.ConnectionLifetime)
+				return true;
+			return false;
+		}
+
+		/// <summary>
+		/// I don't like this setup but can't think of a better way of doing
+		/// right now.
+		/// </summary>
+		/// <param name="connection"></param>
+		public void SetServerVariables(MySqlConnection connection)
+		{
+			if (serverVariablesSet) return;
+
+			// retrieve the encoding that should be used for character data
+			MySqlCommand cmd = new MySqlCommand("select @@session.max_allowed_packet", connection);
+			driver.MaxPacketSize = Convert.ToInt64(cmd.ExecuteScalar());
+
+			cmd.CommandText = "show variables like 'character_set'";
+			MySqlDataReader reader = cmd.ExecuteReader();
+			if (reader.Read())
+				driver.Encoding = CharSetMap.GetEncoding( reader.GetString(1) );
+			else
+				driver.Encoding = System.Text.Encoding.Default;
+			reader.Close();
+
+			serverVariablesSet = true;
+		}
+
+		public void Open() 
+		{
+			driver = new Driver();
+			driver.Open( settings.Host, settings.Port, settings.Username, settings.Password,
+				settings.UseCompression, settings.ConnectTimeout );
+
+			createTime = DateTime.Now;
+		}
+
+		public void Close() 
+		{
+			driver.Close();
+		}
+
+		#endregion
+
+	}
+}

+ 55 - 0
mcs/class/ByteFX.Data/mysqlclient/ConnectionString.cs

@@ -0,0 +1,55 @@
+using System;
+using ByteFX.Data.Common;
+
+namespace ByteFX.Data.MySqlClient
+{
+	/// <summary>
+	/// Summary description for MySqlConnectionString.
+	/// </summary>
+	internal sealed class MySqlConnectionString : DBConnectionString
+	{
+		private bool useCompression;
+
+		public MySqlConnectionString() 
+		{
+			connectLifetime = 0;
+			pooling = true;
+			minPoolSize = 0;
+			maxPoolSize = 100;
+			connectTimeout = 15;
+			port = 3306;
+		}
+
+		public MySqlConnectionString(string connectString) : base(connectString)
+		{
+			connectLifetime = 0;
+			pooling = true;
+			minPoolSize = 0;
+			maxPoolSize = 100;
+			connectTimeout = 15;
+			port = 3306;
+			Parse();
+		}
+
+		#region Properties
+		public bool UseCompression 
+		{
+			get { return useCompression; }
+		}
+		#endregion
+
+		protected override void ConnectionParameterParsed(string key, string value)
+		{
+			switch (key.ToLower()) 
+			{
+				case "use compression":
+				case "compress":
+					useCompression = Boolean.Parse( value );
+					break;
+			}
+
+			base.ConnectionParameterParsed(key, value);
+		}
+
+	}
+}

+ 310 - 0
mcs/class/ByteFX.Data/mysqlclient/Designers/EditConnectionString.cs

@@ -0,0 +1,310 @@
+// ByteFX.Data data access components for .Net
+// Copyright (C) 2002-2003  ByteFX, Inc.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+using System;
+using System.Collections;
+using System.ComponentModel;
+#if WINDOWS
+using System.Drawing;
+using System.Windows.Forms;
+#endif
+
+namespace ByteFX.Data.MySqlClient.Designers
+{
+#if WINDOWS
+	/// <summary>
+	/// Summary description for EditConnectionString.
+	/// </summary>
+	public class EditConnectionString : System.Windows.Forms.Form
+	{
+		private System.Windows.Forms.Button buttonOK;
+		private System.Windows.Forms.Button buttonCancel;
+		private System.Windows.Forms.Label label1;
+		private System.Windows.Forms.TextBox textServer;
+		private System.Windows.Forms.TextBox textUser;
+		private System.Windows.Forms.Label label2;
+		private System.Windows.Forms.TextBox textPassword;
+		private System.Windows.Forms.Label label3;
+		private System.Windows.Forms.ComboBox comboDatabase;
+		private System.Windows.Forms.Label label4;
+		private System.Windows.Forms.Label label5;
+		private System.Windows.Forms.TextBox textPort;
+		private System.Windows.Forms.CheckBox useCompression;
+		/// <summary>
+		/// Required designer variable.
+		/// </summary>
+		private System.ComponentModel.Container components = null;
+
+		public EditConnectionString()
+		{
+			//
+			// Required for Windows Form Designer support
+			//
+			InitializeComponent();
+
+			//
+			// TODO: Add any constructor code after InitializeComponent call
+			//
+		}
+
+		public string ConnectionString;
+
+		/// <summary>
+		/// Clean up any resources being used.
+		/// </summary>
+		protected override void Dispose( bool disposing )
+		{
+			if( disposing )
+			{
+				if(components != null)
+				{
+					components.Dispose();
+				}
+			}
+			base.Dispose( disposing );
+		}
+
+		#region Windows Form Designer generated code
+		/// <summary>
+		/// Required method for Designer support - do not modify
+		/// the contents of this method with the code editor.
+		/// </summary>
+		private void InitializeComponent()
+		{
+			this.buttonOK = new System.Windows.Forms.Button();
+			this.buttonCancel = new System.Windows.Forms.Button();
+			this.label1 = new System.Windows.Forms.Label();
+			this.textServer = new System.Windows.Forms.TextBox();
+			this.textUser = new System.Windows.Forms.TextBox();
+			this.label2 = new System.Windows.Forms.Label();
+			this.textPassword = new System.Windows.Forms.TextBox();
+			this.label3 = new System.Windows.Forms.Label();
+			this.comboDatabase = new System.Windows.Forms.ComboBox();
+			this.label4 = new System.Windows.Forms.Label();
+			this.label5 = new System.Windows.Forms.Label();
+			this.textPort = new System.Windows.Forms.TextBox();
+			this.useCompression = new System.Windows.Forms.CheckBox();
+			this.SuspendLayout();
+			// 
+			// buttonOK
+			// 
+			this.buttonOK.Location = new System.Drawing.Point(67, 200);
+			this.buttonOK.Name = "buttonOK";
+			this.buttonOK.TabIndex = 0;
+			this.buttonOK.Text = "&OK";
+			this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click);
+			// 
+			// buttonCancel
+			// 
+			this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+			this.buttonCancel.Location = new System.Drawing.Point(187, 200);
+			this.buttonCancel.Name = "buttonCancel";
+			this.buttonCancel.TabIndex = 0;
+			this.buttonCancel.Text = "&Cancel";
+			// 
+			// label1
+			// 
+			this.label1.Location = new System.Drawing.Point(12, 24);
+			this.label1.Name = "label1";
+			this.label1.Size = new System.Drawing.Size(104, 16);
+			this.label1.TabIndex = 1;
+			this.label1.Text = "Mysql server name:";
+			this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+			// 
+			// textServer
+			// 
+			this.textServer.Location = new System.Drawing.Point(112, 20);
+			this.textServer.Name = "textServer";
+			this.textServer.Size = new System.Drawing.Size(168, 20);
+			this.textServer.TabIndex = 2;
+			this.textServer.Text = "";
+			// 
+			// textUser
+			// 
+			this.textUser.Location = new System.Drawing.Point(112, 76);
+			this.textUser.Name = "textUser";
+			this.textUser.Size = new System.Drawing.Size(168, 20);
+			this.textUser.TabIndex = 2;
+			this.textUser.Text = "";
+			// 
+			// label2
+			// 
+			this.label2.Location = new System.Drawing.Point(68, 76);
+			this.label2.Name = "label2";
+			this.label2.Size = new System.Drawing.Size(40, 16);
+			this.label2.TabIndex = 1;
+			this.label2.Text = "User:";
+			this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+			// 
+			// textPassword
+			// 
+			this.textPassword.Location = new System.Drawing.Point(112, 108);
+			this.textPassword.Name = "textPassword";
+			this.textPassword.PasswordChar = '*';
+			this.textPassword.Size = new System.Drawing.Size(168, 20);
+			this.textPassword.TabIndex = 2;
+			this.textPassword.Text = "";
+			// 
+			// label3
+			// 
+			this.label3.Location = new System.Drawing.Point(44, 108);
+			this.label3.Name = "label3";
+			this.label3.Size = new System.Drawing.Size(64, 16);
+			this.label3.TabIndex = 1;
+			this.label3.Text = "Password:";
+			this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+			// 
+			// comboDatabase
+			// 
+			this.comboDatabase.Location = new System.Drawing.Point(112, 160);
+			this.comboDatabase.Name = "comboDatabase";
+			this.comboDatabase.Size = new System.Drawing.Size(168, 21);
+			this.comboDatabase.TabIndex = 3;
+			this.comboDatabase.DropDown += new System.EventHandler(this.comboDatabase_DropDown);
+			// 
+			// label4
+			// 
+			this.label4.Location = new System.Drawing.Point(4, 164);
+			this.label4.Name = "label4";
+			this.label4.Size = new System.Drawing.Size(104, 16);
+			this.label4.TabIndex = 1;
+			this.label4.Text = "Select a database:";
+			this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+			// 
+			// label5
+			// 
+			this.label5.Location = new System.Drawing.Point(72, 52);
+			this.label5.Name = "label5";
+			this.label5.Size = new System.Drawing.Size(36, 16);
+			this.label5.TabIndex = 1;
+			this.label5.Text = "Port:";
+			this.label5.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+			// 
+			// textPort
+			// 
+			this.textPort.Location = new System.Drawing.Point(112, 48);
+			this.textPort.Name = "textPort";
+			this.textPort.Size = new System.Drawing.Size(168, 20);
+			this.textPort.TabIndex = 2;
+			this.textPort.Text = "";
+			// 
+			// useCompression
+			// 
+			this.useCompression.Location = new System.Drawing.Point(10, 132);
+			this.useCompression.Name = "useCompression";
+			this.useCompression.RightToLeft = System.Windows.Forms.RightToLeft.Yes;
+			this.useCompression.Size = new System.Drawing.Size(116, 24);
+			this.useCompression.TabIndex = 4;
+			this.useCompression.Text = "Use compression";
+			this.useCompression.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+			// 
+			// EditConnectionString
+			// 
+			this.AcceptButton = this.buttonOK;
+			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
+			this.CancelButton = this.buttonCancel;
+			this.ClientSize = new System.Drawing.Size(298, 239);
+			this.Controls.AddRange(new System.Windows.Forms.Control[] {
+																		  this.useCompression,
+																		  this.comboDatabase,
+																		  this.textServer,
+																		  this.label1,
+																		  this.buttonOK,
+																		  this.buttonCancel,
+																		  this.textUser,
+																		  this.label2,
+																		  this.textPassword,
+																		  this.label3,
+																		  this.label4,
+																		  this.label5,
+																		  this.textPort});
+			this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+			this.MaximizeBox = false;
+			this.MinimizeBox = false;
+			this.Name = "EditConnectionString";
+			this.ShowInTaskbar = false;
+			this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+			this.Text = "Edit Connection String";
+			this.Load += new System.EventHandler(this.EditConnectionString_Load);
+			this.ResumeLayout(false);
+
+		}
+		#endregion
+
+		MySqlConnection conn;
+
+		private void EditConnectionString_Load(object sender, System.EventArgs e)
+		{
+			conn = new MySqlConnection(ConnectionString);
+			textServer.Text = conn.DataSource;
+			textUser.Text = conn.User;
+			textPassword.Text = conn.Password;
+			textPort.Text = conn.Port.ToString();
+			conn = null;
+		}
+
+		string GetString()
+		{
+			System.Text.StringBuilder s;
+			s = new System.Text.StringBuilder();
+			s.Append("server=" + textServer.Text);
+			s.Append(";port=" + textPort.Text);
+			s.Append(";uid=" + textUser.Text);
+			s.Append(";pwd=" + textPassword.Text);
+			if (useCompression.Checked) 
+			{
+				s.Append(";Use compression=true");
+			}
+			if (comboDatabase.SelectedIndex != -1)
+				s.Append(";Initial Catalog=" + comboDatabase.SelectedItem.ToString());
+			else
+				s.Append(";Initial Catalog=" + comboDatabase.Text);
+			return s.ToString();
+		}
+
+		private void comboDatabase_DropDown(object sender, System.EventArgs e)
+		{
+			comboDatabase.Items.Clear();
+			comboDatabase.SelectedIndex = -1;
+		
+			try
+			{
+				conn = new MySqlConnection(GetString());
+				conn.Open();
+				MySqlCommand comm = new MySqlCommand("show databases",conn);
+				MySqlDataReader r = (MySqlDataReader)comm.ExecuteReader();
+				while(r.Read())
+				{
+					comboDatabase.Items.Add(r[0]);
+				}
+				r.Close();
+				conn.Close();
+			}
+			catch(MySqlException)
+			{
+			}
+		}
+
+		private void buttonOK_Click(object sender, System.EventArgs e)
+		{
+			ConnectionString = GetString();
+			DialogResult = DialogResult.OK;
+			Close();
+		}
+	}
+#endif
+}

+ 102 - 0
mcs/class/ByteFX.Data/mysqlclient/Designers/EditConnectionString.resx

@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+            Microsoft ResX Schema 
+        
+            Version 1.3
+                
+            The primary goals of this format is to allow a simple XML format 
+            that is mostly human readable. The generation and parsing of the 
+            various data types are done through the TypeConverter classes 
+            associated with the data types.
+        
+            Example:
+        
+                ... ado.net/XML headers & schema ...
+                <resheader name="resmimetype">text/microsoft-resx</resheader>
+                <resheader name="version">1.3</resheader>
+                <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+                <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+                <data name="Name1">this is my long string</data>
+                <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+                <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+                    [base64 mime encoded serialized .NET Framework object]
+                </data>
+                <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+                    [base64 mime encoded string representing a byte array form of the .NET Framework object]
+                </data>
+        
+            There are any number of "resheader" rows that contain simple 
+            name/value pairs.
+            
+            Each data row contains a name, and value. The row also contains a 
+            type or mimetype. Type corresponds to a .NET class that support 
+            text/value conversion through the TypeConverter architecture. 
+            Classes that don't support this are serialized and stored with the 
+            mimetype set.
+                     
+            The mimetype is used for serialized objects, and tells the 
+            ResXResourceReader how to depersist the object. This is currently not 
+            extensible. For a given mimetype the value must be set accordingly:
+        
+            Note - application/x-microsoft.net.object.binary.base64 is the format 
+                   that the ResXResourceWriter will generate, however the reader can 
+                   read any of the formats listed below.
+        
+            mimetype: application/x-microsoft.net.object.binary.base64
+            value   : The object must be serialized with 
+                    : System.Serialization.Formatters.Binary.BinaryFormatter
+                    : and then encoded with base64 encoding.
+        
+            mimetype: application/x-microsoft.net.object.soap.base64
+            value   : The object must be serialized with 
+                    : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+                    : and then encoded with base64 encoding.
+            mimetype: application/x-microsoft.net.object.bytearray.base64
+            value   : The object must be serialized into a byte array 
+                    : using a System.ComponentModel.TypeConverter
+                    : and then encoded with base64 encoding.
+        -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>1.3</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <data name="$this.Name">
+    <value>EditConnectionString</value>
+  </data>
+</root>

+ 55 - 0
mcs/class/ByteFX.Data/mysqlclient/Designers/MySqlConnectionDesign.cs

@@ -0,0 +1,55 @@
+// ByteFX.Data data access components for .Net
+// Copyright (C) 2002-2003  ByteFX, Inc.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+using System;
+#if WINDOWS
+using System.Windows.Forms;
+using System.Drawing.Design;
+#endif
+
+namespace ByteFX.Data.MySqlClient.Designers
+{
+#if WINDOWS
+	/// <summary>
+	/// Summary description for MySqlConnectionDesign.
+	/// </summary>
+	public class ConnectionStringEditor : UITypeEditor
+	{
+		public override System.Drawing.Design.UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
+		{
+			return System.Drawing.Design.UITypeEditorEditStyle.Modal;
+		}
+
+		public override bool GetPaintValueSupported(System.ComponentModel.ITypeDescriptorContext context)
+		{
+			return false;
+		}
+
+		public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, System.IServiceProvider provider, object value)
+		{
+			EditConnectionString dlg = new EditConnectionString();
+			dlg.ConnectionString = (string)value;
+			if(dlg.ShowDialog() == DialogResult.OK)
+			{
+				return dlg.ConnectionString;
+			}
+			else
+				return value;
+		}
+	}
+#endif
+}

BIN
mcs/class/ByteFX.Data/mysqlclient/Designers/command.bmp


BIN
mcs/class/ByteFX.Data/mysqlclient/Designers/connection.bmp


BIN
mcs/class/ByteFX.Data/mysqlclient/Designers/dataadapter.bmp


+ 540 - 697
mcs/class/ByteFX.Data/mysqlclient/Driver.cs

@@ -1,697 +1,540 @@
-// ByteFX.Data data access components for .Net
-// Copyright (C) 2002-2003  ByteFX, Inc.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-using System;
-using System.Net;
-using System.Net.Sockets;
-using System.IO;
-using ICSharpCode.SharpZipLib.Zip.Compression;
-
-namespace ByteFX.Data.MySQLClient
-{
-	/// <summary>
-	/// Summary description for Driver.
-	/// </summary>
-	internal class Driver : IDisposable
-	{
-		protected const	int COMPRESS_HEADER_LEN = 3;
-		protected const int HEADER_LEN = 4;
-		protected const int MIN_COMPRESS_LEN = 50;
-
-		public MemoryStream		_packet;
-		protected Stream		_stream;
-		protected Socket		_socket;
-		protected int			m_Seq;
-		protected int			m_BufIndex;
-		protected byte			m_LastResult;
-		protected byte[]		m_Buffer;
-		protected int			m_Timeout;
-		protected int			_port;
-
-		int		m_Protocol;
-		String	m_ServerVersion;
-		int		m_ThreadID;
-		String	m_EncryptionSeed;
-		int		m_ServerCaps;
-		bool	m_UseCompression = false;
-
-
-		public Driver(int ConnectionTimeout)
-		{
-			m_Seq = -1;
-			m_LastResult = 0xff;
-			m_Timeout = ConnectionTimeout;
-			m_BufIndex = 0;
-
-			ResetPacket();
-		}
-
-		~Driver() 
-		{
-		}
-
-		public byte LastResult 
-		{
-			get { return m_LastResult; }
-		}
-
-		public string ServerVersion 
-		{
-			get { return m_ServerVersion; }
-		}
-
-		public void Dispose() 
-		{
-		}
-
-#if WINDOWS
-		/// <summary>
-		/// 
-		/// </summary>
-		/// <param name="host"></param>
-		void CreatePipeStream( string host ) 
-		{
-			string _pipename;
-			if (host.ToLower().Equals("localhost"))
-				_pipename = @"\\.\pipe\MySQL";
-			else
-				_pipename = String.Format(@"\\{0}\pipe\MySQL", host);
-
-			_stream = new ByteFX.Data.Common.NamedPipeStream(_pipename, FileAccess.ReadWrite);
-		}
-#endif
-
-		/// <summary>
-		/// 
-		/// </summary>
-		/// <param name="host"></param>
-		/// <param name="port"></param>
-		void CreateSocketStream( string host, int port ) 
-		{
-			_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
-			IPHostEntry he = Dns.GetHostByName(host);
-			IPEndPoint _serverAddr = new IPEndPoint(he.AddressList[0], port);
-
-			_socket.Connect(_serverAddr);
-			_stream = new NetworkStream(_socket);
-		}
-
-		/// <summary>
-		/// 
-		/// </summary>
-		/// <param name="host"></param>
-		/// <param name="port"></param>
-		/// <param name="userid"></param>
-		/// <param name="password"></param>
-		public void Open( String host, int port, String userid, String password, bool UseCompression ) 
-		{
-			_port = port;
-#if WINDOWS
-			if (-1 == port) 
-			{
-				CreatePipeStream(host);
-			}
-#endif
-			
-			if (-1 != port)
-			{
-				CreateSocketStream(host, port);
-			}
-
-			ReadPacket();
-
-			// read off the protocol version
-			m_Protocol = _packet.ReadByte();
-			m_ServerVersion = ReadString();
-			m_ThreadID = ReadInteger(4);
-			m_EncryptionSeed = ReadString();
-
-			// read in Server capabilities if they are provided
-			m_ServerCaps = 0;
-			if (_packet.CanRead)
-				m_ServerCaps = ReadInteger(2);
-
-			Authenticate( userid, password, UseCompression );
-		}
-
-		/// <summary>
-		/// 
-		/// </summary>
-		/// <param name="userid"></param>
-		/// <param name="password"></param>
-		private void Authenticate( String userid, String password, bool UseCompression )
-		{
-			ClientParam clientParam = ClientParam.CLIENT_FOUND_ROWS | ClientParam.CLIENT_LONG_FLAG;
-
-			if ((m_ServerCaps & (int)ClientParam.CLIENT_COMPRESS) != 0 && UseCompression)
-			{
-				clientParam |= ClientParam.CLIENT_COMPRESS;
-			}
-
-			clientParam |= ClientParam.CLIENT_LONG_PASSWORD;
-
-			password = EncryptPassword(password, m_EncryptionSeed, m_Protocol > 9);
-			// header_length = 4
-			//int headerLength = (userid.Length + 16) + 6 + 4; // Passwords can be 16 chars long
-
-			ResetPacket();
-			WriteInteger( (int)clientParam, 2 );
-			WriteInteger( 0, 3 ); 
-			WriteString( userid );
-			WriteString( password );
-			WritePacket();
-
-			CheckResult();
-
-			if ((clientParam & ClientParam.CLIENT_COMPRESS) != 0)
-				m_UseCompression = true;
-		}
-
-		public void ResetPacket()
-		{
-			_packet = new MemoryStream();
-			_packet.SetLength(0);
-
-			// hack for Mono 0.17 not handling length < position on MemoryStream
-			_packet.Position = 0;
-			WriteInteger(0, HEADER_LEN);
-
-			if (m_UseCompression)
-				_packet.Position += (COMPRESS_HEADER_LEN+HEADER_LEN);
-		}
-
-		protected bool CanReadStream()
-		{
-#if WINDOWS
-			if (_port == -1)
-			{
-				return (_stream as ByteFX.Data.Common.NamedPipeStream).DataAvailable;
-			}
-#endif
-			return (_stream as NetworkStream).DataAvailable;
-		}
-
-		/// <summary>
-		/// 
-		/// </summary>
-		/// <returns></returns>
-		public byte ReadStreamByte()
-		{
-			long start = DateTime.Now.Ticks;
-			long timeout = m_Timeout * TimeSpan.TicksPerSecond;
-
-			while ((DateTime.Now.Ticks - start) < timeout)
-			{
-				if (CanReadStream()) return (byte)_stream.ReadByte();
-			}
-			throw new MySQLException("Timeout waiting for response from server");
-		}
-
-		/// <summary>
-		/// 
-		/// </summary>
-		/// <param name="buf"></param>
-		/// <param name="offset"></param>
-		/// <param name="count"></param>
-		protected void ReadStreamBytes(byte[] buf, int offset, int count)
-		{
-			long start = DateTime.Now.Ticks;
-			long timeout = m_Timeout * TimeSpan.TicksPerSecond;
-			long curoffset = offset;
-
-			while (count > 0 && ((DateTime.Now.Ticks - start) < timeout))
-			{
-				if (CanReadStream()) 
-				{
-					int cnt = _stream.Read(buf, (int)curoffset, count);
-					count -= cnt;
-					curoffset += cnt;
-				}
-			}
-			if (count > 0)
-				throw new MySQLException("Timeout waiting for response from server");
-		}
-
-		/// <summary>
-		/// 
-		/// </summary>
-		private void ReadServerDataBlock()
-		{
-			int b0 = (int)ReadStreamByte();
-			int b1 = (int)ReadStreamByte();
-			int b2 = (int)ReadStreamByte();
-
-			if (b0 == -1 && b1 == -1 && b2 == -1) 
-			{
-				//TODO: close?
-				throw new IOException("Unexpected end of input stream");
-			}
-
-			int packetLength = (int)(b0+ (256*b1) + (256*256*b2));
-			int comp_len = 0;
-			byte Seq = (byte)ReadStreamByte();
-	
-			// handle the stupid field swapping does if compression is used
-			// If the block is compressed, then the first length field is the compressed
-			// length and the second is the uncompressed.
-			// If the block is uncompressed, even if compression is selected, the first
-			// length field is the uncompressed size and the second field is zero
-			if (m_UseCompression) 
-			{
-				int c0 = (int)ReadStreamByte();
-				int c1 = (int)ReadStreamByte();
-				int c2 = (int)ReadStreamByte();
-				comp_len = (int)(c0 + (256*c1) + (256*256*c2));
-				if (comp_len > 0) 
-				{
-					int temp = packetLength;
-					packetLength = comp_len;
-					comp_len = temp;
-				}
-			}
-
-			if (m_UseCompression && comp_len > 0) 
-			{
-				m_Buffer = new Byte[packetLength];
-				byte[] comp = new Byte[comp_len];
-				// read in the compressed data
-				ReadStreamBytes(comp, 0, comp_len);
-
-				Inflater i = new Inflater();
-				i.SetInput( comp );
-
-				i.Inflate(m_Buffer);
-				return;
-			}
-
-			if (!m_UseCompression) 
-			{
-				m_Buffer = new Byte[packetLength+4];
-				ReadStreamBytes(m_Buffer, 4, packetLength);
-				m_Buffer[0] = (byte)b0; m_Buffer[1] = (byte)b1; m_Buffer[2] = (byte)b2;
-				m_Buffer[3] = (byte)Seq;
-			}
-			else 
-			{
-				m_Buffer = new Byte[packetLength];
-				ReadStreamBytes(m_Buffer, 0, packetLength);
-			}
-		}
-
-		/// <summary>
-		/// 
-		/// </summary>
-		/// <returns></returns>
-		public int ReadPacket()
-		{
-			if (_packet == null || m_Buffer == null || m_BufIndex == m_Buffer.Length)
-			{
-				ReadServerDataBlock();
-				m_BufIndex = 0;
-			}
-
-			_packet = new MemoryStream(m_Buffer, m_BufIndex, m_Buffer.Length - m_BufIndex);
-			int len = ReadInteger(3);
-			int seq = (int)ReadByte();
-			_packet.SetLength(len+HEADER_LEN);
-			m_BufIndex += (int)_packet.Length;
-
-			// if the sequence doesn't match up, then there must be some orphaned
-			// packets so we just read them off
-			if (seq != (m_Seq+1)) return ReadPacket();
-			
-			m_Seq = seq;
-			return len;
-}
-
-		/// <summary>
-		/// 
-		/// </summary>
-		/// <returns></returns>
-		protected int CompressPacket()
-		{
-			// compress the entire packet except the length
-
-			// make sure we are using a packet prep'ed for compression
-			// and that our packet is large enough to warrant compression
-			// re: my_compress.c from mysql src
-			int offset = HEADER_LEN + COMPRESS_HEADER_LEN;
-			int original_len = (int)(_packet.Length - offset);
-			if (original_len < MIN_COMPRESS_LEN) return 0;
-
-			byte[] packetData = _packet.ToArray();
-
-			byte[] output = new Byte[ original_len * 2 ];
-			Deflater d = new Deflater();
-			d.SetInput( packetData, offset, original_len );
-			d.Finish();
-			int comp_len = d.Deflate( output, offset, output.Length - offset  );
-
-			if (comp_len > original_len) return 0;
-			_packet = new MemoryStream( output, 0, comp_len + offset );
-			return (int)comp_len;
-		}
-
-		/// <summary>
-		/// 
-		/// </summary>
-		/// <param name="useCompressionIfAvail"></param>
-		protected void WritePacket()
-		{
-			if (m_UseCompression)
-			{
-				// store the length of the buffer we are going to compress
-				long num_bytes = _packet.Length - (HEADER_LEN*2) - COMPRESS_HEADER_LEN;
-				_packet.Position = HEADER_LEN + COMPRESS_HEADER_LEN;
-				WriteInteger( (int) num_bytes, 3 );
-				_packet.WriteByte(0);				// internal packet has 0 as seq if compressing
-
-				// now compress it
-				int compressed_size = CompressPacket();
-
-				_packet.Position = 0;
-				if (compressed_size == 0) 
-				{
-					WriteInteger( (int)num_bytes + HEADER_LEN, 3);
-					_packet.WriteByte((byte)++m_Seq);
-					WriteInteger( compressed_size, 3 );
-				}
-				else 
-				{
-					WriteInteger( compressed_size, 3 );
-					_packet.WriteByte((byte)++m_Seq);
-					WriteInteger( (int)num_bytes + HEADER_LEN, 3);
-				}
-			}
-			else 
-			{
-				_packet.Position = 0;
-				WriteInteger( (int)(_packet.Length - HEADER_LEN), 3 );
-				_packet.WriteByte((byte)++m_Seq);
-			}
-
-			_stream.Write( _packet.ToArray(), 0, (int)_packet.Length );
-			_stream.Flush();
-
-			// reset the writeStream to empty
-			ResetPacket();
-		}
-
-
-		protected void WriteString(string v)
-		{
-			WriteStringNoNull(v);
-			_packet.WriteByte(0);
-		}
-
-		protected void WriteStringNoNull(string v)
-		{
-			byte[] bytes = System.Text.Encoding.ASCII.GetBytes(v);
-			_packet.Write(bytes, 0, bytes.Length);
-		}
-
-		public void Close() 
-		{
-			m_Seq = -1;
-			_stream.Close();
-			if (_socket != null)
-				_socket.Close();
-		}
-
-		public string ReadString()
-		{
-			String str = new String('c',0);
-
-			while (_packet.Position < _packet.Length) 
-			{
-				byte b = (byte)_packet.ReadByte();
-				if (b == 0) break;
-				str += Convert.ToChar(b);
-			}
-			return str;
-		}
-
-		protected void WriteInteger( int v, int numbytes )
-		{
-			int val = v;
-
-			if (numbytes < 1 || numbytes > 4) 
-				throw new Exception("Wrong byte count for WriteInteger");
-
-			for (int x=0; x < numbytes; x++)
-			{
-				_packet.WriteByte( (byte)(val&0xff) );
-				val >>= 8;
-			}
-		}
-
-		/// <summary>
-		/// 
-		/// </summary>
-		/// <param name="numbytes"></param>
-		/// <returns></returns>
-		public int ReadInteger(int numbytes)
-		{
-			int val = 0;
-			int raise = 1;
-			for (int x=0; x < numbytes; x++)
-			{
-				int b = (int)_packet.ReadByte();
-				val += (b*raise);
-				raise *= 256;
-			}
-			return val;
-		}
-
-		/// <summary>
-		/// 
-		/// </summary>
-		/// <returns></returns>
-		public int ReadLength()
-		{
-			byte c  = (byte)_packet.ReadByte();
-			switch(c) 
-			{
-				case 251 : return (int) 0; 
-				case 252 : return ReadInteger(2);
-				case 253 : return ReadInteger(3);
-				case 254 : return ReadInteger(4);
-				default  : return (int) c;
-			}
-		}
-
-		public byte ReadByte()
-		{
-			return (byte)_packet.ReadByte();
-		}
-
-		public int ReadNBytes()
-		{
-			byte c = (byte)_packet.ReadByte();
-			if (c < 1 || c > 4) throw new MySQLException("Unexpected byte count received");
-			return ReadInteger((int)c);
-		}
-
-		public string ReadLenString()
-		{
-			int len = ReadLength();
-
-			byte[] buf = new Byte[len];
-			_packet.Read(buf, 0, len);
-
-			String s = new String('c', 0);
-			for (int x=0; x < buf.Length; x++)
-				s += Convert.ToChar(buf[x]);
-			return s;
-		}
-
-
-		void CheckResult()
-		{
-			ReadPacket();
-
-			m_LastResult = (byte)_packet.ReadByte();
-
-			if (0xff == m_LastResult) 
-			{
-				int errno = ReadInteger(2);
-				string msg = ReadString();
-				throw new MySQLException(msg, errno);
-			}
-		}
-
-		/// <summary>
-		/// 
-		/// </summary>
-		/// <returns></returns>
-		public bool IsLastPacketSignal() 
-		{
-			byte b = (byte)_packet.ReadByte();
-			_packet.Position--;
-
-			if ((_packet.Length - HEADER_LEN) == 1 && b == 0xfe)
-			{
-				return true;
-			}
-
-			return false;
-		}
-
-		/// <summary>
-		/// Read the byte data from the server for the next column
-		/// </summary>
-		/// <returns></returns>
-		public byte[] ReadColumnData()
-		{
-			int		len;
-
-			byte c = (byte)_packet.ReadByte(); 
-
-			switch (c)
-			{
-				case 251:  return null; //new byte[1] { c }; 
-				case 252:  len = ReadInteger(2); break;
-				case 253:  len = ReadInteger(3); break;
-				case 254:  len = ReadInteger(4); break;
-				default:   len = c; break;
-			}
-
-			byte[] buf = new Byte[len];
-			_packet.Read(buf, 0, len);
-			return buf;
-		}
-
-
-		/// <summary>
-		/// Sends the specified command to the database
-		/// </summary>
-		/// <param name="command">Command to execute</param>
-		/// <param name="text">Text attribute of command</param>
-		/// <returns>Result packet returned from database server</returns>
-		public void SendCommand( DBCmd command, String text ) 
-		{
-			m_Seq = -1;
-			ResetPacket();
-
-			_packet.WriteByte( (byte)command );
-
-			if (text != null && text.Length > 0)
-				WriteStringNoNull(text);
-
-			try 
-			{
-				WritePacket();
-
-				if (command != DBCmd.QUIT)
-					CheckResult();
-			}
-			catch (Exception e) 
-			{
-				throw e;
-			}
-		}
-
-		public void SendQuery( byte[] sql )
-		{
-			try 
-			{
-				m_Seq = -1;
-				ResetPacket();
-
-				_packet.WriteByte( (byte)DBCmd.QUERY );
-				_packet.Write( sql, 0, sql.Length );
-
-				WritePacket();
-				CheckResult();
-			}
-			catch (Exception e) 
-			{
-				throw e;
-			}
-		}
-
-		#region PasswordStuff
-		private static double rand(ref long seed1, ref long seed2)
-		{
-			seed1 = (seed1 * 3) + seed2;
-			seed1 %= 0x3fffffff;
-			seed2 = (seed1 + seed2 + 33) % 0x3fffffff;
-			return (seed1 / (double)0x3fffffff);
-		}
-
-		/// <summary>
-		/// 
-		/// </summary>
-		/// <param name="password"></param>
-		/// <param name="seed"></param>
-		/// <returns></returns>
-		public static String EncryptPassword(String password, String message, bool new_ver)
-		{
-			if (password == null || password.Length == 0)
-				return password;
-
-			long[] hash_message = Hash(message);
-			long[] hash_pass = Hash(password);
-
-			long seed1 = (hash_message[0]^hash_pass[0]) % 0x3fffffff;
-			long seed2 = (hash_message[1]^hash_pass[1]) % 0x3fffffff;
-
-			char[] scrambled = new char[message.Length];
-			for (int x=0; x < message.Length; x++) 
-			{
-				double r = rand(ref seed1, ref seed2);
-				scrambled[x] = (char)(Math.Floor(r*31) + 64);
-			}
-
-			if (new_ver)
-			{						/* Make it harder to break */
-				char extra = (char)Math.Floor( rand(ref seed1, ref seed2) * 31 );
-				for (int x=0; x < scrambled.Length; x++)
-					scrambled[x] ^= extra;
-			}
-
-			return new string(scrambled);
-		}
-
-		/// <summary>
-		/// 
-		/// </summary>
-		/// <param name="P"></param>
-		/// <returns></returns>
-		static long[] Hash(String P) 
-		{
-			long val1 = 1345345333;
-			long val2 = 0x12345671;
-			long inc  = 7;
-
-			for (int i=0; i < P.Length; i++) 
-			{
-				if (P[i] == ' ' || P[i] == '\t') continue;
-				long temp = (long)(0xff & P[i]);
-				val1 ^= (((val1 & 63)+inc)*temp) + (val1 << 8);
-				val2 += (val2 << 8) ^ val1;
-				inc += temp;
-			}
-
-			long[] hash = new long[2];
-			hash[0] = val1 & 0x7fffffff;
-			hash[1] = val2 & 0x7fffffff;
-			return hash;
-		}
-		#endregion
-	}
-}
+// ByteFX.Data data access components for .Net
+// Copyright (C) 2002-2003  ByteFX, Inc.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.IO;
+using ICSharpCode.SharpZipLib.Zip.Compression;
+using System.Security.Cryptography;
+using ByteFX.Data.Common;
+using System.Text;
+
+namespace ByteFX.Data.MySqlClient
+{
+	/// <summary>
+	/// Summary description for Driver.
+	/// </summary>
+	internal class Driver
+	{
+		protected const int HEADER_LEN = 4;
+		protected const int MIN_COMPRESS_LENGTH = 50;
+
+		protected MySqlStream		stream;
+		protected Encoding			encoding;
+		protected byte				packetSeq;
+		protected int				timeOut;
+		protected long				maxPacketSize;
+		protected Packet			peekedPacket = null;
+		protected ByteFX.Data.Common.Version	serverVersion;
+		protected bool				isOpen;
+
+		int		protocol;
+		uint	threadID;
+		String	encryptionSeed;
+		int		serverCaps;
+		bool	useCompression = false;
+
+
+		public Driver()
+		{
+			packetSeq = 0;
+			encoding = System.Text.Encoding.Default;
+			isOpen = false;
+		}
+
+		#region Properties
+		public bool IsDead
+		{
+			get 
+			{ 
+				return stream.IsClosed;
+			}
+		}
+		#endregion
+
+		public Encoding Encoding 
+		{
+			get { return encoding; }
+			set { encoding = value; }
+		}
+
+		public long MaxPacketSize 
+		{
+			get { return maxPacketSize; }
+			set { maxPacketSize = value; }
+		}
+
+		/// <summary>
+		/// 
+		/// </summary>
+		/// <param name="host"></param>
+		/// <param name="port"></param>
+		/// <param name="userid"></param>
+		/// <param name="password"></param>
+		public void Open( String host, int port, String userid, String password, 
+			bool UseCompression, int connectTimeout ) 
+		{
+			timeOut = connectTimeout;
+			stream = new MySqlStream( host, port, timeOut );
+
+			Packet packet = ReadPacket();
+
+			// read off the protocol version
+			protocol = packet.ReadByte();
+			serverVersion = ByteFX.Data.Common.Version.Parse( packet.ReadString() );
+			threadID = packet.ReadInteger(4);
+			encryptionSeed = packet.ReadString();
+
+			// read in Server capabilities if they are provided
+			serverCaps = 0;
+			if (packet.CanRead)
+				serverCaps = (int)packet.ReadInteger(2);
+
+			Authenticate( userid, password, UseCompression );
+			isOpen = true;
+		}
+
+		/// <summary>
+		/// 
+		/// </summary>
+		/// <param name="userid"></param>
+		/// <param name="password"></param>
+		private void Authenticate( String userid, String password, bool UseCompression )
+		{
+			ClientParam clientParam = ClientParam.CLIENT_FOUND_ROWS | ClientParam.CLIENT_LONG_FLAG;
+
+			if ((serverCaps & (int)ClientParam.CLIENT_COMPRESS) != 0 && UseCompression)
+			{
+				clientParam |= ClientParam.CLIENT_COMPRESS;
+			}
+
+			clientParam |= ClientParam.CLIENT_LONG_PASSWORD;
+			clientParam |= ClientParam.CLIENT_LOCAL_FILES;
+//			if (serverVersion.isAtLeast(4,1,0))
+//				clientParam |= ClientParam.CLIENT_PROTOCOL_41;
+			if ( (serverCaps & (int)ClientParam.CLIENT_SECURE_CONNECTION ) != 0 && password.Length > 0 )
+				clientParam |= ClientParam.CLIENT_SECURE_CONNECTION;
+
+			int packetLength = userid.Length + 16 + 6 + 4;  // Passwords can be 16 chars long
+
+			Packet packet = new Packet();// packetLength );
+
+			if ((clientParam & ClientParam.CLIENT_PROTOCOL_41) != 0)
+			{
+				packet.WriteInteger( (int)clientParam, 4 );
+				packet.WriteInteger( (256*256*256)-1, 4 );
+			}
+			else
+			{
+				packet.WriteInteger( (int)clientParam, 2 );
+				packet.WriteInteger( 255*255*255, 3 );
+			}
+
+			packet.WriteString( userid, encoding  );
+			if ( (clientParam & ClientParam.CLIENT_SECURE_CONNECTION ) != 0 )
+			{
+				// use the new authentication system
+				AuthenticateSecurely( packet, password );
+			}
+			else
+			{
+				// use old authentication system
+				packet.WriteString( EncryptPassword(password, encryptionSeed, protocol > 9), encoding );
+				SendPacket(packet);
+			}
+
+			packet = ReadPacket();
+			if ((clientParam & ClientParam.CLIENT_COMPRESS) != 0)
+				useCompression = true;
+		}
+
+		/// <summary>
+		/// AuthenticateSecurity implements the new 4.1 authentication scheme
+		/// </summary>
+		/// <param name="password"></param>
+		private void AuthenticateSecurely( Packet packet, string password )
+		{
+			packet.WriteString("xxxxxxxx", encoding );
+			SendPacket(packet);
+
+			packet = ReadPacket();
+
+			// compute pass1 hash
+			string newPass = password.Replace(" ","").Replace("\t","");
+			SHA1 sha = new SHA1CryptoServiceProvider(); 
+			byte[] firstPassBytes = sha.ComputeHash( System.Text.Encoding.Default.GetBytes(newPass));
+
+			byte[] salt = packet.GetBytes();
+			byte[] input = new byte[ firstPassBytes.Length + 4 ];
+			salt.CopyTo( input, 0 );
+			firstPassBytes.CopyTo( input, 4 );
+			byte[] outPass = new byte[100];
+			byte[] secondPassBytes = sha.ComputeHash( input );
+
+			byte[] cryptSalt = new byte[20];
+			Security.ArrayCrypt( salt, 4, cryptSalt, 0, secondPassBytes, 20 );
+
+			Security.ArrayCrypt( cryptSalt, 0, firstPassBytes, 0, firstPassBytes, 20 );
+
+			// send the packet
+			packet = new Packet();
+			packet.WriteBytes( firstPassBytes, 0, 20 );
+			SendPacket(packet);
+		}
+
+
+		/// <summary>
+		/// 
+		/// </summary>
+		private Packet ReadRawPacket()
+		{
+			int packetLength = stream.ReadInt24();
+			int unCompressedLen = 0;
+
+			// read the packet sequence and make sure it makes sense
+			byte seq = (byte)stream.ReadByte();
+			if (seq != packetSeq) 
+				throw new MySqlException("Unknown transmission status: sequence out of order");
+	
+			if (useCompression) 
+				unCompressedLen = stream.ReadInt24();
+
+			byte[] buffer;
+			if (useCompression && unCompressedLen > 0)
+			{
+				byte[] compressed_buffer = new Byte[packetLength];
+				buffer = new Byte[unCompressedLen];
+
+				// read in the compressed data
+				stream.Read( compressed_buffer, 0, packetLength );
+
+				// inflate it
+				Inflater i = new Inflater();
+				i.SetInput( compressed_buffer );
+				i.Inflate( buffer );
+			}
+			else 
+			{
+				buffer = new Byte[packetLength];
+				stream.Read( buffer, 0, packetLength);
+			}
+
+			packetSeq++;
+			Packet packet = new Packet( buffer );
+			packet.Encoding = encoding;
+			return packet;
+		}
+
+		/// <summary>
+		/// 
+		/// </summary>
+		public void SendFileToServer()
+		{
+		}
+
+
+		/// <summary>
+		/// 
+		/// </summary>
+		/// <returns></returns>
+		public Packet PeekPacket()
+		{
+			// we can peek the same packet more than once
+			if (peekedPacket != null)
+				return peekedPacket;
+
+			peekedPacket = ReadPacket();
+			return peekedPacket;
+		}
+
+		/// <summary>
+		/// 
+		/// </summary>
+		/// <returns></returns>
+		public Packet ReadPacket()
+		{
+			// if we have a peeked packet, return it now
+			if (peekedPacket != null) 
+			{
+				Packet p = peekedPacket;
+				peekedPacket = null;
+				return p;
+			}
+
+			Packet packet = ReadRawPacket();
+
+			if (packet.Type == PacketType.Error)
+			{
+				int errorCode = (int)packet.ReadInteger(2);
+				string msg = packet.ReadString();
+				throw new MySqlException( msg, errorCode );
+			}
+			else 
+				packet.Position = 0;
+
+			return packet;
+		}
+
+		/// <summary>
+		/// 
+		/// </summary>
+		/// <param name="packet"></param>
+		private Packet LoadSchemaIntoPacket( Packet packet, int count )
+		{
+			for (int i=0; i < count; i++) 
+			{
+				Packet colPacket = ReadRawPacket();
+				packet.AppendPacket( colPacket );
+			}
+			Packet lastPacket = ReadRawPacket();
+			if (lastPacket.Type != PacketType.Last)
+				throw new MySqlException("Last packet not received when expected");
+
+			packet.Type = PacketType.ResultSchema;
+			packet.Position = 0;
+			return packet;
+		}
+
+		/// <summary>
+		/// 
+		/// </summary>
+		/// <returns></returns>
+/*		protected byte[] CompressPacket(Packet packet)
+		{
+			// compress the entire packet except the length
+
+			// make sure we are using a packet prep'ed for compression
+			// and that our packet is large enough to warrant compression
+			// re: my_compress.c from mysql src
+			int offset = HEADER_LEN + COMPRESS_HEADER_LEN;
+			int original_len = (int)(_packet.Length - offset);
+			if (original_len < MIN_COMPRESS_LEN) return 0;
+
+			byte[] packetData = _packet.ToArray();
+
+			byte[] output = new Byte[ original_len * 2 ];
+			Deflater d = new Deflater();
+			d.SetInput( packetData, offset, original_len );
+			d.Finish();
+			int comp_len = d.Deflate( output, offset, output.Length - offset  );
+
+			if (comp_len > original_len) return 0;
+			_packet = new MemoryStream( output, 0, comp_len + offset );
+			return (int)comp_len;
+		}
+*/
+		protected byte[] CompressPacket(Packet packet)
+		{
+			if (packet.Length < MIN_COMPRESS_LENGTH) return null;
+
+			byte[] compressed_buffer = new byte[packet.Length * 2];
+			Deflater deflater = new Deflater();
+			deflater.SetInput( packet.GetBytes(), 0, packet.Length );
+			deflater.Finish();
+			int comp_len = deflater.Deflate( compressed_buffer, 0, compressed_buffer.Length );
+			if (comp_len > packet.Length) return null;
+			return compressed_buffer;
+		}
+
+		protected void SendPacket(Packet packet)
+		{
+			Packet header = null;
+			byte[] buffer = null;
+
+			if (useCompression)
+			{
+				byte[] compressed_bytes = CompressPacket(packet);
+				header = new Packet();
+				
+				// if we succeeded in compressing
+				if (compressed_bytes != null) 
+				{
+					header.WriteInteger( compressed_bytes.Length, 3 );
+					header.WriteByte( packetSeq );
+					header.WriteInteger( packet.Length + HEADER_LEN, 3 );
+					buffer = compressed_bytes;
+				}
+				else
+				{
+					header.WriteInteger( packet.Length + HEADER_LEN, 3 );
+					header.WriteByte( packetSeq );
+					header.WriteInteger( 0, 3 );
+					buffer = packet.GetBytes();
+				}
+				// now write the internal header
+				header.WriteInteger( packet.Length, 3 );
+				header.WriteByte( 0 );
+			}
+			else 
+			{
+				header = new Packet();
+				header.WriteInteger( packet.Length, 3 );
+				header.WriteByte( packetSeq );
+				buffer = packet.GetBytes();
+			}
+			packetSeq++;
+
+			// send the data to eth server
+			stream.Write( header.GetBytes(), 0, header.Length );
+			stream.Write( buffer, 0, buffer.Length );
+			stream.Flush();
+		}
+
+
+		public void Close() 
+		{
+			stream.Close();
+		}
+
+
+		/// <summary>
+		/// Sends the specified command to the database
+		/// </summary>
+		/// <param name="command">Command to execute</param>
+		/// <param name="text">Text attribute of command</param>
+		/// <returns>Result packet returned from database server</returns>
+		public void SendCommand( DBCmd command, String text ) 
+		{
+			Packet packet = new Packet();
+			packetSeq = 0;
+			packet.WriteByte( (byte)command );
+			packet.WriteStringNoNull( text, encoding );
+			SendPacket(packet);
+			
+			packet = ReadPacket();
+			if (packet.Type != PacketType.UpdateOrOk)
+				throw new MySqlException("SendCommand failed for command " + text );
+		}
+
+		/// <summary>
+		/// SendQuery sends a byte array of SQL to the server
+		/// </summary>
+		/// <param name="sql"></param>
+		/// <returns>A packet containing the bytes returned by the server</returns>
+		public Packet SendQuery( byte[] sql )
+		{
+			Packet packet = new Packet();
+			packetSeq = 0;
+			packet.WriteByte( (byte)DBCmd.QUERY );
+			packet.WriteBytes( sql, 0, sql.Length );
+
+			SendPacket( packet );
+			return ReadPacket();
+		}
+
+		public Packet SendSql( string sql )
+		{
+			byte[] bytes = encoding.GetBytes(sql);
+
+			Packet packet = new Packet();
+			packetSeq = 0;
+			packet.WriteByte( (byte)DBCmd.QUERY );
+			packet.WriteBytes( bytes, 0, bytes.Length );
+
+			SendPacket( packet );
+			packet = ReadPacket();
+
+			switch (packet.Type)
+			{
+				case PacketType.LoadDataLocal:
+					SendFileToServer();
+					return null;
+
+				case PacketType.Other:
+					packet.Position = 0;
+					int count = (int)packet.ReadLenInteger();
+					if (count > 0) 
+						return LoadSchemaIntoPacket( packet, count );
+					else
+						return packet;
+			}
+
+			return packet;
+		}
+
+		#region PasswordStuff
+		private static double rand(ref long seed1, ref long seed2)
+		{
+			seed1 = (seed1 * 3) + seed2;
+			seed1 %= 0x3fffffff;
+			seed2 = (seed1 + seed2 + 33) % 0x3fffffff;
+			return (seed1 / (double)0x3fffffff);
+		}
+
+		/// <summary>
+		/// 
+		/// </summary>
+		/// <param name="password"></param>
+		/// <param name="seed"></param>
+		/// <returns></returns>
+		public static String EncryptPassword(String password, String message, bool new_ver)
+		{
+			if (password == null || password.Length == 0)
+				return password;
+
+			long[] hash_message = Hash(message);
+			long[] hash_pass = Hash(password);
+
+			long seed1 = (hash_message[0]^hash_pass[0]) % 0x3fffffff;
+			long seed2 = (hash_message[1]^hash_pass[1]) % 0x3fffffff;
+
+			char[] scrambled = new char[message.Length];
+			for (int x=0; x < message.Length; x++) 
+			{
+				double r = rand(ref seed1, ref seed2);
+				scrambled[x] = (char)(Math.Floor(r*31) + 64);
+			}
+
+			if (new_ver)
+			{						/* Make it harder to break */
+				char extra = (char)Math.Floor( rand(ref seed1, ref seed2) * 31 );
+				for (int x=0; x < scrambled.Length; x++)
+					scrambled[x] ^= extra;
+			}
+
+			return new string(scrambled);
+		}
+
+		/// <summary>
+		/// 
+		/// </summary>
+		/// <param name="P"></param>
+		/// <returns></returns>
+		static long[] Hash(String P) 
+		{
+			long val1 = 1345345333;
+			long val2 = 0x12345671;
+			long inc  = 7;
+
+			for (int i=0; i < P.Length; i++) 
+			{
+				if (P[i] == ' ' || P[i] == '\t') continue;
+				long temp = (long)(0xff & P[i]);
+				val1 ^= (((val1 & 63)+inc)*temp) + (val1 << 8);
+				val2 += (val2 << 8) ^ val1;
+				inc += temp;
+			}
+
+			long[] hash = new long[2];
+			hash[0] = val1 & 0x7fffffff;
+			hash[1] = val2 & 0x7fffffff;
+			return hash;
+		}
+		#endregion
+	}
+}

+ 48 - 40
mcs/class/ByteFX.Data/mysqlclient/Exception.cs

@@ -1,40 +1,48 @@
-// ByteFX.Data data access components for .Net
-// Copyright (C) 2002-2003  ByteFX, Inc.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-using System;
-
-namespace ByteFX.Data.MySQLClient
-{
-	/// <summary>
-	/// Summary description for MySQLException.
-	/// </summary>
-	public sealed class MySQLException : SystemException
-	{
-		public MySQLException(string msg) 
-		{
-		}
-
-		public MySQLException() 
-		{
-		}
-
-		public MySQLException(string msg, int errno) : base(msg)
-		{
-			
-		}
-	}
-}
+// ByteFX.Data data access components for .Net
+// Copyright (C) 2002-2003  ByteFX, Inc.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+using System;
+using System.Runtime.Serialization;
+
+namespace ByteFX.Data.MySqlClient
+{
+	/// <summary>
+	/// Summary description for MySqlException.
+	/// </summary>
+	[Serializable]
+	public sealed class MySqlException : Exception
+	{
+		public MySqlException(string msg) : base(msg)
+		{
+		}
+
+		public MySqlException() 
+		{
+		}
+
+		public MySqlException(string msg, int errno) : base(msg)
+		{
+			
+		}
+
+		public MySqlException(SerializationInfo info,
+					StreamingContext context) : base(info, context)
+		{
+		}
+
+	}
+}

+ 392 - 400
mcs/class/ByteFX.Data/mysqlclient/Field.cs

@@ -1,400 +1,392 @@
-// ByteFX.Data data access components for .Net
-// Copyright (C) 2002-2003  ByteFX, Inc.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-using System;
-using System.Data;
-using System.Data.SqlTypes;
-
-namespace ByteFX.Data.MySQLClient
-{
-	
-
-	internal enum MySQLFieldType : byte
-	{
-		DECIMAL		=   0,
-		TINY        =   1,
-		BYTE		=   1,
-		SHORT       =   2,
-		LONG        =   3,
-		FLOAT       =   4,
-		DOUBLE      =   5,
-		NULL        =   6,
-		TIMESTAMP   =   7,
-		LONGLONG    =   8,
-		INT24       =   9,
-		DATE        =  10,
-		TIME        =  11,
-		DATETIME    =  12,
-		YEAR        =  13,
-		NEWDATE     =  14,
-		ENUM        = 247,
-		SET         = 248,
-		TINY_BLOB   = 249,
-		MEDIUM_BLOB = 250,
-		LONG_BLOB   = 251,
-		BLOB        = 252,
-		VAR_STRING  = 253,
-		STRING      = 254
-	};
-
-	internal enum ColFlags : int
-	{
-		NOT_NULL		= 1,
-		PRIMARY_KEY		= 2,
-		UNIQUE_KEY		= 4,
-		MULTIPLE_KEY	= 8,
-		BLOB			= 16,
-		UNSIGNED		= 32,
-		ZERO_FILL		= 64,
-		BINARY			= 128,
-		ENUM			= 256,
-		AUTO_INCREMENT	= 512,
-		TIMESTAMP		= 1024,
-		SET				= 2048,
-		NUMBER			= 32768
-	};
-	
-	/// <summary>
-	/// Summary description for Field.
-	/// </summary>
-	internal class MySQLField : Common.Field
-	{
-		  MySQLFieldType	m_FieldType;
-		public	ColFlags		ColumnFlags;
-		public	int				ColumnDecimals;
-		object					m_Value;
-
-		public MySQLField()
-		{
-		}
-
-		public void ReadSchemaInfo( Driver d )
-		{	
-			d.ReadPacket();
-
-			m_TableName = d.ReadLenString();
-			m_ColName = d.ReadLenString();
-			m_ColLen = d.ReadNBytes();
-			m_FieldType = (MySQLFieldType)d.ReadNBytes();
-			d.ReadByte();									// this is apparently 2 -- not sure what it is for
-			ColumnFlags = (ColFlags)d.ReadInteger(2);		//(short)(d.ReadByte() & 0xff);
-			ColumnDecimals = d.ReadByte();
-		}
-
-		public object GetValue() 
-		{
-			return m_Value;
-		}
-
-		public int NumericPrecision()
-		{
-			if (m_FieldType == MySQLFieldType.DECIMAL)
-				return ColumnLength;
-			return -1;
-		}
-
-		public int NumericScale()
-		{
-			if (m_FieldType == MySQLFieldType.DECIMAL)
-				return ColumnDecimals;
-			return -1;
-		}
-
-		public bool IsAutoIncrement()
-		{
-			return (ColumnFlags & ColFlags.AUTO_INCREMENT) > 0;
-		}
-
-		public bool IsNumeric()
-		{
-			return (ColumnFlags & ColFlags.NUMBER) > 0;
-		}
-
-		public bool AllowsNull()
-		{
-			return (ColumnFlags & ColFlags.NOT_NULL) == 0;
-		}
-
-		public bool IsUnique()
-		{
-			return (ColumnFlags & ColFlags.UNIQUE_KEY) > 0;
-		}
-
-		public bool IsPrimaryKey()
-		{
-			return (ColumnFlags & ColFlags.PRIMARY_KEY) > 0;
-		}
-
-		public bool IsBlob() 
-		{
-			return (ColumnFlags & ColFlags.BLOB) > 0;
-		}
-
-		public bool IsBinary()
-		{
-			return (ColumnFlags & ColFlags.BINARY) > 0;
-		}
-
-		public bool IsUnsigned()
-		{
-			return (ColumnFlags & ColFlags.UNSIGNED) > 0;
-		}
-
-		public void SetValueData( byte[] data )
-		{
-			if (data == null) 
-			{
-				m_Value = null;
-				return;
-			}
-
-			// if it is a blob and binary, then GetBytes is the way to go
-			if ( IsBlob() && IsBinary() ) 
-			{
-				m_DbType = DbType.Binary;
-				return;
-			}
-
-			char[] _Chars = System.Text.Encoding.ASCII.GetChars( data );
-			string sValue = new string(_Chars);
-
-			switch(m_FieldType)
-			{
-				case MySQLFieldType.BYTE:
-					if (IsUnsigned()) 
-						m_Value = Byte.Parse( sValue );
-					else 
-						m_Value = SByte.Parse( sValue );
-					break;
-
-				case MySQLFieldType.SHORT:
-					if (IsUnsigned()) 
-						m_Value = UInt16.Parse( sValue );
-					else 
-						m_Value = Int16.Parse( sValue );
-					break;
-
-				case MySQLFieldType.INT24:
-				case MySQLFieldType.LONG : 
-					if (IsUnsigned()) 
-						m_Value = UInt32.Parse( sValue );
-					else 
-						m_Value = Int32.Parse( sValue );
-					break;
-
-				case MySQLFieldType.LONGLONG:
-					if (IsUnsigned()) 
-						m_Value = UInt64.Parse( sValue );
-					else 
-						m_Value = Int64.Parse( sValue );
-					break;
-
-				case MySQLFieldType.FLOAT:
-					m_Value = Single.Parse( sValue );
-					break;
-
-				case MySQLFieldType.DOUBLE:
-					m_Value = Double.Parse( sValue );
-					break;
-
-				case MySQLFieldType.DECIMAL:
-					m_Value = Decimal.Parse( sValue );
-					break;
-			
-				case MySQLFieldType.DATE:
-					if (sValue == "0000-00-00")
-						m_Value = null;
-					else
-						m_Value = DateTime.ParseExact( sValue, "yyyy-MM-dd", new System.Globalization.DateTimeFormatInfo());
-						
-					break;
-
-				case MySQLFieldType.DATETIME:
-					if (sValue == "0000-00-00 00:00:00")
-						m_Value = null;
-					else
-						m_Value = DateTime.ParseExact( sValue, "yyyy-MM-dd HH:mm:ss", new System.Globalization.DateTimeFormatInfo());
-
-					break;
-
-				case MySQLFieldType.TIME:
-					m_Value = TimeSpan.Parse(sValue);
-					break;
-
-				case MySQLFieldType.TIMESTAMP:
-					string pattern;
-				switch (ColumnLength) 
-				{
-					case 2:  pattern = "yy"; break;
-					case 4:  pattern = "yyMM"; break;
-					case 6:  pattern = "yyMMdd"; break;
-					case 8:  pattern = "yyyyMMdd"; break;
-					case 10: pattern = "yyMMddHHmm"; break;
-					case 12: pattern = "yyMMddHHmmss"; break;
-					case 14: 
-					default: pattern = "yyyyMMddHHmmss"; break;
-				}
-					m_Value = DateTime.ParseExact( sValue, pattern, new System.Globalization.DateTimeFormatInfo());
-					break;
-
-				case MySQLFieldType.STRING:
-				case MySQLFieldType.VAR_STRING:
-				case MySQLFieldType.BLOB:
-				case MySQLFieldType.TINY_BLOB:
-				case MySQLFieldType.LONG_BLOB:
-				case MySQLFieldType.MEDIUM_BLOB:
-					m_Value = sValue;
-					break;
-
-				default:
-					throw new NotSupportedException();
-			}
-		}
-
-		public string GetFieldTypeName() 
-		{
-			switch (m_FieldType) 
-			{
-				case MySQLFieldType.DECIMAL:		return "DECIMAL";
-				case MySQLFieldType.TINY:			return "TINY";
-				case MySQLFieldType.SHORT:			return "SHORT";
-				case MySQLFieldType.LONG:			return "LONG";
-				case MySQLFieldType.FLOAT:			return "FLOAT";
-				case MySQLFieldType.DOUBLE:			return "DOUBLE";
-				case MySQLFieldType.NULL:			return "NULL";
-				case MySQLFieldType.TIMESTAMP:		return "TIMESTAMP";
-				case MySQLFieldType.LONGLONG:		return "LONGLONG";
-				case MySQLFieldType.INT24:			return "INT24";
-				case MySQLFieldType.DATE:			return "DATE";
-				case MySQLFieldType.TIME:			return "TIME";
-				case MySQLFieldType.DATETIME:		return "DATETIME";
-				case MySQLFieldType.YEAR:			return "YEAR";
-				case MySQLFieldType.NEWDATE:		return "NEWDATE";
-				case MySQLFieldType.ENUM:			return "ENUM";
-				case MySQLFieldType.SET:			return "SET";
-				case MySQLFieldType.TINY_BLOB:		return "TINY_BLOB";
-				case MySQLFieldType.MEDIUM_BLOB:	return "MEDIUM_BLOB";
-				case MySQLFieldType.LONG_BLOB:		return "LONG_BLOB";
-				case MySQLFieldType.BLOB:			return "BLOB";
-				case MySQLFieldType.VAR_STRING:	return "VAR_STRING";
-				case MySQLFieldType.STRING:		return "STRING";
-			}
-			return "Unknown typeid";
-		}
-
-
-		public Type GetFieldType() 
-		{
-			switch (m_FieldType) 
-			{
-				case MySQLFieldType.BYTE:		return Type.GetType("System.Byte");
-
-				case MySQLFieldType.SHORT:		return Type.GetType("System.Int16");
-
-				case MySQLFieldType.LONG:
-				case MySQLFieldType.INT24:		return Type.GetType("System.Int32", false, true);
-
-				case MySQLFieldType.FLOAT:		return Type.GetType("System.Single");
-				case MySQLFieldType.DOUBLE:		return Type.GetType("System.Double");
-
-				case MySQLFieldType.TIME:		return Type.GetType("System.TimeSpan");
-
-				case MySQLFieldType.DATE:
-				case MySQLFieldType.DATETIME:
-				case MySQLFieldType.TIMESTAMP:	return Type.GetType("System.DateTime");
-
-				case MySQLFieldType.LONGLONG:	return Type.GetType("System.Int64");
-
-				case MySQLFieldType.DECIMAL:	return Type.GetType("System.Decimal");
-
-				case MySQLFieldType.VAR_STRING:	
-				case MySQLFieldType.STRING:		return Type.GetType("System.String");
-
-				case MySQLFieldType.TINY_BLOB:
-				case MySQLFieldType.MEDIUM_BLOB:
-				case MySQLFieldType.LONG_BLOB:
-				case MySQLFieldType.BLOB:		return Type.GetType("System.Array");
-
-				default:
-				case MySQLFieldType.NULL:		return Type.GetType("System.null", false, true);
-			}
-		}
-
-		public DbType GetDbType() 
-		{
-			switch (m_FieldType) 
-			{
-				case MySQLFieldType.DECIMAL:		return DbType.Decimal;
-				case MySQLFieldType.TINY:			return DbType.Byte;
-				case MySQLFieldType.SHORT:			
-					if (IsUnsigned())
-						return DbType.UInt16;
-					else
-						return DbType.Int16;
-
-				case MySQLFieldType.LONG:			
-					if (IsUnsigned())
-						return DbType.UInt32;
-					else
-						return DbType.Int32;
-
-				case MySQLFieldType.FLOAT:			return DbType.Double;
-				case MySQLFieldType.DOUBLE:			return DbType.Double;
-				case MySQLFieldType.NULL:			return DbType.Object;
-
-				case MySQLFieldType.LONGLONG:		
-					if (IsUnsigned())
-						return DbType.UInt64;
-					else
-						return DbType.Int64;
-
-				case MySQLFieldType.INT24:			
-					if (IsUnsigned())
-						return DbType.UInt32;
-					else
-						return DbType.Int32;
-				case MySQLFieldType.DATE:			
-				case MySQLFieldType.YEAR:
-				case MySQLFieldType.NEWDATE:
-					return DbType.Date;
-
-				case MySQLFieldType.TIME:			
-					return DbType.Time;
-				case MySQLFieldType.DATETIME:		
-				case MySQLFieldType.TIMESTAMP:
-					return DbType.DateTime;
-
-				case MySQLFieldType.ENUM:			return DbType.UInt32;
-				case MySQLFieldType.SET:			return DbType.Object;
-
-				case MySQLFieldType.TINY_BLOB:		
-				case MySQLFieldType.MEDIUM_BLOB:
-				case MySQLFieldType.LONG_BLOB:
-				case MySQLFieldType.BLOB:
-					if (IsBinary()) return DbType.Binary;
-					return DbType.String;
-				case MySQLFieldType.VAR_STRING:
-					return DbType.String;
-				case MySQLFieldType.STRING:
-					return DbType.StringFixedLength;
-			}
-			throw new Exception("unknown MySQLFieldType");
-		}
-
-	}
-
-}
+// ByteFX.Data data access components for .Net
+// Copyright (C) 2002-2003  ByteFX, Inc.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+using System;
+using System.Data;
+using System.Data.SqlTypes;
+using System.Globalization;
+using System.Text;
+
+namespace ByteFX.Data.MySqlClient
+{
+	internal enum ColFlags : int
+	{
+		NOT_NULL		= 1,
+		PRIMARY_KEY		= 2,
+		UNIQUE_KEY		= 4,
+		MULTIPLE_KEY	= 8,
+		BLOB			= 16,
+		UNSIGNED		= 32,
+		ZERO_FILL		= 64,
+		BINARY			= 128,
+		ENUM			= 256,
+		AUTO_INCREMENT	= 512,
+		TIMESTAMP		= 1024,
+		SET				= 2048,
+		NUMBER			= 32768
+	};
+	
+	/// <summary>
+	/// Summary description for Field.
+	/// </summary>
+	internal class MySqlField : Common.Field
+	{
+		  MySqlDbType			colType;
+		public	ColFlags		colFlags;
+		public	int				colDecimals;
+//		System.Text.Encoding	encoding;
+		private static NumberFormatInfo		numberFormat = null;
+
+
+		public MySqlField()
+		{
+//			this.encoding = encoding;
+			if (numberFormat == null)
+			{
+				numberFormat = (NumberFormatInfo)NumberFormatInfo.InvariantInfo.Clone();
+				numberFormat.NumberDecimalSeparator = ".";
+			}
+		}
+
+		public void ReadSchemaInfo( Packet packet )
+		{	
+			tableName = packet.ReadLenString();
+			colName = packet.ReadLenString();
+			colLen = (int)packet.ReadNBytes();
+			colType = (MySqlDbType)packet.ReadNBytes();
+			packet.ReadByte();									// this is apparently 2 -- not sure what it is for
+			colFlags = (ColFlags)packet.ReadInteger(2);		//(short)(d.ReadByte() & 0xff);
+			colDecimals = packet.ReadByte();
+		}
+
+		public object GetValue() 
+		{
+			return value;
+		}
+
+		public int NumericPrecision()
+		{
+			if (colType == MySqlDbType.Decimal)
+				return ((SqlDecimal)value).Precision;
+			return -1;
+		}
+
+		public int NumericScale()
+		{
+			if (colType == MySqlDbType.Decimal)
+				return ((SqlDecimal)value).Scale; 
+			return -1;
+		}
+
+		public bool IsAutoIncrement()
+		{
+			return (colFlags & ColFlags.AUTO_INCREMENT) > 0;
+		}
+
+		public bool IsNumeric()
+		{
+			return (colFlags & ColFlags.NUMBER) > 0;
+		}
+
+		public bool AllowsNull()
+		{
+			return (colFlags & ColFlags.NOT_NULL) == 0;
+		}
+
+		public bool IsUnique()
+		{
+			return (colFlags & ColFlags.UNIQUE_KEY) > 0;
+		}
+
+		public bool IsPrimaryKey()
+		{
+			return (colFlags & ColFlags.PRIMARY_KEY) > 0;
+		}
+
+		public bool IsBlob() 
+		{
+			return (colFlags & ColFlags.BLOB) > 0;
+		}
+
+		public bool IsBinary()
+		{
+			return (colFlags & ColFlags.BINARY) > 0;
+		}
+
+		public bool IsUnsigned()
+		{
+			return (colFlags & ColFlags.UNSIGNED) > 0;
+		}
+
+		public void SetValueData( byte[] data, int offset, int count, Encoding encoding )
+		{
+			if (data == null || count == 0) 
+			{
+				value = DBNull.Value;
+				return;
+			}
+
+			// if it is a blob and binary, then GetBytes is the way to go
+			if ( IsBlob() && IsBinary() ) 
+			{
+				dbType = DbType.Binary;
+				value = data;
+				return;
+			}
+
+			char[] _Chars = encoding.GetChars(data, offset, count );
+			string sValue = new string(_Chars);
+
+			switch(colType)
+			{
+				case MySqlDbType.Byte:
+					if (IsUnsigned())
+						value = Byte.Parse( sValue );
+					else
+						value = SByte.Parse( sValue );
+					break;
+
+				case MySqlDbType.Short:
+					if (IsUnsigned())
+						value = UInt16.Parse( sValue );
+					else
+						value = Int16.Parse( sValue );
+					break;
+					
+				case MySqlDbType.Long : 
+				case MySqlDbType.Int24:
+					if (IsUnsigned())
+						value = UInt32.Parse( sValue );
+					else
+						value = Int32.Parse( sValue );
+					break;
+
+				case MySqlDbType.LongLong:
+					if (IsUnsigned())
+						value = UInt64.Parse( sValue );
+					else
+						value = Int64.Parse( sValue );
+					break;
+
+				case MySqlDbType.Decimal:
+					value = Decimal.Parse( sValue , numberFormat );
+					break;
+
+				case MySqlDbType.Float:
+					value = Convert.ToSingle( sValue, numberFormat );
+					break;
+
+				case MySqlDbType.Double:
+					value = Convert.ToDouble( sValue, numberFormat );
+					break;
+
+				case MySqlDbType.Date:
+					ParseDateValue( "0000-00-00", "yyyy-MM-dd", sValue );
+					break;
+
+				case MySqlDbType.Datetime:
+					ParseDateValue( "0000-00-00 00:00:00", "yyyy-MM-dd HH:mm:ss", sValue );
+					break;
+
+				case MySqlDbType.Time:
+					if (sValue.Equals("00:00:00"))
+						value = DBNull.Value;
+					else
+						value = TimeSpan.Parse(sValue);
+					break;
+
+				case MySqlDbType.Timestamp:
+					string pattern;
+					string null_value = "00000000000000";
+					switch (ColumnLength) 
+					{
+						case 2:  pattern = "yy"; break;
+						case 4:  pattern = "yyMM"; break;
+						case 6:  pattern = "yyMMdd"; break;
+						case 8:  pattern = "yyyyMMdd"; break;
+						case 10: pattern = "yyMMddHHmm"; break;
+						case 12: pattern = "yyMMddHHmmss"; break;
+						case 14: 
+						default: pattern = "yyyyMMddHHmmss"; break;
+					}
+
+					if (ColumnLength > 2 && sValue.Equals( null_value.Substring(0, ColumnLength)))
+						value = DBNull.Value;
+					else
+						value = DateTime.ParseExact( sValue, pattern, new System.Globalization.DateTimeFormatInfo());
+					break;
+
+				case MySqlDbType.String:
+				case MySqlDbType.VarChar:
+				case MySqlDbType.Blob:
+				case MySqlDbType.TinyBlob:
+				case MySqlDbType.LongBlob:
+				case MySqlDbType.MediumBlob: 
+					value = sValue;
+					break;
+
+				default:
+					throw new NotSupportedException();
+			}
+		}
+
+		protected void ParseDateValue( string nullpattern, string pattern, string data )
+		{
+			if ( data.Equals (nullpattern) )
+				value = DBNull.Value;
+			else
+				value = DateTime.ParseExact( data, pattern, new System.Globalization.DateTimeFormatInfo());
+		}
+
+		public string GetFieldTypeName() 
+		{
+			switch (colType) 
+			{
+				case MySqlDbType.Decimal:		return "DECIMAL";
+				case MySqlDbType.Byte:			return "TINY";
+				case MySqlDbType.Short:			return "SHORT";
+				case MySqlDbType.Long:			return "LONG";
+				case MySqlDbType.Float:			return "FLOAT";
+				case MySqlDbType.Double:		return "DOUBLE";
+				case MySqlDbType.Null:			return "NULL";
+				case MySqlDbType.Timestamp:		return "TIMESTAMP";
+				case MySqlDbType.LongLong:		return "LONGLONG";
+				case MySqlDbType.Int24:			return "INT24";
+				case MySqlDbType.Date:			return "DATE";
+				case MySqlDbType.Time:			return "TIME";
+				case MySqlDbType.Datetime:		return "DATETIME";
+				case MySqlDbType.Year:			return "YEAR";
+				case MySqlDbType.Newdate:		return "NEWDATE";
+				case MySqlDbType.Enum:			return "ENUM";
+				case MySqlDbType.Set:			return "SET";
+				case MySqlDbType.TinyBlob:		return "TINY_BLOB";
+				case MySqlDbType.MediumBlob:	return "MEDIUM_BLOB";
+				case MySqlDbType.LongBlob:		return "LONG_BLOB";
+				case MySqlDbType.Blob:			return "BLOB";
+				case MySqlDbType.VarChar:	return "VAR_STRING";
+				case MySqlDbType.String:		return "STRING";
+			}
+			return "Unknown typeid";
+		}
+
+
+		public Type GetFieldType() 
+		{
+			switch (colType) 
+			{
+				case MySqlDbType.Byte:		return IsUnsigned() ? typeof(System.Byte) : typeof(System.SByte);
+
+				case MySqlDbType.Short:		return IsUnsigned() ? typeof(System.UInt16) : typeof(System.Int16);
+
+				case MySqlDbType.Long:
+				case MySqlDbType.Int24:		return IsUnsigned() ? typeof(System.UInt32) : typeof(System.Int32);
+
+				case MySqlDbType.LongLong:	return IsUnsigned() ? typeof(System.UInt64) : typeof(System.Int64);
+
+				case MySqlDbType.Float:		return typeof(System.Single);
+				case MySqlDbType.Double:		return typeof(System.Double);
+
+				case MySqlDbType.Time:		return typeof(System.TimeSpan);
+
+				case MySqlDbType.Date:
+				case MySqlDbType.Datetime:
+				case MySqlDbType.Timestamp:	return typeof(System.DateTime);
+
+				case MySqlDbType.Decimal:	return typeof(System.Decimal);
+
+				case MySqlDbType.VarChar:	
+				case MySqlDbType.String:		return typeof(System.String);
+
+				case MySqlDbType.TinyBlob:
+				case MySqlDbType.MediumBlob:
+				case MySqlDbType.LongBlob:
+				case MySqlDbType.Blob:		return typeof(System.Array);
+
+				default:
+				case MySqlDbType.Null:		return typeof(System.DBNull);
+			}
+		}
+
+		public MySqlDbType GetMySqlDbType()
+		{
+			return colType;
+		}
+
+		public DbType GetDbType() 
+		{
+			switch (colType) 
+			{
+				case MySqlDbType.Decimal:		return DbType.Decimal;
+				case MySqlDbType.Byte:			return DbType.Byte;
+				case MySqlDbType.Short:			
+					if (IsUnsigned())
+						return DbType.UInt16;
+					else
+						return DbType.Int16;
+
+				case MySqlDbType.Long:			
+					if (IsUnsigned())
+						return DbType.UInt32;
+					else
+						return DbType.Int32;
+
+				case MySqlDbType.Float:			return DbType.Single;
+				case MySqlDbType.Double:		return DbType.Double;
+				case MySqlDbType.Null:			return DbType.Object;
+
+				case MySqlDbType.LongLong:		
+					if (IsUnsigned())
+						return DbType.UInt64;
+					else
+						return DbType.Int64;
+
+				case MySqlDbType.Int24:			
+					if (IsUnsigned())
+						return DbType.UInt32;
+					else
+						return DbType.Int32;
+				case MySqlDbType.Date:			
+				case MySqlDbType.Year:
+				case MySqlDbType.Newdate:
+					return DbType.Date;
+
+				case MySqlDbType.Time:			
+					return DbType.Time;
+				case MySqlDbType.Datetime:		
+				case MySqlDbType.Timestamp:
+					return DbType.DateTime;
+
+				case MySqlDbType.Enum:			return DbType.UInt32;
+				case MySqlDbType.Set:			return DbType.Object;
+
+				case MySqlDbType.TinyBlob:		
+				case MySqlDbType.MediumBlob:
+				case MySqlDbType.LongBlob:
+				case MySqlDbType.Blob:
+					if (IsBinary()) return DbType.Binary;
+					return DbType.String;
+				case MySqlDbType.VarChar:
+					return DbType.String;
+				case MySqlDbType.String:
+					return DbType.StringFixedLength;
+			}
+			throw new Exception("unknown MySqlDbType");
+		}
+
+	}
+
+}

+ 229 - 0
mcs/class/ByteFX.Data/mysqlclient/MySqlHelper.cs

@@ -0,0 +1,229 @@
+using System;
+using System.Data;
+using ByteFX.Data.MySqlClient;
+
+namespace ByteFX.Data.MySqlClient
+{
+	/// <summary>
+	/// Summary description for MySqlHelper.
+	/// </summary>
+	public sealed class MySqlHelper
+	{
+		// this class provides only static methods
+		private MySqlHelper()
+		{
+		}
+
+		#region ExecuteNonQuery
+		public static int ExecuteNonQuery( MySqlConnection connection, string commandText, params MySqlParameter[] commandParameters )
+		{
+			//create a command and prepare it for execution
+			MySqlCommand cmd = new MySqlCommand();
+			cmd.Connection = connection;
+			cmd.CommandText = commandText;
+			cmd.CommandType = CommandType.Text;
+
+			if (commandParameters != null)
+				foreach (MySqlParameter p in commandParameters)
+					cmd.Parameters.Add( p );
+
+			int result = cmd.ExecuteNonQuery();
+			cmd.Parameters.Clear();
+
+			return result;
+		}
+
+		public static int ExecuteNonQuery( string connectionString, string commandText, params MySqlParameter[] parms )
+		{
+			//create & open a SqlConnection, and dispose of it after we are done.
+			using (MySqlConnection cn = new MySqlConnection(connectionString))
+			{
+				cn.Open();
+
+				//call the overload that takes a connection in place of the connection string
+				return ExecuteNonQuery(cn, commandText, parms );
+			}
+		}
+		#endregion
+
+		#region ExecuteDataSet
+		public static DataRow ExecuteDatarow( string connectionString, string commandText, params MySqlParameter[] parms )
+		{
+			DataSet ds = ExecuteDataset( connectionString, commandText, parms );
+			if (ds == null) return null;
+			if (ds.Tables.Count == 0) return null;
+			if (ds.Tables[0].Rows.Count == 0) return null;
+			return ds.Tables[0].Rows[0];
+		}
+
+		public static DataSet ExecuteDataset(string connectionString, string commandText)
+		{
+			//pass through the call providing null for the set of SqlParameters
+			return ExecuteDataset(connectionString, commandText, (MySqlParameter[])null);
+		}
+
+		public static DataSet ExecuteDataset(string connectionString, string commandText, params MySqlParameter[] commandParameters)
+		{
+			//create & open a SqlConnection, and dispose of it after we are done.
+			using (MySqlConnection cn = new MySqlConnection(connectionString))
+			{
+				cn.Open();
+
+				//call the overload that takes a connection in place of the connection string
+				return ExecuteDataset(cn, commandText, commandParameters);
+			}
+		}
+
+		public static DataSet ExecuteDataset(MySqlConnection connection, string commandText)
+		{
+			//pass through the call providing null for the set of SqlParameters
+			return ExecuteDataset(connection, commandText, (MySqlParameter[])null);
+		}
+
+
+		public static DataSet ExecuteDataset(MySqlConnection connection, string commandText, params MySqlParameter[] commandParameters)
+		{
+			//create a command and prepare it for execution
+			MySqlCommand cmd = new MySqlCommand();
+			cmd.Connection = connection;
+			cmd.CommandText = commandText;
+			cmd.CommandType = CommandType.Text;
+
+			if (commandParameters != null)
+				foreach (MySqlParameter p in commandParameters)
+					cmd.Parameters.Add( p );
+			
+			//create the DataAdapter & DataSet
+			MySqlDataAdapter da = new MySqlDataAdapter(cmd);
+			DataSet ds = new DataSet();
+
+			//fill the DataSet using default values for DataTable names, etc.
+			da.Fill(ds);
+			
+			// detach the MySqlParameters from the command object, so they can be used again.			
+			cmd.Parameters.Clear();
+			
+			//return the dataset
+			return ds;						
+		}
+
+		public static void UpdateDataSet( string connectionString, string commandText, DataSet ds, string tablename )
+		{
+			MySqlConnection cn = new MySqlConnection( connectionString );
+			cn.Open();
+			MySqlDataAdapter da = new MySqlDataAdapter( commandText, cn );
+			MySqlCommandBuilder cb = new MySqlCommandBuilder( da );
+			da.Update( ds, tablename );
+			cn.Close();
+		}
+
+		#endregion
+
+		#region ExecuteDataReader
+		private static MySqlDataReader ExecuteReader(MySqlConnection connection, MySqlTransaction transaction, string commandText, MySqlParameter[] commandParameters, bool ExternalConn )
+		{	
+			//create a command and prepare it for execution
+			MySqlCommand cmd = new MySqlCommand();
+			cmd.Connection = connection;
+			cmd.Transaction = transaction;
+			cmd.CommandText = commandText;
+			cmd.CommandType = CommandType.Text;
+			
+			if (commandParameters != null)
+				foreach (MySqlParameter p in commandParameters)
+					cmd.Parameters.Add( p );
+
+			//create a reader
+			MySqlDataReader dr;
+
+			// call ExecuteReader with the appropriate CommandBehavior
+			if (ExternalConn)
+			{
+				dr = cmd.ExecuteReader();
+			}
+			else
+			{
+				dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
+			}
+			
+			// detach the SqlParameters from the command object, so they can be used again.
+			cmd.Parameters.Clear();
+			
+			return dr;
+		}
+
+		public static MySqlDataReader ExecuteReader(string connectionString, string commandText)
+		{
+			//pass through the call providing null for the set of SqlParameters
+			return ExecuteReader(connectionString, commandText, (MySqlParameter[])null);
+		}
+
+		public static MySqlDataReader ExecuteReader(string connectionString, string commandText, params MySqlParameter[] commandParameters)
+		{
+			//create & open a SqlConnection
+			MySqlConnection cn = new MySqlConnection(connectionString);
+			cn.Open();
+
+			try
+			{
+				//call the private overload that takes an internally owned connection in place of the connection string
+				return ExecuteReader(cn, null, commandText, commandParameters, false );
+			}
+			catch
+			{
+				//if we fail to return the SqlDatReader, we need to close the connection ourselves
+				cn.Close();
+				throw;
+			}
+		}
+		#endregion
+
+		#region ExecuteScalar
+		public static object ExecuteScalar(string connectionString, string commandText)
+		{
+			//pass through the call providing null for the set of MySqlParameters
+			return ExecuteScalar(connectionString, commandText, (MySqlParameter[])null);
+		}
+
+		public static object ExecuteScalar(string connectionString, string commandText, params MySqlParameter[] commandParameters)
+		{
+			//create & open a SqlConnection, and dispose of it after we are done.
+			using (MySqlConnection cn = new MySqlConnection(connectionString))
+			{
+				cn.Open();
+
+				//call the overload that takes a connection in place of the connection string
+				return ExecuteScalar(cn, commandText, commandParameters);
+			}
+		}
+
+		public static object ExecuteScalar(MySqlConnection connection, string commandText)
+		{
+			//pass through the call providing null for the set of MySqlParameters
+			return ExecuteScalar(connection, commandText, (MySqlParameter[])null);
+		}
+
+		public static object ExecuteScalar(MySqlConnection connection, string commandText, params MySqlParameter[] commandParameters)
+		{
+			//create a command and prepare it for execution
+			MySqlCommand cmd = new MySqlCommand();
+			cmd.Connection = connection;
+			cmd.CommandText = commandText;
+			cmd.CommandType = CommandType.Text;
+			
+			if (commandParameters != null)
+				foreach (MySqlParameter p in commandParameters)
+					cmd.Parameters.Add( p );
+			
+			//execute the command & return the results
+			object retval = cmd.ExecuteScalar();
+			
+			// detach the SqlParameters from the command object, so they can be used again.
+			cmd.Parameters.Clear();
+			return retval;
+			
+		}
+
+		#endregion
+	}
+}

+ 112 - 0
mcs/class/ByteFX.Data/mysqlclient/MySqlPool.cs

@@ -0,0 +1,112 @@
+using System;
+using ByteFX.Data.Common;
+using System.Collections;
+
+namespace ByteFX.Data.MySqlClient
+{
+	/// <summary>
+	/// Summary description for MySqlPool.
+	/// </summary>
+	internal sealed class MySqlPool
+	{
+		private ArrayList			inUsePool;
+		private ArrayList			idlePool;
+		private int					minSize;
+		private int					maxSize;
+
+		public MySqlPool(int minSize, int maxSize)
+		{
+			this.minSize = minSize;
+			this.maxSize = maxSize;
+			inUsePool =new ArrayList(minSize);
+			idlePool = new ArrayList(minSize);
+		}
+
+		private MySqlInternalConnection GetPooledConnection()
+		{
+			lock (idlePool.SyncRoot) 
+			{
+				foreach (MySqlInternalConnection conn in idlePool)
+				{
+					if (conn.IsAlive()) 
+					{
+						lock (inUsePool) 
+						{
+							inUsePool.Add( conn );
+						}
+						idlePool.Remove( conn );
+						return conn;
+					}
+					else 
+					{
+						conn.Close();
+						idlePool.Remove(conn);
+					}
+				}
+			}
+			return null;
+		}
+
+		private MySqlInternalConnection CreateNewPooledConnection( MySqlConnectionString settings )
+		{
+			MySqlInternalConnection conn = new MySqlInternalConnection( settings );
+			conn.Open();
+			return conn;
+		}
+
+		public void ReleaseConnection( MySqlInternalConnection connection )
+		{
+			lock (inUsePool.SyncRoot)
+				lock (idlePool.SyncRoot) 
+				{
+					inUsePool.Remove( connection );
+					if (connection.Settings.ConnectionLifetime != 0 && connection.IsTooOld())
+						connection.Close();
+					else
+						idlePool.Add( connection );
+				}
+		}
+
+		public MySqlInternalConnection GetConnection(MySqlConnectionString settings) 
+		{
+			MySqlInternalConnection conn;
+
+			DateTime start = DateTime.Now;
+			TimeSpan ts;
+			do 
+			{
+				conn = GetPooledConnection();
+				if (conn == null)
+					conn = CreateNewPooledConnection( settings );
+				ts = DateTime.Now.Subtract( start );
+			} while (conn == null && ts.Seconds < settings.ConnectTimeout );
+
+					 
+			// if pool size is at maximum, then we must have reached our timeout so we simply
+			// throw our exception
+			if (conn == null)
+				throw new MySqlException("error connecting: Timeout expired.  The timeout period elapsed " + 
+					"prior to obtaining a connection from the pool.  This may have occurred because all " +
+					"pooled connections were in use and max pool size was reached.");
+
+			return conn;
+			//System.Diagnostics.Debug.WriteLine("Creating a new driver");
+/*			Driver driver = new Driver();
+			try 
+			{
+				driver.Connection = conn;
+				driver.Open( conn.DataSource, conn.Port, conn.User, conn.Password, conn.UseCompression );
+
+				driver.SendCommand( DBCmd.INIT_DB, connString["database"] );
+			}
+			catch (Exception ex)
+			{
+				throw new MySqlException("Database initialization failed with message: " + ex.Message);
+			}
+
+			pool.Add( driver );
+			return driver;*/
+		}
+
+	}
+}

+ 63 - 0
mcs/class/ByteFX.Data/mysqlclient/MySqlPoolManager.cs

@@ -0,0 +1,63 @@
+using System;
+using ByteFX.Data.Common;
+using System.Collections;
+
+namespace ByteFX.Data.MySqlClient
+{
+	/// <summary>
+	/// Summary description for MySqlPoolManager.
+	/// </summary>
+	internal sealed class MySqlPoolManager
+	{
+		private static Hashtable	pools;
+
+		public MySqlPoolManager() 
+		{
+		}
+
+		/// <summary>
+		/// 
+		/// </summary>
+		private static void Initialize()
+		{
+			pools = new Hashtable();
+		}
+
+		public static MySqlInternalConnection GetConnection( MySqlConnectionString settings ) 
+		{
+			// make sure the manager is initialized
+			if (MySqlPoolManager.pools == null)
+				MySqlPoolManager.Initialize();
+
+			string text = settings.ConnectString;
+
+			lock( pools.SyncRoot ) 
+			{
+				MySqlPool pool;
+				if (!pools.Contains( text )) 
+				{
+					pool = new MySqlPool( settings.MinPoolSize, settings.MaxPoolSize );
+					pools.Add( text, pool );
+				}
+				else 
+				{
+					pool = (pools[text] as MySqlPool);
+				}
+
+				return pool.GetConnection( settings );
+			}
+		}
+
+		public static void ReleaseConnection( MySqlInternalConnection connection )
+		{
+			lock (pools.SyncRoot) 
+			{
+				string key = connection.Settings.ConnectString;
+				MySqlPool pool = (MySqlPool)pools[ key ];
+				if (pool == null)
+					throw new MySqlException("Pooling exception: Unable to find original pool for connection");
+				pool.ReleaseConnection(connection);
+			}
+		}
+	}
+}

+ 187 - 0
mcs/class/ByteFX.Data/mysqlclient/MySqlStream.cs

@@ -0,0 +1,187 @@
+// ByteFX.Data data access components for .Net
+// Copyright (C) 2002-2003  ByteFX, Inc.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+using System;
+using System.IO;
+using System.Net;
+using System.Net.Sockets;
+using ByteFX.Data.Common;
+
+namespace ByteFX.Data.MySqlClient
+{
+	/// <summary>
+	/// Summary description for API.
+	/// </summary>
+	public class MySqlStream : Stream
+	{
+		Stream	stream;
+		Socket	socket;
+		int		timeOut;
+
+		public MySqlStream( string host, int port, int timeout )
+		{
+			if (port == -1)
+				Create( host );
+			else
+				Create( host, port );
+			timeOut = timeout;
+		}
+
+		public bool IsClosed
+		{
+			get 
+			{
+				if (stream is NetworkStream) 
+				{
+					bool poll = socket.Poll(-1, SelectMode.SelectWrite );
+					poll = socket.Poll(-1, SelectMode.SelectRead );
+					poll = socket.Poll(-1, SelectMode.SelectError );
+					return ! poll;
+				}
+				return false;
+			}
+		}
+
+		private void Create( string host, int port )
+		{
+			socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+			IPHostEntry he = Dns.GetHostByName( host );
+			IPEndPoint serverAddr = new IPEndPoint(he.AddressList[0], port);
+
+			socket.Connect(serverAddr);
+			stream = new NetworkStream(socket);
+		}
+
+		private void Create( string host )
+		{
+			string pipeName;
+
+			if (host.ToLower().Equals("localhost"))
+				pipeName = @"\\.\pipe\MySql";
+			else
+				pipeName = String.Format(@"\\{0}\pipe\MySql", host);
+
+			stream = new ByteFX.Data.Common.NamedPipeStream(pipeName, FileAccess.ReadWrite);
+		}
+
+		public bool DataAvailable
+		{
+			get 
+			{
+				if (stream is NetworkStream)
+					return ((NetworkStream)stream).DataAvailable;
+				else return (stream as NamedPipeStream).DataAvailable;
+			}
+	}
+
+		public override bool CanRead
+		{
+			get { return stream.CanRead; }
+		}
+
+		public override bool CanWrite
+		{
+			get { return stream.CanWrite; }
+		}
+
+		public override bool CanSeek
+		{
+			get { return stream.CanSeek; }
+		}
+
+		public override long Length
+		{
+			get { return stream.Length; }
+		}
+
+		public override long Position 
+		{
+			get { return stream.Position; }
+			set { stream.Position = value; }
+		}
+
+		public override void Flush() 
+		{
+			stream.Flush();
+		}
+
+		public override int ReadByte()
+		{
+			long start = Environment.TickCount;
+			long timeout_ticks = timeOut * TimeSpan.TicksPerSecond;
+
+			while (((Environment.TickCount - start) < timeout_ticks))
+			{
+				if (DataAvailable)
+				{
+					int b = stream.ReadByte();
+					return b;
+				}
+			}
+			throw new Exception("Timeout waiting for response from server");
+		}
+
+		public override int Read(byte[] buffer, int offset, int count)
+		{
+			long start = Environment.TickCount;
+			int  numToRead = count;
+			long timeout_ticks = timeOut * TimeSpan.TicksPerSecond;
+
+			while (numToRead > 0 && ((Environment.TickCount - start) < timeout_ticks))
+			{
+				if (DataAvailable)
+				{
+					int bytes_read = stream.Read(buffer, offset, numToRead);
+					offset += bytes_read;
+					numToRead -= bytes_read;
+				}
+			}
+			if (numToRead > 0)
+				throw new Exception("Timeout waiting for response from server");
+			return count;
+		}
+
+		public int ReadInt24()
+		{
+			byte[] bytes = new byte[3];
+			Read( bytes, 0, 3 );
+			return (bytes[0] + (bytes[1]*256) + (bytes[2]*256*256));
+		}
+
+		public override void Close()
+		{
+			stream.Close();
+		}
+
+		public override void SetLength(long length)
+		{
+			stream.SetLength( length );
+		}
+
+		public override void Write(byte[] buffer, int offset, int count)
+		{
+			stream.Write( buffer, offset, count );
+		}
+
+		public override long Seek( long offset, SeekOrigin origin )
+		{
+			return stream.Seek( offset, origin );
+		}
+	}
+}
+
+

+ 126 - 121
mcs/class/ByteFX.Data/mysqlclient/MysqlDefs.cs

@@ -1,121 +1,126 @@
-// ByteFX.Data data access components for .Net
-// Copyright (C) 2002-2003  ByteFX, Inc.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-namespace ByteFX.Data.MySQLClient
-{
-	/// <summary>
-	/// Summary description for ClientParam.
-	/// </summary>
-	internal enum ClientParam : short
-	{
-		CLIENT_LONG_PASSWORD	= 1,			// new more secure passwords
-		CLIENT_FOUND_ROWS		= 2,			// found instead of affected rows
-		CLIENT_LONG_FLAG		= 4,			// Get all column flags
-		CLIENT_CONNECT_WITH_DB	= 8,			// One can specify db on connect
-		CLIENT_NO_SCHEMA		= 16,			// Don't allow db.table.column
-		CLIENT_COMPRESS			= 32,			// Client can use compression protocol
-		CLIENT_ODBC				= 64,			// ODBC client
-		CLIENT_LOCAL_FILES		= 128,			// Can use LOAD DATA LOCAL
-		CLIENT_IGNORE_SPACE		= 256,			// Ignore spaces before '('
-		CLIENT_CHANGE_USER		= 512,			// Support the mysql_change_user()
-		CLIENT_INTERACTIVE		= 1024,			// This is an interactive client
-		CLIENT_SSL				= 2048,			// Switch to SSL after handshake
-		CLIENT_IGNORE_SIGPIPE	= 4096,			// IGNORE sigpipes
-		CLIENT_TRANSACTIONS		= 8192,			// Client knows about transactions
-	}
-	
-	/// <summary>
-	/// DB Operations Code
-	/// </summary>
-	internal enum DBCmd : byte
-	{
-		SLEEP        =  0,
-		QUIT         =  1,
-		INIT_DB      =  2,
-		QUERY        =  3,
-		FIELD_LIST   =  4,
-		CREATE_DB    =  5,
-		DROP_DB      =  6,
-		RELOAD       =  7,
-		SHUTDOWN     =  8,
-		STATISTICS   =  9,
-		PROCESS_INFO = 10,
-		CONNECT      = 11,
-		PROCESS_KILL = 12,
-		DEBUG        = 13,
-		PING         = 14,
-		TIME         = 15,
-		DELAYED_INSERT = 16,
-		CHANGE_USER    = 17,
-	}
-
-	public enum MySQLDbType
-	{
-		Decimal		=   0,
-		Tiny        =   1,
-		Byte		=   1,
-		Short       =   2,
-		Long        =   3,
-		Float       =   4,
-		Double      =   5,
-		Null        =   6,
-		Timestamp   =   7,
-		LongLong    =   8,
-		Int24       =   9,
-		Date        =  10,
-		Time        =  11,
-		Datetime    =  12,
-		Year        =  13,
-		Newdate     =  14,
-		Enum        = 247,
-		Set         = 248,
-		TinyBlob    = 249,
-		MediumBlob  = 250,
-		LongBlob    = 251,
-		Blob        = 252,
-		VarChar     = 253,
-		String      = 254
-	};
-
-
-	enum Field_Type : byte
-	{
-		DECIMAL					=0,
-		BYTE						=1,
-		SHORT					=2,
-		LONG						=3,
-		FLOAT					=4,
-		DOUBLE					=5,
-		NULL						=6,
-		TIMESTAMP				=7,
-		LONGLONG				=8,
-		INT24						=9,
-		DATE						=10,
-		TIME						=11,
-		DATETIME				=12,
-		YEAR						=13,
-		NEWDATE				=14,
-		ENUM						=247,
-		SET						=248,
-		TINY_BLOB				=249,
-		MEDIUM_BLOB			=250,
-		LONG_BLOB				=251,
-		BLOB						=252,
-		VAR_STRING			=253,
-		STRING					=254,
-	}
-}
+// ByteFX.Data data access components for .Net
+// Copyright (C) 2002-2003  ByteFX, Inc.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+using System;
+
+namespace ByteFX.Data.MySqlClient
+{
+	/// <summary>
+	/// Summary description for ClientParam.
+	/// </summary>
+	[Flags()]
+	internal enum ClientParam
+	{
+		CLIENT_LONG_PASSWORD	= 1,			// new more secure passwords
+		CLIENT_FOUND_ROWS		= 2,			// found instead of affected rows
+		CLIENT_LONG_FLAG		= 4,			// Get all column flags
+		CLIENT_CONNECT_WITH_DB	= 8,			// One can specify db on connect
+		CLIENT_NO_SCHEMA		= 16,			// Don't allow db.table.column
+		CLIENT_COMPRESS			= 32,			// Client can use compression protocol
+		CLIENT_ODBC				= 64,			// ODBC client
+		CLIENT_LOCAL_FILES		= 128,			// Can use LOAD DATA LOCAL
+		CLIENT_IGNORE_SPACE		= 256,			// Ignore spaces before '('
+		CLIENT_CHANGE_USER		= 512,			// Support the mysql_change_user()
+		CLIENT_INTERACTIVE		= 1024,			// This is an interactive client
+		CLIENT_SSL				= 2048,			// Switch to SSL after handshake
+		CLIENT_IGNORE_SIGPIPE	= 4096,			// IGNORE sigpipes
+		CLIENT_TRANSACTIONS		= 8192,			// Client knows about transactions
+		CLIENT_PROTOCOL_41		= 16384,
+		CLIENT_SECURE_CONNECTION = 32768
+
+	}
+	
+
+	/// <summary>
+	/// DB Operations Code
+	/// </summary>
+	internal enum DBCmd : byte
+	{
+		SLEEP        =  0,
+		QUIT         =  1,
+		INIT_DB      =  2,
+		QUERY        =  3,
+		FIELD_LIST   =  4,
+		CREATE_DB    =  5,
+		DROP_DB      =  6,
+		RELOAD       =  7,
+		SHUTDOWN     =  8,
+		STATISTICS   =  9,
+		PROCESS_INFO = 10,
+		CONNECT      = 11,
+		PROCESS_KILL = 12,
+		DEBUG        = 13,
+		PING         = 14,
+		TIME         = 15,
+		DELAYED_INSERT = 16,
+		CHANGE_USER    = 17,
+	}
+
+	public enum MySqlDbType
+	{
+		Decimal		=   0,
+		Byte		=   1,
+		Short       =   2,
+		Long        =   3,
+		Float       =   4,
+		Double      =   5,
+		Null        =   6,
+		Timestamp   =   7,
+		LongLong    =   8,
+		Int24       =   9,
+		Date        =  10,
+		Time        =  11,
+		Datetime    =  12,
+		Year        =  13,
+		Newdate     =  14,
+		Enum        = 247,
+		Set         = 248,
+		TinyBlob    = 249,
+		MediumBlob  = 250,
+		LongBlob    = 251,
+		Blob        = 252,
+		VarChar     = 253,
+		String      = 254
+	};
+
+
+	enum Field_Type : byte
+	{
+		DECIMAL					=0,
+		BYTE					=1,
+		SHORT					=2,
+		LONG					=3,
+		FLOAT					=4,
+		DOUBLE					=5,
+		NULL					=6,
+		TIMESTAMP				=7,
+		LONGLONG				=8,
+		INT24					=9,
+		DATE					=10,
+		TIME					=11,
+		DATETIME				=12,
+		YEAR					=13,
+		NEWDATE					=14,
+		ENUM					=247,
+		SET						=248,
+		TINY_BLOB				=249,
+		MEDIUM_BLOB				=250,
+		LONG_BLOB				=251,
+		BLOB					=252,
+		VAR_STRING				=253,
+		STRING					=254,
+	}
+}

+ 228 - 0
mcs/class/ByteFX.Data/mysqlclient/Packet.cs

@@ -0,0 +1,228 @@
+using System;
+using System.IO;
+using System.Text;
+
+namespace ByteFX.Data.MySqlClient
+{
+	internal enum PacketType 
+	{
+		None,
+		UpdateOrOk,
+		ResultSchema,
+		Last,
+		Auth,
+		Error,
+		LoadDataLocal,
+		Other
+	}
+
+	/// <summary>
+	/// Summary description for Packet.
+	/// </summary>
+	internal class Packet
+	{
+		MemoryStream	data;
+		PacketType		type = PacketType.None;
+		Encoding		encoding;
+
+		public Packet()
+		{
+			data = new MemoryStream();
+		}
+
+		public Packet(int len)
+		{
+			data = new MemoryStream(len);
+		}
+
+		public Packet(byte[] bytes)
+		{
+			data = new MemoryStream( bytes.Length );
+			data.Write( bytes, 0, bytes.Length );
+			data.Position = 0;
+		}
+
+		public Encoding Encoding 
+		{
+			set { encoding = value; }
+			get { return encoding; }
+		}
+
+		public int Length 
+		{
+			get { return (int)data.Length; }
+		}
+
+		public PacketType Type
+		{
+			get { if (type == PacketType.None) ParseType(); return type; }
+			set { type = value; }
+		}
+
+		public long Position
+		{
+			get { return data.Position; }
+			set { data.Position = value; }
+		}
+
+		public void AppendPacket( Packet newPacket )
+		{
+			data.Position = data.Length;
+			byte[] bytes = newPacket.GetBytes();
+			data.Write( bytes, 0, bytes.Length );
+		}
+
+		private PacketType ParseType()
+		{
+			byte b = ReadByte();
+
+			// a 1 byte packet with byte 0xfe means last packet
+			if ( data.Length == 1 && b == 0xfe)
+				type = PacketType.Last;
+			
+			// a first byte of 0xff means the packet is an error message
+			else if ( b == 0xff )
+				type = PacketType.Error;
+
+			// the first byte == 0 means an update packet or column count
+			else if ( b == 0 ) 
+				type = PacketType.UpdateOrOk;
+			else
+				type = PacketType.Other;
+			return type;
+		}
+
+		public byte[] GetBytes()
+		{
+			return data.ToArray();
+		}
+
+		public void WriteByte( byte b )
+		{
+			data.WriteByte( b );
+		}
+
+		public byte ReadByte()
+		{
+			return (byte)data.ReadByte();
+		}
+
+		public void ReadBytes( byte[] buffer, int offset, int len )
+		{
+			data.Read( buffer, offset, len );
+		}
+
+		public void WriteBytes( byte[] bytes, int offset, int len )
+		{
+			data.Write( bytes, offset, len );
+		}
+
+		public uint ReadNBytes()
+		{
+			byte c = (byte)ReadByte();
+			if (c < 1 || c > 4) throw new MySqlException("Unexpected byte count received");
+			return ReadInteger((int)c);
+		}
+
+		public string ReadLenString()
+		{
+			uint len = ReadLenInteger();
+
+			byte[] buffer = new Byte[len];
+			ReadBytes(buffer, 0, (int)len);
+			return encoding.GetString( buffer, 0, (int)len);
+		}
+
+
+		/// <summary>
+		/// WriteInteger
+		/// </summary>
+		/// <param name="v"></param>
+		/// <param name="numbytes"></param>
+		public void WriteInteger( int v, int numbytes )
+		{
+			int val = v;
+
+			if (numbytes < 1 || numbytes > 4) 
+				throw new ArgumentOutOfRangeException("Wrong byte count for WriteInteger");
+
+			for (int x=0; x < numbytes; x++)
+			{
+				data.WriteByte( (byte)(val&0xff) );
+				val >>= 8;
+			}
+		}
+
+		/// <summary>
+		/// 
+		/// </summary>
+		/// <param name="numbytes"></param>
+		/// <returns></returns>
+		public uint ReadInteger(int numbytes)
+		{
+			uint val = 0;
+			uint raise = 1;
+			for (int x=0; x < numbytes; x++)
+			{
+				uint b = (uint)data.ReadByte();
+				val += (b*raise);
+				raise *= 256;
+			}
+			return val;
+		}
+
+		/// <summary>
+		/// 
+		/// </summary>
+		/// <returns></returns>
+		public uint ReadLenInteger()
+		{
+			byte c  = (byte)ReadByte();
+
+			switch(c) 
+			{
+				case 251 : return 0; 
+				case 252 : return ReadInteger(2);
+				case 253 : return ReadInteger(3);
+				case 254 : return ReadInteger(4);
+				default  : return c;
+			}
+		}
+
+		public bool CanRead
+		{
+			get { return data.Position < data.Length; }
+		}
+
+		#region String Functions
+		public string ReadString()
+		{
+			System.Text.StringBuilder sb = new System.Text.StringBuilder();
+
+			while ( CanRead )
+			{
+				byte b = ReadByte();
+				if (b == 0) break;
+				sb.Append( Convert.ToChar( b ));
+			}
+
+			return sb.ToString();
+		}
+
+		public void WriteString(string v, Encoding encoding)
+		{
+			WriteStringNoNull(v, encoding);
+			data.WriteByte(0);
+		}
+
+		public void WriteStringNoNull(string v, Encoding encoding)
+		{
+			byte[] bytes = encoding.GetBytes(v);
+			data.Write(bytes, 0, bytes.Length);
+		}
+
+		#endregion
+
+
+	}
+}

+ 468 - 478
mcs/class/ByteFX.Data/mysqlclient/command.cs

@@ -1,478 +1,468 @@
-// ByteFX.Data data access components for .Net
-// Copyright (C) 2002-2003  ByteFX, Inc.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-using System;
-using System.Data;
-using System.ComponentModel;
-using System.Collections;
-
-namespace ByteFX.Data.MySQLClient
-{
-#if WINDOWS
-	[System.Drawing.ToolboxBitmap( typeof(MySQLCommand), "Designers.command.bmp")]
-#endif
-	public sealed class MySQLCommand : Component, IDbCommand, ICloneable
-	{
-		MySQLConnection				m_connection;
-		MySQLTransaction			m_txn;
-		string						m_sCmdText;
-		int							m_UpdateCount;
-		UpdateRowSource				m_updatedRowSource = UpdateRowSource.Both;
-		MySQLParameterCollection	m_parameters = new MySQLParameterCollection();
-
-		// Implement the default constructor here.
-		public MySQLCommand()
-		{
-		}
-
-		// Implement other constructors here.
-		public MySQLCommand(string cmdText)
-		{
-			m_sCmdText = cmdText;
-		}
-
-		public MySQLCommand(System.ComponentModel.IContainer container)
-		{
-			/// <summary>
-			/// Required for Windows.Forms Class Composition Designer support
-			/// </summary>
-			container.Add(this);
-		}
-
-		public MySQLCommand(string cmdText, MySQLConnection connection)
-		{
-			m_sCmdText    = cmdText;
-			m_connection  = connection;
-		}
-
-		public new void Dispose() 
-		{
-			base.Dispose();
-		}
-
-		public MySQLCommand(string cmdText, MySQLConnection connection, MySQLTransaction txn)
-		{
-			m_sCmdText		= cmdText;
-			m_connection	= connection;
-			m_txn			= txn;
-		} 
-
-		/****
-		* IMPLEMENT THE REQUIRED PROPERTIES.
-		****/
-		public string CommandText
-		{
-			get { return m_sCmdText;  }
-			set  { m_sCmdText = value;  }
-		}
-
-		public int CommandTimeout
-		{
-			/*
-			* The sample does not support a command time-out. As a result,
-			* for the get, zero is returned because zero indicates an indefinite
-			* time-out period. For the set, throw an exception.
-			*/
-			get  { return 0; }
-			set  { if (value != 0) throw new NotSupportedException(); }
-		}
-
-		public CommandType CommandType
-		{
-			/*
-			* The sample only supports CommandType.Text.
-			*/
-			get { return CommandType.Text; }
-			set { if (value != CommandType.Text) throw new NotSupportedException(); }
-		}
-
-		public IDbConnection Connection
-		{
-			/*
-			* The user should be able to set or change the connection at 
-			* any time.
-			*/
-			get 
-			{ 
-				return m_connection;  
-			}
-			set
-			{
-				/*
-				* The connection is associated with the transaction
-				* so set the transaction object to return a null reference if the connection 
-				* is reset.
-				*/
-				if (m_connection != value)
-				this.Transaction = null;
-
-				m_connection = (MySQLConnection)value;
-			}
-		}
-
-		public MySQLParameterCollection Parameters
-		{
-			get  { return m_parameters; }
-		}
-
-		IDataParameterCollection IDbCommand.Parameters
-		{
-			get  { return m_parameters; }
-		}
-
-		public IDbTransaction Transaction
-		{
-			/*
-			* Set the transaction. Consider additional steps to ensure that the transaction
-			* is compatible with the connection, because the two are usually linked.
-			*/
-			get 
-			{ 
-				return m_txn; 
-			}
-			set 
-			{ 
-				m_txn = (MySQLTransaction)value; 
-			}
-		}
-
-		public UpdateRowSource UpdatedRowSource
-		{
-			get 
-			{ 
-				return m_updatedRowSource;  
-			}
-			set 
-			{ 
-				m_updatedRowSource = value; 
-			}
-		}
-
-		/****
-			* IMPLEMENT THE REQUIRED METHODS.
-			****/
-		public void Cancel()
-		{
-			// The sample does not support canceling a command
-			// once it has been initiated.
-			throw new NotSupportedException();
-		}
-
-		public IDbDataParameter CreateParameter()
-		{
-			return new MySQLParameter();
-		}
-
-		/// <summary>
-		/// Convert the SQL command into a series of ASCII bytes streaming
-		/// each of the parameters into the proper place
-		/// </summary>
-		/// <param name="sql">Source SQL command with parameter markers</param>
-		/// <returns>Byte array with all parameters included</returns>
-		private ArrayList ConvertSQLToBytes(string sql)
-		{
-			ArrayList	byteArrays = new ArrayList();
-			System.IO.MemoryStream ms = new System.IO.MemoryStream();
-			
-			if (sql[ sql.Length-1 ] != ';')
-				sql += ';';
-			byte[] bytes = System.Text.Encoding.ASCII.GetBytes(sql);
-
-			byte left_byte = 0;
-			int  parm_start=-1, parm_end = -1;
-			for (int x=0; x < bytes.Length; x++)
-			{
-				byte b = bytes[x];
-				// if we see a quote marker, then check to see if we are opening
-				// or closing a quote
-				if (b == '\'' || b == '\"')
-				{
-					if (b == left_byte)
-					{
-						left_byte = 0;
-					}
-					else
-					{
-						if (left_byte == 0)
-							left_byte = b;
-					}
-					ms.WriteByte(b);
-				}
-
-					// if we find a ; not part of a quoted string, then take the parsed portion
-					// as a sql command and add it to the array
-				else if (b == ';' && left_byte == 0)
-				{
-					byte[] sqlBytes = ms.ToArray();
-					byteArrays.Add( sqlBytes );
-					ms = new System.IO.MemoryStream();
-				}
-
-					// if we see the marker for a parameter, then save its position and
-					// look for the end
-				else if (b == '@' && left_byte == 0) 
-				{
-					parm_start = x;
-					left_byte = b;
-				}
-
-					// if we see a space and we are tracking a parameter, then end the parameter and have
-					// that parameter serialize itself to the memory streams
-				else if ((b == ' ' || b == ',' || b == ';' || b == ')') && left_byte == '@')
-				{
-					parm_end = x-1;
-					string parm_name = sql.Substring(parm_start, parm_end-parm_start+1);
-					MySQLParameter p = (m_parameters[parm_name] as MySQLParameter);
-					p.SerializeToBytes(ms);
-					ms.WriteByte(b);
-
-					if (b == ';') 
-					{
-						byte[] sqlBytes = ms.ToArray();
-						byteArrays.Add( sqlBytes );
-						ms = new System.IO.MemoryStream();
-					}
-
-					left_byte = 0;
-				}
-
-					// we want to write out the bytes in all cases except when we are parsing out a parameter
-				else if (left_byte != '@')
-					ms.WriteByte( b );
-			}
-
-			// if we have any left, then add it at the end
-			if (ms.Length > 0) 
-			{
-				byte[] newbytes = ms.ToArray();
-				byteArrays.Add( newbytes );
-			}
-
-/*			string s = new string('c', 0);
-			byte[] bites = (byte[])byteArrays[0];
-			for (int zt=0; zt < bites.Length; zt++)
-				s += Convert.ToChar(bites[zt]);
-			System.Windows.Forms.MessageBox.Show(s);
-*/
-			return byteArrays;
-		}
-
-		/// <summary>
-		/// Executes a single non-select SQL statement.  Examples of this are update,
-		/// insert, etc.
-		/// </summary>
-		/// <returns>Number of rows affected</returns>
-		public int ExecuteNonQuery()
-		{
-			/*
-			* ExecuteNonQuery is intended for commands that do
-			* not return results, instead returning only the number
-			* of records affected.
-			*/
-
-			// There must be a valid and open connection.
-			if (m_connection == null || m_connection.State != ConnectionState.Open)
-			throw new InvalidOperationException("Connection must valid and open");
-
-			ArrayList list = ConvertSQLToBytes( m_sCmdText );
-			m_UpdateCount = 0;
-
-			// Execute the command.
-			Driver d = m_connection.Driver;
-			try 
-			{
-				for (int x=0; x < list.Count; x++)
-				{
-					d.SendQuery( (byte[])list[x] );	
-					if (d.LastResult == 0)
-						m_UpdateCount += d.ReadLength();
-				}
-			}
-			catch (Exception ex)
-			{
-				throw ex;
-			}
-
-			return m_UpdateCount;
-		}
-
-		IDataReader IDbCommand.ExecuteReader ()
-		{
-			return ExecuteReader ();
-		}
-
-		IDataReader IDbCommand.ExecuteReader (CommandBehavior behavior)
-		{
-			return ExecuteReader (behavior);
-		}
-
-		public MySQLDataReader ExecuteReader()
-		{
-			return ExecuteReader(CommandBehavior.Default);
-		}
-
-		public MySQLDataReader ExecuteReader(CommandBehavior behavior)
-		{
-			/*
-			* ExecuteReader should retrieve results from the data source
-			* and return a DataReader that allows the user to process 
-			* the results.
-			*/
-
-			// There must be a valid and open connection.
-			if (m_connection == null || m_connection.State != ConnectionState.Open)
-				throw new InvalidOperationException("Connection must valid and open");
-
-			if (0 != (behavior & CommandBehavior.CloseConnection))
-			{
-			}
-
-			if (0 != (behavior & CommandBehavior.Default))
-			{
-			}
-
-			if (0 != (behavior & CommandBehavior.KeyInfo))
-			{
-			}
-
-			if (0 != (behavior & CommandBehavior.SchemaOnly))
-			{
-			}
-
-			if (0 != (behavior & CommandBehavior.SequentialAccess))
-			{
-			}
-
-			if (0 != (behavior & CommandBehavior.SingleResult))
-			{
-			}
-
-			if (0 != (behavior & CommandBehavior.SingleRow))
-			{
-			}
-
-
-			/*
-			* ExecuteReader should retrieve results from the data source
-			* and return a DataReader that allows the user to process 
-			* the results.
-			*/
-			ArrayList cmds = ConvertSQLToBytes( m_sCmdText );
-			m_UpdateCount = 0;
-
-			MySQLDataReader reader = new MySQLDataReader(m_connection, behavior == CommandBehavior.SequentialAccess);
-
-			// Execute the command.
-			Driver d = m_connection.Driver;
-			try 
-			{
-				for (int x=0; x < cmds.Count; x++)
-				{
-/*					string st = new string('c',0);
-					for (int z=0; z < ((byte[])cmds[x]).Length; z++)
-					{
-						st += Convert.ToChar( ((byte[])cmds[x])[z] );
-					}
-					System.Windows.Forms.MessageBox.Show(st); */
-
-/*					System.IO.FileStream fs = new System.IO.FileStream("c:\\cmd.sql",  System.IO.FileMode.OpenOrCreate);
-					byte[] bites = (byte[])(cmds[0]);
-					fs.Write(bites, 0, bites.Length);
-					fs.Close();
-*/
-					d.SendQuery( (byte[])cmds[x] );
-					if (d.LastResult == 0)
-						m_UpdateCount += d.ReadLength();
-					else
-						reader.LoadResults();
-				}
-			}
-			catch (Exception ex) 
-			{
-				throw ex;
-			}
-
-			return reader;
-
-			//TODO implement rest of command behaviors on ExecuteReader
-			/*
-			* The only CommandBehavior option supported by this
-			* sample is the automatic closing of the connection
-			* when the user is done with the reader.
-			*/
-		//      if (behavior == CommandBehavior.CloseConnection)
-		//        return new TemplateDataReader(resultset, m_connection);
-		//      else
-		//        return new TemplateDataReader(resultset);
-		}
-
-		/// <summary>
-		/// ExecuteScalar executes a single SQL command that will return
-		/// a single row with a single column, or if more rows/columns are
-		/// returned it will return the first column of the first row.
-		/// </summary>
-		/// <returns></returns>
-		public object ExecuteScalar()
-		{
-			// There must be a valid and open connection.
-			if (m_connection == null || m_connection.State != ConnectionState.Open)
-				throw new InvalidOperationException("Connection must valid and open");
-
-			MySQLDataReader reader = new MySQLDataReader(m_connection, false);
-			ArrayList cmds = ConvertSQLToBytes( m_sCmdText );
-			m_UpdateCount = 0;
-
-			// Execute the command.
-			Driver d = m_connection.Driver;
-
-			try 
-			{
-				for (int x=0; x < cmds.Count; x++)
-				{
-					d.SendQuery( (byte[])cmds[x] );
-					if (d.LastResult == 0)
-						m_UpdateCount += d.ReadLength();
-					else
-						reader.LoadResults();
-				}
-			}
-			catch (Exception ex)
-			{
-				throw ex;
-			}
-
-			if (! reader.Read()) return null;
-			return reader.GetValue(0);
-		}
-
-		public void Prepare()
-		{
-		}
-
-		#region ICloneable
-		public object Clone() 
-		{
-			MySQLCommand clone = new MySQLCommand(m_sCmdText, m_connection, m_txn);
-			foreach (MySQLParameter p in m_parameters) 
-			{
-				clone.Parameters.Add(p.Clone());
-			}
-			return clone;
-		}
-		#endregion
-  }
-}
+// ByteFX.Data data access components for .Net
+// Copyright (C) 2002-2003  ByteFX, Inc.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+using System;
+using System.Data;
+using System.ComponentModel;
+using System.Collections;
+
+namespace ByteFX.Data.MySqlClient
+{
+#if WINDOWS
+	[System.Drawing.ToolboxBitmap( typeof(MySqlCommand), "Designers.command.bmp")]
+#endif
+
+	[System.ComponentModel.DesignerCategory("Code")]
+	public sealed class MySqlCommand : Component, IDbCommand, ICloneable
+	{
+		MySqlConnection				connection;
+		MySqlTransaction			curTransaction;
+		string						cmdText;
+		int							updateCount;
+		UpdateRowSource				updatedRowSource = UpdateRowSource.Both;
+		MySqlParameterCollection	parameters = new MySqlParameterCollection();
+		private ArrayList			arraySql = new ArrayList();
+
+		// Implement the default constructor here.
+		public MySqlCommand()
+		{
+		}
+
+		// Implement other constructors here.
+		public MySqlCommand(string cmdText)
+		{
+			this.cmdText = cmdText;
+		}
+
+		public MySqlCommand(System.ComponentModel.IContainer container)
+		{
+			/// <summary>
+			/// Required for Windows.Forms Class Composition Designer support
+			/// </summary>
+			container.Add(this);
+		}
+
+		public MySqlCommand(string cmdText, MySqlConnection connection)
+		{
+			this.cmdText    = cmdText;
+			this.connection  = connection;
+		}
+
+		public new void Dispose() 
+		{
+			base.Dispose();
+		}
+
+		public MySqlCommand(string cmdText, MySqlConnection connection, MySqlTransaction txn)
+		{
+			this.cmdText	= cmdText;
+			this.connection	= connection;
+			curTransaction	= txn;
+		} 
+
+		#region Properties
+		[Category("Data")]
+		[Description("Command text to execute")]
+#if WINDOWS
+		[Editor(typeof(ByteFX.Data.Common.SqlCommandTextEditor), typeof(System.Drawing.Design.UITypeEditor))]
+#endif
+		public string CommandText
+		{
+			get { return cmdText;  }
+			set  { cmdText = value;  }
+		}
+
+		public int UpdateCount 
+		{
+			get { return updateCount; }
+		}
+
+		[Category("Misc")]
+		[Description("Time to wait for command to execute")]
+		public int CommandTimeout
+		{
+			/*
+			* The sample does not support a command time-out. As a result,
+			* for the get, zero is returned because zero indicates an indefinite
+			* time-out period. For the set, throw an exception.
+			*/
+			get  { return 0; }
+			set  { if (value != 0) throw new NotSupportedException(); }
+		}
+
+		[Category("Data")]
+		public CommandType CommandType
+		{
+			/*
+			* The sample only supports CommandType.Text.
+			*/
+			get { return CommandType.Text; }
+			set 
+			{ 
+				if (value != CommandType.Text) 
+					throw new NotSupportedException("This version of the MySql provider only supports Text command types"); 
+			}
+		}
+
+		[Category("Behavior")]
+		[Description("Connection used by the command")]
+		public IDbConnection Connection
+		{
+			/*
+			* The user should be able to set or change the connection at 
+			* any time.
+			*/
+			get 
+			{ 
+				return connection;  
+			}
+			set
+			{
+				/*
+				* The connection is associated with the transaction
+				* so set the transaction object to return a null reference if the connection 
+				* is reset.
+				*/
+				if (connection != value)
+				this.Transaction = null;
+
+				connection = (MySqlConnection)value;
+			}
+		}
+
+		[Category("Data")]
+		[Description("The parameters collection")]
+		[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
+		public MySqlParameterCollection Parameters
+		{
+			get  { return parameters; }
+		}
+
+		IDataParameterCollection IDbCommand.Parameters
+		{
+			get  { return parameters; }
+		}
+
+		[Browsable(false)]
+		public IDbTransaction Transaction
+		{
+			/*
+			* Set the transaction. Consider additional steps to ensure that the transaction
+			* is compatible with the connection, because the two are usually linked.
+			*/
+			get 
+			{ 
+				return curTransaction; 
+			}
+			set 
+			{ 
+				curTransaction = (MySqlTransaction)value; 
+			}
+		}
+
+		[Category("Behavior")]
+		public UpdateRowSource UpdatedRowSource
+		{
+			get 
+			{ 
+				return updatedRowSource;  
+			}
+			set 
+			{ 
+				updatedRowSource = value; 
+			}
+		}
+		#endregion
+
+		#region Methods
+		public void Cancel()
+		{
+			throw new NotSupportedException();
+		}
+
+		public MySqlParameter CreateParameter()
+		{
+			return new MySqlParameter();
+		}
+
+		IDbDataParameter IDbCommand.CreateParameter()
+		{
+			return CreateParameter();
+		}
+
+		private ArrayList SplitSql(string sql)
+		{
+			ArrayList commands = new ArrayList();
+			System.IO.MemoryStream ms = new System.IO.MemoryStream();
+
+			// first we tack on a semi-colon, if not already there, to make our
+			// sql processing code easier.  Then we ask our encoder to give us
+			// the bytes for this sql string
+			byte[] bytes = connection.Encoding.GetBytes(sql + ";");
+
+			byte left_byte = 0;
+			bool escaped = false;
+			int  parm_start=-1;
+			for (int x=0; x < bytes.Length; x++)
+			{
+				byte b = bytes[x];
+
+				// if we see a quote marker, then check to see if we are opening
+				// or closing a quote
+				if ((b == '\'' || b == '\"') && ! escaped )
+				{
+					if (b == left_byte) left_byte = 0;
+					else if (left_byte == 0) left_byte = b;
+				}
+
+				else if (b == '\\') 
+				{
+					escaped = !escaped;
+				}
+
+					// if we see the marker for a parameter, then save its position and
+					// look for the end
+				else if (b == '@' && left_byte == 0 && ! escaped && parm_start==-1) 
+					parm_start = x;
+
+					// if we see a space and we are tracking a parameter, then end the parameter and have
+					// that parameter serialize itself to the memory stream
+				else if (parm_start > -1 && (b != '@') && (b != '$') && (b != '_') && (b != '.') && ! Char.IsLetterOrDigit((char)b))
+				{
+					string parm_name = sql.Substring(parm_start, x-parm_start); 
+
+					if(parm_name.Length<2 || parm_name[1]!='@') // if doesn't begin with @@, do our processing.
+					{
+						MySqlParameter p = (parameters[parm_name] as MySqlParameter);
+						p.SerializeToBytes(ms, connection );
+					}
+					else
+					{
+						// otherwise assume system param. just write it out
+						byte[] buf = connection.Encoding.GetBytes(parm_name);
+						ms.Write(buf, 0, buf.Length); 
+					}
+					parm_start=-1;
+				}
+
+				// if we are not in a string and we are not escaped and we are on a semi-colon,
+				// then write out what we have as a command
+				if (left_byte == 0 && ! escaped && b == ';' && ms.Length > 0)
+				{
+					commands.Add( ms.ToArray() );
+					ms.SetLength(0);
+				}
+				else if (parm_start == -1)
+					ms.WriteByte(b);
+
+
+				// we want to write out the bytes in all cases except when we are parsing out a parameter
+				if (escaped && b != '\\') escaped = false;
+			}
+
+			return commands;
+		}
+
+/*		internal void ExecuteRemainingCommands()
+		{
+			// let's execute any remaining commands
+			Packet packet = ExecuteNextSql();
+			while (packet != null)
+			{
+				while (packet.Type != PacketType.Last)
+					packet = connection.InternalConnection.Driver.ReadPacket();
+				packet = ExecuteNextSql();
+			}
+		}
+*/
+		/// <summary>
+		/// Internal function to execute the next command in an array of commands
+		/// </summary>
+		internal Packet ExecuteBatch( bool stopAtResultSet )
+		{
+			Driver driver = connection.InternalConnection.Driver;
+
+			while (arraySql.Count > 0)
+			{
+				byte[] sql = (byte[])arraySql[0];
+				arraySql.RemoveAt(0);
+
+				string s = connection.Encoding.GetString(sql);
+				Packet packet =  driver.SendSql( s );
+				if (packet.Type == PacketType.UpdateOrOk)
+					updateCount += (int)packet.ReadLenInteger();
+				else if (packet.Type == PacketType.ResultSchema && stopAtResultSet)
+					return packet;
+				else do 
+					 {
+						packet = driver.ReadPacket();
+					 } while (packet.Type != PacketType.Last);
+			}
+			return null;
+		}
+
+		/// <summary>
+		/// Executes a single non-select SQL statement.  Examples of this are update,
+		/// insert, etc.
+		/// </summary>
+		/// <returns>Number of rows affected</returns>
+		public int ExecuteNonQuery()
+		{
+			// There must be a valid and open connection.
+			if (connection == null || connection.State != ConnectionState.Open)
+				throw new InvalidOperationException("Connection must valid and open");
+
+			// Data readers have to be closed first
+			if (connection.Reader != null)
+				throw new MySqlException("There is already an open DataReader associated with this Connection which must be closed first.");
+
+			// execute any commands left in the queue from before.
+			ExecuteBatch(false);
+			
+			arraySql = SplitSql( cmdText );
+			updateCount = 0;
+
+			ExecuteBatch(false);
+
+			return (int)updateCount;
+		}
+
+		IDataReader IDbCommand.ExecuteReader ()
+		{
+			return ExecuteReader ();
+		}
+
+		IDataReader IDbCommand.ExecuteReader (CommandBehavior behavior)
+		{
+			return ExecuteReader (behavior);
+		}
+
+		public MySqlDataReader ExecuteReader()
+		{
+			return ExecuteReader(CommandBehavior.Default);
+		}
+
+		public MySqlDataReader ExecuteReader(CommandBehavior behavior)
+		{
+			/*
+			* ExecuteReader should retrieve results from the data source
+			* and return a DataReader that allows the user to process 
+			* the results.
+			*/
+
+			// There must be a valid and open connection.
+			if (connection == null || connection.State != ConnectionState.Open)
+				throw new InvalidOperationException("Connection must valid and open");
+
+			// make sure all readers on this connection are closed
+			if (connection.Reader != null)
+				throw new InvalidOperationException("There is already an open DataReader associated with this Connection which must be closed first.");
+
+			string sql = cmdText;
+
+			if (0 != (behavior & CommandBehavior.KeyInfo))
+			{
+			}
+
+			if (0 != (behavior & CommandBehavior.SchemaOnly))
+			{
+			}
+
+			if (0 != (behavior & CommandBehavior.SequentialAccess))
+			{
+			}
+
+			if (0 != (behavior & CommandBehavior.SingleResult))
+			{
+			}
+
+			if (0 != (behavior & CommandBehavior.SingleRow))
+			{
+				sql = String.Format("SET SQL_SELECT_LIMIT=1;{0};SET sql_select_limit=-1;", cmdText);
+			}
+
+			// execute any commands left in the queue from before.
+			ExecuteBatch(false);
+
+			arraySql = SplitSql( sql );
+
+			MySqlDataReader reader = new MySqlDataReader(this, behavior);
+
+			try 
+			{
+				if (reader.NextResult()) 
+				{
+					connection.Reader = reader;
+					return reader;
+				}
+				return null;
+			}
+			catch (Exception e) 
+			{
+				System.Diagnostics.Trace.WriteLine("Exception in ExecuteReader: " + e.Message);
+				throw e;
+			}
+		}
+
+		/// <summary>
+		/// ExecuteScalar executes a single SQL command that will return
+		/// a single row with a single column, or if more rows/columns are
+		/// returned it will return the first column of the first row.
+		/// </summary>
+		/// <returns></returns>
+		public object ExecuteScalar()
+		{
+			// There must be a valid and open connection.
+			if (connection == null || connection.State != ConnectionState.Open)
+				throw new InvalidOperationException("Connection must valid and open");
+
+			// Data readers have to be closed first
+			if (connection.Reader != null)
+				throw new MySqlException("There is already an open DataReader associated with this Connection which must be closed first.");
+
+			// execute any commands left in the queue from before.
+			ExecuteBatch(false);
+
+			arraySql = SplitSql( cmdText );
+
+			MySqlDataReader reader = new MySqlDataReader(this, 0);
+			reader.NextResult();
+			object val = null;
+			if (reader.Read())
+				val = reader.GetValue(0);
+			reader.Close();
+			return val;
+		}
+
+		public void Prepare()
+		{
+		}
+		#endregion
+
+		#region ICloneable
+		public object Clone() 
+		{
+			MySqlCommand clone = new MySqlCommand(cmdText, connection, curTransaction);
+			foreach (MySqlParameter p in parameters) 
+			{
+				clone.Parameters.Add(p.Clone());
+			}
+			return clone;
+		}
+		#endregion
+  }
+}

+ 42 - 42
mcs/class/ByteFX.Data/mysqlclient/command.resx

@@ -1,42 +1,42 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<root>
-	<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
-		<xsd:element name="root" msdata:IsDataSet="true">
-			<xsd:complexType>
-				<xsd:choice maxOccurs="unbounded">
-					<xsd:element name="data">
-						<xsd:complexType>
-							<xsd:sequence>
-								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-								<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
-							</xsd:sequence>
-							<xsd:attribute name="name" type="xsd:string" />
-							<xsd:attribute name="type" type="xsd:string" />
-							<xsd:attribute name="mimetype" type="xsd:string" />
-						</xsd:complexType>
-					</xsd:element>
-					<xsd:element name="resheader">
-						<xsd:complexType>
-							<xsd:sequence>
-								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-							</xsd:sequence>
-							<xsd:attribute name="name" type="xsd:string" use="required" />
-						</xsd:complexType>
-					</xsd:element>
-				</xsd:choice>
-			</xsd:complexType>
-		</xsd:element>
-	</xsd:schema>
-	<resheader name="ResMimeType">
-		<value>text/microsoft-resx</value>
-	</resheader>
-	<resheader name="Version">
-		<value>1.0.0.0</value>
-	</resheader>
-	<resheader name="Reader">
-		<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.3102.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-	</resheader>
-	<resheader name="Writer">
-		<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.3102.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-	</resheader>
-</root>
+<?xml version="1.0" encoding="utf-8" ?>
+<root>
+	<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+		<xsd:element name="root" msdata:IsDataSet="true">
+			<xsd:complexType>
+				<xsd:choice maxOccurs="unbounded">
+					<xsd:element name="data">
+						<xsd:complexType>
+							<xsd:sequence>
+								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+								<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+							</xsd:sequence>
+							<xsd:attribute name="name" type="xsd:string" />
+							<xsd:attribute name="type" type="xsd:string" />
+							<xsd:attribute name="mimetype" type="xsd:string" />
+						</xsd:complexType>
+					</xsd:element>
+					<xsd:element name="resheader">
+						<xsd:complexType>
+							<xsd:sequence>
+								<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+							</xsd:sequence>
+							<xsd:attribute name="name" type="xsd:string" use="required" />
+						</xsd:complexType>
+					</xsd:element>
+				</xsd:choice>
+			</xsd:complexType>
+		</xsd:element>
+	</xsd:schema>
+	<resheader name="ResMimeType">
+		<value>text/microsoft-resx</value>
+	</resheader>
+	<resheader name="Version">
+		<value>1.0.0.0</value>
+	</resheader>
+	<resheader name="Reader">
+		<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.3102.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+	</resheader>
+	<resheader name="Writer">
+		<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.3102.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+	</resheader>
+</root>

+ 193 - 186
mcs/class/ByteFX.Data/mysqlclient/dataadapter.cs

@@ -1,186 +1,193 @@
-// ByteFX.Data data access components for .Net
-// Copyright (C) 2002-2003  ByteFX, Inc.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-using System.Data;
-using System.Data.Common;
-
-namespace ByteFX.Data.MySQLClient
-{
-#if WINDOWS
-	[System.Drawing.ToolboxBitmap( typeof(MySQLDataAdapter), "Designers.dataadapter.bmp")]
-#endif
-	public sealed class MySQLDataAdapter : DbDataAdapter, IDbDataAdapter
-  {
-    private MySQLCommand m_selectCommand;
-    private MySQLCommand m_insertCommand;
-    private MySQLCommand m_updateCommand;
-    private MySQLCommand m_deleteCommand;
-
-    /*
-     * Inherit from Component through DbDataAdapter. The event
-     * mechanism is designed to work with the Component.Events
-     * property. These variables are the keys used to find the
-     * events in the components list of events.
-     */
-    static private readonly object EventRowUpdated = new object(); 
-    static private readonly object EventRowUpdating = new object(); 
-
-
-    public MySQLDataAdapter()
-    {
-    }
-
-	public MySQLDataAdapter( MySQLCommand selectCommand ) 
-	{
-		SelectCommand = selectCommand;
-	}
-
-	public MySQLDataAdapter( string selectCommandText, string selectConnString) 
-	{
-		SelectCommand = new MySQLCommand( selectCommandText, 
-			new MySQLConnection(selectConnString) );
-	}
-
-	public MySQLDataAdapter( string selectCommandText, MySQLConnection conn) 
-	{
-		SelectCommand = new MySQLCommand( selectCommandText, conn );
-	}
-
-    public MySQLCommand SelectCommand 
-    {
-      get { return m_selectCommand; }
-      set { m_selectCommand = value; }
-    }
-
-    IDbCommand IDbDataAdapter.SelectCommand 
-    {
-      get { return m_selectCommand; }
-      set { m_selectCommand = (MySQLCommand)value; }
-    }
-
-    public MySQLCommand InsertCommand 
-    {
-      get { return m_insertCommand; }
-      set { m_insertCommand = value; }
-    }
-
-    IDbCommand IDbDataAdapter.InsertCommand 
-    {
-      get { return m_insertCommand; }
-      set { m_insertCommand = (MySQLCommand)value; }
-    }
-
-    public MySQLCommand UpdateCommand 
-    {
-      get { return m_updateCommand; }
-      set { m_updateCommand = value; }
-    }
-
-    IDbCommand IDbDataAdapter.UpdateCommand 
-    {
-      get { return m_updateCommand; }
-      set { m_updateCommand = (MySQLCommand)value; }
-    }
-
-    public MySQLCommand DeleteCommand 
-    {
-      get { return m_deleteCommand; }
-      set { m_deleteCommand = value; }
-    }
-
-    IDbCommand IDbDataAdapter.DeleteCommand 
-    {
-      get { return m_deleteCommand; }
-      set { m_deleteCommand = (MySQLCommand)value; }
-    }
-
-    /*
-     * Implement abstract methods inherited from DbDataAdapter.
-     */
-    override protected RowUpdatedEventArgs CreateRowUpdatedEvent(DataRow dataRow, IDbCommand command, StatementType statementType, DataTableMapping tableMapping)
-    {
-      return new MySQLRowUpdatedEventArgs(dataRow, command, statementType, tableMapping);
-    }
-
-    override protected RowUpdatingEventArgs CreateRowUpdatingEvent(DataRow dataRow, IDbCommand command, StatementType statementType, DataTableMapping tableMapping)
-    {
-      return new MySQLRowUpdatingEventArgs(dataRow, command, statementType, tableMapping);
-    }
-
-    override protected void OnRowUpdating(RowUpdatingEventArgs value)
-    {
-      MySQLRowUpdatingEventHandler handler = (MySQLRowUpdatingEventHandler) Events[EventRowUpdating];
-      if ((null != handler) && (value is MySQLRowUpdatingEventArgs)) 
-      {
-        handler(this, (MySQLRowUpdatingEventArgs) value);
-      }
-    }
-
-    override protected void OnRowUpdated(RowUpdatedEventArgs value)
-    {
-      MySQLRowUpdatedEventHandler handler = (MySQLRowUpdatedEventHandler) Events[EventRowUpdated];
-      if ((null != handler) && (value is MySQLRowUpdatedEventArgs)) 
-      {
-        handler(this, (MySQLRowUpdatedEventArgs) value);
-      }
-    }
-
-    public event MySQLRowUpdatingEventHandler RowUpdating
-    {
-      add { Events.AddHandler(EventRowUpdating, value); }
-      remove { Events.RemoveHandler(EventRowUpdating, value); }
-    }
-
-    public event MySQLRowUpdatedEventHandler RowUpdated
-    {
-      add { Events.AddHandler(EventRowUpdated, value); }
-      remove { Events.RemoveHandler(EventRowUpdated, value); }
-    }
-  }
-
-  public delegate void MySQLRowUpdatingEventHandler(object sender, MySQLRowUpdatingEventArgs e);
-  public delegate void MySQLRowUpdatedEventHandler(object sender, MySQLRowUpdatedEventArgs e);
-
-  public class MySQLRowUpdatingEventArgs : RowUpdatingEventArgs
-  {
-    public MySQLRowUpdatingEventArgs(DataRow row, IDbCommand command, StatementType statementType, DataTableMapping tableMapping) 
-      : base(row, command, statementType, tableMapping) 
-    {
-    }
-
-    // Hide the inherited implementation of the command property.
-    new public MySQLCommand Command
-    {
-      get  { return (MySQLCommand)base.Command; }
-      set  { base.Command = value; }
-    }
-  }
-
-  public class MySQLRowUpdatedEventArgs : RowUpdatedEventArgs
-  {
-    public MySQLRowUpdatedEventArgs(DataRow row, IDbCommand command, StatementType statementType, DataTableMapping tableMapping)
-      : base(row, command, statementType, tableMapping) 
-    {
-    }
-
-    // Hide the inherited implementation of the command property.
-    new public MySQLCommand Command
-    {
-      get  { return (MySQLCommand)base.Command; }
-    }
-  }
-}
+// ByteFX.Data data access components for .Net
+// Copyright (C) 2002-2003  ByteFX, Inc.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+using System.Data;
+using System.Data.Common;
+using System.ComponentModel;
+
+namespace ByteFX.Data.MySqlClient
+{
+	[System.Drawing.ToolboxBitmap( typeof(MySqlDataAdapter), "Designers.dataadapter.bmp")]
+	[System.ComponentModel.DesignerCategory("Code")]
+	public sealed class MySqlDataAdapter : DbDataAdapter, IDbDataAdapter
+	{
+		private MySqlCommand m_selectCommand;
+		private MySqlCommand m_insertCommand;
+		private MySqlCommand m_updateCommand;
+		private MySqlCommand m_deleteCommand;
+
+		/*
+			* Inherit from Component through DbDataAdapter. The event
+			* mechanism is designed to work with the Component.Events
+			* property. These variables are the keys used to find the
+			* events in the components list of events.
+			*/
+		static private readonly object EventRowUpdated = new object(); 
+		static private readonly object EventRowUpdating = new object(); 
+
+
+		public MySqlDataAdapter()
+		{
+		}
+
+		public MySqlDataAdapter( MySqlCommand selectCommand ) 
+		{
+			SelectCommand = selectCommand;
+		}
+
+		public MySqlDataAdapter( string selectCommandText, string selectConnString) 
+		{
+			SelectCommand = new MySqlCommand( selectCommandText, 
+				new MySqlConnection(selectConnString) );
+		}
+
+		public MySqlDataAdapter( string selectCommandText, MySqlConnection conn) 
+		{
+			SelectCommand = new MySqlCommand( selectCommandText, conn );
+		}
+
+		#region Properties
+		[DataSysDescription("Used during Fill/FillSchema")]
+		[Category("Fill")]
+		public MySqlCommand SelectCommand 
+		{
+			get { return m_selectCommand; }
+			set { m_selectCommand = value; }
+		}
+
+		IDbCommand IDbDataAdapter.SelectCommand 
+		{
+			get { return m_selectCommand; }
+			set { m_selectCommand = (MySqlCommand)value; }
+		}
+
+		[DataSysDescription("Used during Update for new rows in Dataset.")]
+		public MySqlCommand InsertCommand 
+		{
+			get { return m_insertCommand; }
+			set { m_insertCommand = value; }
+		}
+
+		IDbCommand IDbDataAdapter.InsertCommand 
+		{
+			get { return m_insertCommand; }
+			set { m_insertCommand = (MySqlCommand)value; }
+		}
+
+		[DataSysDescription("Used during Update for modified rows in Dataset.")]
+		public MySqlCommand UpdateCommand 
+		{
+			get { return m_updateCommand; }
+			set { m_updateCommand = value; }
+		}
+
+		IDbCommand IDbDataAdapter.UpdateCommand 
+		{
+			get { return m_updateCommand; }
+			set { m_updateCommand = (MySqlCommand)value; }
+		}
+
+		[DataSysDescription("Used during Update for deleted rows in Dataset.")]
+		public MySqlCommand DeleteCommand 
+		{
+			get { return m_deleteCommand; }
+			set { m_deleteCommand = value; }
+		}
+
+		IDbCommand IDbDataAdapter.DeleteCommand 
+		{
+			get { return m_deleteCommand; }
+			set { m_deleteCommand = (MySqlCommand)value; }
+		}
+		#endregion
+
+		/*
+			* Implement abstract methods inherited from DbDataAdapter.
+			*/
+		override protected RowUpdatedEventArgs CreateRowUpdatedEvent(DataRow dataRow, IDbCommand command, StatementType statementType, DataTableMapping tableMapping)
+		{
+			return new MySqlRowUpdatedEventArgs(dataRow, command, statementType, tableMapping);
+		}
+
+		override protected RowUpdatingEventArgs CreateRowUpdatingEvent(DataRow dataRow, IDbCommand command, StatementType statementType, DataTableMapping tableMapping)
+		{
+			return new MySqlRowUpdatingEventArgs(dataRow, command, statementType, tableMapping);
+		}
+
+		override protected void OnRowUpdating(RowUpdatingEventArgs value)
+		{
+			MySqlRowUpdatingEventHandler handler = (MySqlRowUpdatingEventHandler) Events[EventRowUpdating];
+			if ((null != handler) && (value is MySqlRowUpdatingEventArgs)) 
+			{
+				handler(this, (MySqlRowUpdatingEventArgs) value);
+			}
+		}
+
+		override protected void OnRowUpdated(RowUpdatedEventArgs value)
+		{
+			MySqlRowUpdatedEventHandler handler = (MySqlRowUpdatedEventHandler) Events[EventRowUpdated];
+			if ((null != handler) && (value is MySqlRowUpdatedEventArgs)) 
+			{
+				handler(this, (MySqlRowUpdatedEventArgs) value);
+			}
+		}
+
+		public event MySqlRowUpdatingEventHandler RowUpdating
+		{
+			add { Events.AddHandler(EventRowUpdating, value); }
+			remove { Events.RemoveHandler(EventRowUpdating, value); }
+		}
+
+		public event MySqlRowUpdatedEventHandler RowUpdated
+		{
+			add { Events.AddHandler(EventRowUpdated, value); }
+			remove { Events.RemoveHandler(EventRowUpdated, value); }
+		}
+	}
+
+	public delegate void MySqlRowUpdatingEventHandler(object sender, MySqlRowUpdatingEventArgs e);
+	public delegate void MySqlRowUpdatedEventHandler(object sender, MySqlRowUpdatedEventArgs e);
+
+	public class MySqlRowUpdatingEventArgs : RowUpdatingEventArgs
+	{
+		public MySqlRowUpdatingEventArgs(DataRow row, IDbCommand command, StatementType statementType, DataTableMapping tableMapping) 
+			: base(row, command, statementType, tableMapping) 
+		{
+		}
+
+		// Hide the inherited implementation of the command property.
+		new public MySqlCommand Command
+		{
+			get  { return (MySqlCommand)base.Command; }
+			set  { base.Command = value; }
+		}
+	}
+
+	public class MySqlRowUpdatedEventArgs : RowUpdatedEventArgs
+	{
+		public MySqlRowUpdatedEventArgs(DataRow row, IDbCommand command, StatementType statementType, DataTableMapping tableMapping)
+			: base(row, command, statementType, tableMapping) 
+		{
+		}
+
+		// Hide the inherited implementation of the command property.
+		new public MySqlCommand Command
+		{
+			get  { return (MySqlCommand)base.Command; }
+		}
+	}
+}

+ 535 - 464
mcs/class/ByteFX.Data/mysqlclient/datareader.cs

@@ -1,464 +1,535 @@
-// ByteFX.Data data access components for .Net
-// Copyright (C) 2002-2003  ByteFX, Inc.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-using System;
-using System.Data;
-using System.Collections;
-
-namespace ByteFX.Data.MySQLClient
-{
-	public sealed class MySQLDataReader : MarshalByRefObject, IEnumerable, IDataReader, IDisposable, IDataRecord
-	{
-		// The DataReader should always be open when returned to the user.
-		private bool m_fOpen = true;
-
-		// Keep track of the results and position
-		// within the resultset (starts prior to first record).
-		private MySQLField[]	_fields;
-		private ArrayList		m_Rows;
-		private	bool			m_IsSequential;
-
-		/* 
-		 * Keep track of the connection in order to implement the
-		 * CommandBehavior.CloseConnection flag. A null reference means
-		 * normal behavior (do not automatically close).
-		 */
-		private MySQLConnection _connection = null;
-
-		/*
-		 * Because the user should not be able to directly create a 
-		 * DataReader object, the constructors are
-		 * marked as internal.
-		 */
-		internal MySQLDataReader( MySQLConnection conn, bool Sequential)
-		{
-			_connection = conn;
-			m_IsSequential = Sequential;
-
-			m_Rows = new ArrayList();
-
-		}
-
-		/****
-		 * METHODS / PROPERTIES FROM IDataReader.
-		 ****/
-		public int Depth 
-		{
-			/*
-			 * Always return a value of zero if nesting is not supported.
-			 */
-			get { return 0;  }
-		}
-
-		public bool IsClosed
-		{
-			/*
-			 * Keep track of the reader state - some methods should be
-			 * disallowed if the reader is closed.
-			 */
-			get  { return !m_fOpen; }
-		}
-
-		public void Dispose() 
-		{
-		}
-
-		public int RecordsAffected 
-		{
-			/*
-			 * RecordsAffected is only applicable to batch statements
-			 * that include inserts/updates/deletes. The sample always
-			 * returns -1.
-			 */
-			get { return -1; }
-		}
-
-		internal void LoadResults() 
-		{
-			Driver d = _connection.Driver;
-
-			// When executing query statements, the result byte that is returned
-			// from MySQL is the column count.  That is why we reference the LastResult
-			// property here to dimension our field array
-			_fields = new MySQLField[d.LastResult];
-			for (int x=0; x < _fields.Length; x++) 
-			{
-				_fields[x] = new MySQLField();
-			}
-
-			_connection.m_State = ConnectionState.Fetching;
-
-			// Load in the column defs
-			for (int i=0; i < _fields.Length; i++) 
-			{
-				_fields[i].ReadSchemaInfo( d );
-			}
-
-			// read the end of schema packet
-			d.ReadPacket();
-			if (! d.IsLastPacketSignal())
-				throw new MySQLException("Expected end of column data.  Unknown transmission status");
-
-			_connection.m_State = ConnectionState.Open;
-		}
-
-		public void Close()
-		{
-			m_fOpen = false;
-			m_Rows.Clear();
-		}
-
-		public bool NextResult()
-		{
-			// The sample only returns a single resultset. However,
-			// DbDataAdapter expects NextResult to return a value.
-			return false;
-		}
-
-		public bool Read()
-		{
-			_connection.m_State = ConnectionState.Fetching;
-			Driver d = _connection.Driver;
-
-			try 
-			{
-				d.ReadPacket();
-			}
-			catch (Exception e)
-			{
-				Console.Error.WriteLine("MySQL.Net error: " + e.Message);
-				_connection.m_State = ConnectionState.Open;
-				return false;
-			}
-
-			if (d.IsLastPacketSignal()) 
-			{
-				_connection.m_State = ConnectionState.Open;
-				return false;
-			}
-
-			for (int col=0; col < _fields.Length; col++)
-			{
-				byte [] data = d.ReadColumnData();
-				_fields[col].SetValueData( data );
-			}
-
-			_connection.m_State = ConnectionState.Open;
-			return true;			
-		}
-
-		public DataTable GetSchemaTable()
-		{
-			// Only Results from SQL SELECT Queries 
-			// get a DataTable for schema of the result
-			// otherwise, DataTable is null reference
-			if (_fields.Length == 0) return null;
-
-			DataTable dataTableSchema = new DataTable ("SchemaTable");
-			
-			dataTableSchema.Columns.Add ("ColumnName", typeof (string));
-			dataTableSchema.Columns.Add ("ColumnOrdinal", typeof (int));
-			dataTableSchema.Columns.Add ("ColumnSize", typeof (int));
-			dataTableSchema.Columns.Add ("NumericPrecision", typeof (int));
-			dataTableSchema.Columns.Add ("NumericScale", typeof (int));
-			dataTableSchema.Columns.Add ("IsUnique", typeof (bool));
-			dataTableSchema.Columns.Add ("IsKey", typeof (bool));
-			DataColumn dc = dataTableSchema.Columns["IsKey"];
-			dc.AllowDBNull = true; // IsKey can have a DBNull
-			dataTableSchema.Columns.Add ("BaseCatalogName", typeof (string));
-			dataTableSchema.Columns.Add ("BaseColumnName", typeof (string));
-			dataTableSchema.Columns.Add ("BaseSchemaName", typeof (string));
-			dataTableSchema.Columns.Add ("BaseTableName", typeof (string));
-			dataTableSchema.Columns.Add ("DataType", typeof(Type));
-			dataTableSchema.Columns.Add ("AllowDBNull", typeof (bool));
-			dataTableSchema.Columns.Add ("ProviderType", typeof (int));
-			dataTableSchema.Columns.Add ("IsAliased", typeof (bool));
-			dataTableSchema.Columns.Add ("IsExpression", typeof (bool));
-			dataTableSchema.Columns.Add ("IsIdentity", typeof (bool));
-			dataTableSchema.Columns.Add ("IsAutoIncrement", typeof (bool));
-			dataTableSchema.Columns.Add ("IsRowVersion", typeof (bool));
-			dataTableSchema.Columns.Add ("IsHidden", typeof (bool));
-			dataTableSchema.Columns.Add ("IsLong", typeof (bool));
-			dataTableSchema.Columns.Add ("IsReadOnly", typeof (bool));
-
-			int ord = 1;
-			foreach (MySQLField f in _fields)
-			{
-				DataRow r = dataTableSchema.NewRow();
-				r["ColumnName"] = f.ColumnName;
-				r["ColumnOrdinal"] = ord++;
-				r["ColumnSize"] = f.ColumnLength;
-				int prec = f.NumericPrecision();
-				int pscale = f.NumericScale();
-				if (prec != -1)
-					r["NumericPrecision"] = (short)prec;
-				if (pscale != -1)
-					r["NumericScale"] = (short)pscale;
-				r["DataType"] = f.GetFieldType();
-				r["ProviderType"] = (int)f.GetDbType();
-				r["IsLong"] = f.IsBlob() && f.ColumnLength > 255;
-				r["AllowDBNull"] = f.AllowsNull();
-				r["IsReadOnly"] = false;
-				r["IsRowVersion"] = false;
-				r["IsUnique"] = f.IsUnique();
-				r["IsKey"] = f.IsPrimaryKey();
-				r["IsAutoIncrement"] = f.IsAutoIncrement();
-				r["BaseSchemaName"] = null;
-				r["BaseCatalogName"] = null;
-				r["BaseTableName"] = f.TableName;
-				r["BaseColumnName"] = f.ColumnName;
-
-				dataTableSchema.Rows.Add( r );
-			}
-
-			return dataTableSchema;
-		}
-
-		/****
-		 * METHODS / PROPERTIES FROM IDataRecord.
-		 ****/
-		public int FieldCount
-		{
-			// Return the count of the number of columns, which in
-			// this case is the size of the column metadata
-			// array.
-			get 
-			{ 
-				return _fields.Length;
-			}
-		}
-
-		public String GetName(int i)
-		{
-			return _fields[i].ColumnName;
-		}
-
-		public String GetDataTypeName(int i)
-		{
-			if (!m_fOpen) throw new Exception("No current query in data reader");
-			if (i >= _fields.Length) throw new IndexOutOfRangeException();
-
-			// return the name of the type used on the backend
-			return _fields[i].GetFieldTypeName();
-		}
-
-		public Type GetFieldType(int i)
-		{
-			if (!m_fOpen) throw new Exception("No current query in data reader");
-			if (i >= _fields.Length) throw new IndexOutOfRangeException();
-
-			return _fields[i].GetFieldType();
-		}
-
-		public Object GetValue(int i)
-		{
-			if (!m_fOpen) throw new Exception("No current query in data reader");
-			if (i >= _fields.Length) throw new IndexOutOfRangeException();
-
-			return _fields[i].GetValue();
-		}
-
-		public int GetValues(object[] values)
-		{
-			for (int i=0; i < _fields.Length; i ++) 
-			{
-				values[i] = GetValue(i);
-			}
-
-			return 0;
-		}
-
-		public int GetOrdinal(string name)
-		{
-			if (! m_fOpen)
-				throw new Exception("No current query in data reader");
-
-			for (int i=0; i < _fields.Length; i ++) 
-			{
-				if (_fields[i].ColumnName.ToLower().Equals(name.ToLower()))
-					return i;
-			}
-
-			// Throw an exception if the ordinal cannot be found.
-			throw new IndexOutOfRangeException("Could not find specified column in results");
-		}
-
-		public object this [ int i ]
-		{
-			get 
-			{
-				return this.GetValue(i);
-			}
-		}
-
-		public object this [ String name ]
-		{
-			// Look up the ordinal and return 
-			// the value at that position.
-			get { return this[GetOrdinal(name)]; }
-		}
-
-		public bool GetBoolean(int i)
-		{
-			return (bool)GetValue(i);
-		}
-
-		public byte GetByte(int i)
-		{
-			return (byte)GetValue(i);
-		}
-
-		public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)
-		{
-			if (i >= _fields.Length) 
-				throw new IndexOutOfRangeException();
-
-			byte[] bytes = (m_Rows[0] as ArrayList)[i] as byte[];
-
-			if (buffer == null) 
-				return bytes.Length;
-
-			/// adjust the length so we don't run off the end
-			if (bytes.Length < (fieldOffset+length)) 
-			{
-				length = (int)(bytes.Length - fieldOffset);
-			}
-
-			for (int x=0; x < length; x++)
-			{
-				buffer[bufferoffset+x] = bytes[fieldOffset+x];	
-			}
-
-			return length;
-		}
-
-		public char GetChar(int i)
-		{
-			return (char)GetValue(i);
-		}
-
-		public long GetChars(int i, long fieldOffset, char[] buffer, int bufferoffset, int length)
-		{
-			if (i >= _fields.Length) 
-				throw new IndexOutOfRangeException();
-
-			// retrieve the bytes of the column
-			long bytesize = GetBytes(i, 0, null, 0, 0);
-			byte[] bytes = new byte[bytesize];
-			GetBytes(i, 0, bytes, 0, (int)bytesize);
-
-			char[] chars = System.Text.Encoding.UTF8.GetChars(bytes, 0, (int)bytesize);
-
-			if (buffer == null) 
-				return chars.Length;
-
-			/// adjust the length so we don't run off the end
-			if (chars.Length < (fieldOffset+length)) 
-			{
-				length = (int)(chars.Length - fieldOffset);
-			}
-
-			for (int x=0; x < length; x++)
-			{
-				buffer[bufferoffset+x] = chars[fieldOffset+x];	
-			}
-
-			return length;
-		}
-
-		public Guid GetGuid(int i)
-		{
-			/*
-			* Force the cast to return the type. InvalidCastException
-			* should be thrown if the data is not already of the correct type.
-			*/
-			// The sample does not support this method.
-			throw new NotSupportedException("GetGUID not supported.");
-		}
-
-		public Int16 GetInt16(int i)
-		{
-			return (Int16)GetValue(i);
-		}
-
-		public Int32 GetInt32(int i)
-		{
-			return (Int32)GetValue(i);
-		}
-
-		public Int64 GetInt64(int i)
-		{
-			return (Int64)GetValue(i);
-		}
-
-		public float GetFloat(int i)
-		{
-			return (float)GetValue(i);
-		}
-
-		public double GetDouble(int i)
-		{
-			return (double)GetValue(i);
-		}
-
-		public String GetString(int i)
-		{
-			return (string)GetValue(i);
-		}
-
-		public Decimal GetDecimal(int i)
-		{
-			return (Decimal)GetValue(i);
-		}
-
-		public DateTime GetDateTime(int i)
-		{
-			return (DateTime)GetValue(i);
-		}
-
-		public IDataReader GetData(int i)
-		{
-			/*
-			* The sample code does not support this method. Normally,
-			* this would be used to expose nested tables and
-			* other hierarchical data.
-			*/
-			throw new NotSupportedException("GetData not supported.");
-		}
-
-		public bool IsDBNull(int i)
-		{
-			return DBNull.Value == GetValue(i);
-		}
-
-		/*
-		* Implementation specific methods.
-		*/
-		private int _cultureAwareCompare(string strA, string strB)
-		{
-	//      return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth | CompareOptions.IgnoreCase);
-			return 0;
-		}
-
-		#region IEnumerator
-		public IEnumerator	GetEnumerator()
-		{
-			return new System.Data.Common.DbEnumerator(this);
-		}
-		#endregion
-  }
-}
+// ByteFX.Data data access components for .Net
+// Copyright (C) 2002-2003  ByteFX, Inc.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+using System;
+using System.Data;
+using System.Collections;
+
+namespace ByteFX.Data.MySqlClient
+{
+	public sealed class MySqlDataReader : MarshalByRefObject, IEnumerable, IDataReader, IDisposable, IDataRecord
+	{
+		// The DataReader should always be open when returned to the user.
+		private bool			isOpen = true;
+
+		// Keep track of the results and position
+		// within the resultset (starts prior to first record).
+		private MySqlField[]	_fields;
+		private CommandBehavior	commandBehavior;
+		private MySqlCommand	command;
+		private bool			canRead;
+		private bool			hasRows;
+//		private Packet			rowPacket = null;
+
+		/* 
+		 * Keep track of the connection in order to implement the
+		 * CommandBehavior.CloseConnection flag. A null reference means
+		 * normal behavior (do not automatically close).
+		 */
+		private MySqlConnection connection = null;
+
+		/*
+		 * Because the user should not be able to directly create a 
+		 * DataReader object, the constructors are
+		 * marked as internal.
+		 */
+		internal MySqlDataReader( MySqlCommand cmd, CommandBehavior behavior)
+		{
+			this.command = cmd;
+			connection = (MySqlConnection)command.Connection;
+			commandBehavior = behavior;
+		}
+
+		/****
+		 * METHODS / PROPERTIES FROM IDataReader.
+		 ****/
+		public int Depth 
+		{
+			/*
+			 * Always return a value of zero if nesting is not supported.
+			 */
+			get { return 0;  }
+		}
+
+		public bool IsClosed
+		{
+			/*
+			 * Keep track of the reader state - some methods should be
+			 * disallowed if the reader is closed.
+			 */
+			get  { return ! isOpen; }
+		}
+
+		public void Dispose() 
+		{
+			if (isOpen)
+				Close();
+		}
+
+		public int RecordsAffected 
+		{
+			// RecordsAffected returns the number of rows affected in batch
+			// statments from insert/delete/update statments.  This property
+			// is not completely accurate until .Close() has been called.
+			get { return command.UpdateCount; }
+		}
+
+		public bool HasRows
+		{
+			get { return hasRows; }
+		}
+
+		/// <summary>
+		/// 
+		/// </summary>
+		public void Close()
+		{
+			// finish any current command
+			ClearCurrentResult();
+			command.ExecuteBatch(false);
+
+			connection.Reader = null;
+			if (0 != (commandBehavior & CommandBehavior.CloseConnection))
+				connection.Close();
+
+			isOpen = false;
+		}
+
+		/// <summary>
+		/// 
+		/// </summary>
+		/// <returns></returns>
+		public bool NextResult()
+		{
+			if (! isOpen)
+				throw new MySqlException("Invalid attempt to NextResult when reader is closed.");
+
+			Driver driver = connection.InternalConnection.Driver;
+
+			ClearCurrentResult();
+
+			// tell our command to execute the next sql batch
+			Packet packet = command.ExecuteBatch(true);
+
+			// if there was no more batches, then signal done
+			if (packet == null) return false;
+
+			// When executing query statements, the result byte that is returned
+			// from MySql is the column count.  That is why we reference the LastResult
+			// property here to dimension our field array
+			connection.SetState( ConnectionState.Fetching );
+			
+			_fields = new MySqlField[ packet.ReadLenInteger() ];
+			for (int x=0; x < _fields.Length; x++) 
+			{
+				_fields[x] = new MySqlField();
+				_fields[x].ReadSchemaInfo( packet );
+			}
+
+			// now take a quick peek at the next packet to see if we have rows
+			// 
+			packet = driver.PeekPacket();
+			hasRows = packet.Type != PacketType.Last;
+			canRead = hasRows;
+
+			connection.SetState( ConnectionState.Open );
+			return true;
+		}
+
+		/// <summary>
+		/// 
+		/// </summary>
+		/// <returns></returns>
+		public bool Read()
+		{
+			if (! isOpen)
+				throw new MySqlException("Invalid attempt to Read when reader is closed.");
+
+			if (! canRead) return false;
+
+			Driver driver = connection.InternalConnection.Driver;
+			connection.SetState( ConnectionState.Fetching );
+
+			try 
+			{
+				Packet rowPacket = driver.ReadPacket();
+				if (rowPacket.Type == PacketType.Last) 
+				{
+					canRead = false;
+					return false;
+				}
+				rowPacket.Position = 0;
+
+				for (int col=0; col < _fields.Length; col++)
+				{
+					int len = (int)rowPacket.ReadLenInteger();
+					_fields[col].SetValueData( rowPacket.GetBytes(), (int)rowPacket.Position, len, driver.Encoding );
+					rowPacket.Position += len;
+				}
+			}
+			catch (Exception ex)
+			{
+				System.Diagnostics.Trace.WriteLine("MySql error: " + ex.Message);
+				throw ex;
+			}
+			finally 
+			{
+				connection.SetState( ConnectionState.Open );
+			}
+			return true;
+		}
+
+		public DataTable GetSchemaTable()
+		{
+			// Only Results from SQL SELECT Queries 
+			// get a DataTable for schema of the result
+			// otherwise, DataTable is null reference
+			if (_fields.Length == 0) return null;
+
+			DataTable dataTableSchema = new DataTable ("SchemaTable");
+			
+			dataTableSchema.Columns.Add ("ColumnName", typeof (string));
+			dataTableSchema.Columns.Add ("ColumnOrdinal", typeof (int));
+			dataTableSchema.Columns.Add ("ColumnSize", typeof (int));
+			dataTableSchema.Columns.Add ("NumericPrecision", typeof (int));
+			dataTableSchema.Columns.Add ("NumericScale", typeof (int));
+			dataTableSchema.Columns.Add ("IsUnique", typeof (bool));
+			dataTableSchema.Columns.Add ("IsKey", typeof (bool));
+			DataColumn dc = dataTableSchema.Columns["IsKey"];
+			dc.AllowDBNull = true; // IsKey can have a DBNull
+			dataTableSchema.Columns.Add ("BaseCatalogName", typeof (string));
+			dataTableSchema.Columns.Add ("BaseColumnName", typeof (string));
+			dataTableSchema.Columns.Add ("BaseSchemaName", typeof (string));
+			dataTableSchema.Columns.Add ("BaseTableName", typeof (string));
+			dataTableSchema.Columns.Add ("DataType", typeof(Type));
+			dataTableSchema.Columns.Add ("AllowDBNull", typeof (bool));
+			dataTableSchema.Columns.Add ("ProviderType", typeof (int));
+			dataTableSchema.Columns.Add ("IsAliased", typeof (bool));
+			dataTableSchema.Columns.Add ("IsExpression", typeof (bool));
+			dataTableSchema.Columns.Add ("IsIdentity", typeof (bool));
+			dataTableSchema.Columns.Add ("IsAutoIncrement", typeof (bool));
+			dataTableSchema.Columns.Add ("IsRowVersion", typeof (bool));
+			dataTableSchema.Columns.Add ("IsHidden", typeof (bool));
+			dataTableSchema.Columns.Add ("IsLong", typeof (bool));
+			dataTableSchema.Columns.Add ("IsReadOnly", typeof (bool));
+
+			int ord = 1;
+			foreach (MySqlField f in _fields)
+			{
+				DataRow r = dataTableSchema.NewRow();
+				r["ColumnName"] = f.ColumnName;
+				r["ColumnOrdinal"] = ord++;
+				r["ColumnSize"] = f.ColumnLength;
+				int prec = f.NumericPrecision();
+				int pscale = f.NumericScale();
+				if (prec != -1)
+					r["NumericPrecision"] = (short)prec;
+				if (pscale != -1)
+					r["NumericScale"] = (short)pscale;
+				r["DataType"] = f.GetFieldType();
+				r["ProviderType"] = (int)f.GetMySqlDbType();
+				r["IsLong"] = f.IsBlob() && f.ColumnLength > 255;
+				r["AllowDBNull"] = f.AllowsNull();
+				r["IsReadOnly"] = false;
+				r["IsRowVersion"] = false;
+				r["IsUnique"] = f.IsUnique();
+				r["IsKey"] = f.IsPrimaryKey();
+				r["IsAutoIncrement"] = f.IsAutoIncrement();
+				r["BaseSchemaName"] = null;
+				r["BaseCatalogName"] = null;
+				r["BaseTableName"] = f.TableName;
+				r["BaseColumnName"] = f.ColumnName;
+
+				dataTableSchema.Rows.Add( r );
+			}
+
+			return dataTableSchema;
+		}
+
+		/****
+		 * METHODS / PROPERTIES FROM IDataRecord.
+		 ****/
+		public int FieldCount
+		{
+			// Return the count of the number of columns, which in
+			// this case is the size of the column metadata
+			// array.
+			get 
+			{ 
+				if (_fields != null)
+					return _fields.Length;
+				return 0;
+			}
+		}
+
+		public String GetName(int i)
+		{
+			return _fields[i].ColumnName;
+		}
+
+		public String GetDataTypeName(int i)
+		{
+			if (! isOpen) throw new Exception("No current query in data reader");
+			if (i >= _fields.Length) throw new IndexOutOfRangeException();
+
+			// return the name of the type used on the backend
+			return _fields[i].GetFieldTypeName();
+		}
+
+		public Type GetFieldType(int i)
+		{
+			if (! isOpen) throw new Exception("No current query in data reader");
+			if (i >= _fields.Length) throw new IndexOutOfRangeException();
+
+			return _fields[i].GetFieldType();
+		}
+
+		public object GetValue(int i)
+		{
+			if (! isOpen) throw new Exception("No current query in data reader");
+			if (i >= _fields.Length) throw new IndexOutOfRangeException();
+
+			return _fields[i].GetValue();
+		}
+
+		public int GetValues(object[] values)
+		{
+			for (int i=0; i < _fields.Length; i ++) 
+			{
+				values[i] = GetValue(i);
+			}
+
+			return 0;
+		}
+
+		public int GetOrdinal(string name)
+		{
+			if (! isOpen)
+				throw new Exception("No current query in data reader");
+
+			for (int i=0; i < _fields.Length; i ++) 
+			{
+				if (_fields[i].ColumnName.ToLower().Equals(name.ToLower()))
+					return i;
+			}
+
+			// Throw an exception if the ordinal cannot be found.
+			throw new IndexOutOfRangeException("Could not find specified column in results");
+		}
+
+		public object this [ int i ]
+		{
+			get 
+			{
+				return this.GetValue(i);
+			}
+		}
+
+		public object this [ String name ]
+		{
+			// Look up the ordinal and return 
+			// the value at that position.
+			get { return this[GetOrdinal(name)]; }
+		}
+
+		private MySqlField GetField(int i)
+		{
+			if (i >= _fields.Length) throw new IndexOutOfRangeException();
+			return _fields[i];
+		}
+
+		#region TypeSafe Accessors
+		public bool GetBoolean(int i)
+		{
+			return Convert.ToBoolean(GetValue(i));
+		}
+
+		public byte GetByte(int i)
+		{
+			return Convert.ToByte(GetValue(i));
+		}
+
+		public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)
+		{
+			if (i >= _fields.Length) 
+				throw new IndexOutOfRangeException();
+
+			byte[] bytes = (byte[])GetValue(i);
+
+			if (buffer == null) 
+				return bytes.Length;
+
+			/// adjust the length so we don't run off the end
+			if (bytes.Length < (fieldOffset+length)) 
+			{
+				length = (int)(bytes.Length - fieldOffset);
+			}
+
+			for (int x=0; x < length; x++)
+			{
+				buffer[bufferoffset+x] = bytes[fieldOffset+x];	
+			}
+
+			return length;
+		}
+
+		public char GetChar(int i)
+		{
+			return Convert.ToChar(GetValue(i));
+		}
+
+		public long GetChars(int i, long fieldOffset, char[] buffer, int bufferoffset, int length)
+		{
+			if (i >= _fields.Length) 
+				throw new IndexOutOfRangeException();
+
+			// retrieve the bytes of the column
+			long bytesize = GetBytes(i, 0, null, 0, 0);
+			byte[] bytes = new byte[bytesize];
+			GetBytes(i, 0, bytes, 0, (int)bytesize);
+
+			char[] chars = System.Text.Encoding.UTF8.GetChars(bytes, 0, (int)bytesize);
+
+			if (buffer == null) 
+				return chars.Length;
+
+			/// adjust the length so we don't run off the end
+			if (chars.Length < (fieldOffset+length)) 
+			{
+				length = (int)(chars.Length - fieldOffset);
+			}
+
+			for (int x=0; x < length; x++)
+			{
+				buffer[bufferoffset+x] = chars[fieldOffset+x];	
+			}
+
+			return length;
+		}
+
+		public Guid GetGuid(int i)
+		{
+			/*
+			* Force the cast to return the type. InvalidCastException
+			* should be thrown if the data is not already of the correct type.
+			*/
+			// The sample does not support this method.
+			throw new NotSupportedException("GetGUID not supported.");
+		}
+
+		public Int16 GetInt16(int i)
+		{
+			return Convert.ToInt16(GetValue(i));
+		}
+
+		public UInt16 GetUInt16( int i )
+		{
+			return Convert.ToUInt16(GetValue(i));
+		}
+
+		public Int32 GetInt32(int i)
+		{
+			return Convert.ToInt32(GetValue(i));
+		}
+
+		public UInt32 GetUInt32( int i )
+		{
+			return Convert.ToUInt32(GetValue(i));
+		}
+
+		public Int64 GetInt64(int i)
+		{
+			return Convert.ToInt64(GetValue(i));
+		}
+
+		public UInt64 GetUInt64( int i )
+		{
+			return Convert.ToUInt64(GetValue(i));
+		}
+
+		public float GetFloat(int i)
+		{
+			return Convert.ToSingle(GetValue(i));
+		}
+
+		public double GetDouble(int i)
+		{
+			return Convert.ToDouble(GetValue(i));
+		}
+
+		public String GetString(int i)
+		{
+			return GetValue(i).ToString();
+		}
+
+		public Decimal GetDecimal(int i)
+		{
+			return Convert.ToDecimal(GetValue(i));
+		}
+
+		public DateTime GetDateTime(int i)
+		{
+			return Convert.ToDateTime(GetValue(i));
+		}
+		#endregion
+
+		public IDataReader GetData(int i)
+		{
+			/*
+			* The sample code does not support this method. Normally,
+			* this would be used to expose nested tables and
+			* other hierarchical data.
+			*/
+			throw new NotSupportedException("GetData not supported.");
+		}
+
+		public bool IsDBNull(int i)
+		{
+			return DBNull.Value == GetValue(i);
+		}
+
+		/*
+		* Implementation specific methods.
+		*/
+		private int _cultureAwareCompare(string strA, string strB)
+		{
+	//      return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth | CompareOptions.IgnoreCase);
+			return 0;
+		}
+
+		#region Private Methods
+
+		private void ClearCurrentResult() 
+		{
+			if (! canRead) return;
+
+			Packet packet = connection.InternalConnection.Driver.ReadPacket();
+			// clean out any current resultset
+			while (packet.Type != PacketType.Last)
+				packet = connection.InternalConnection.Driver.ReadPacket();
+		}
+
+		#endregion
+
+		#region IEnumerator
+		public IEnumerator	GetEnumerator()
+		{
+			return new System.Data.Common.DbEnumerator(this);
+		}
+		#endregion
+  }
+}

+ 493 - 287
mcs/class/ByteFX.Data/mysqlclient/parameter.cs

@@ -1,287 +1,493 @@
-// ByteFX.Data data access components for .Net
-// Copyright (C) 2002-2003  ByteFX, Inc.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-using System;
-using System.Data;
-using System.Text;
-
-namespace ByteFX.Data.MySQLClient
-{
-	public sealed class MySQLParameter : MarshalByRefObject, IDataParameter, IDbDataParameter, ICloneable
-	{
-		MySQLDbType			m_dbType  = MySQLDbType.Null;
-		DbType				m_genericType;
-		ParameterDirection	m_direction = ParameterDirection.Input;
-		bool				m_fNullable  = false;
-		string				m_sParamName;
-		string				m_sSourceColumn;
-		DataRowVersion		m_sourceVersion = DataRowVersion.Current;
-		object				m_value;
-
-		public MySQLParameter()
-		{
-		}
-
-		public MySQLParameter(string name, MySQLDbType type, ParameterDirection dir, string col, DataRowVersion ver, object val)
-		{
-			m_dbType = type;
-			m_direction = dir;
-			m_sParamName = name;
-			m_sSourceColumn = col;
-			m_sourceVersion = ver;
-			m_value = val;
-		}
-
-		public MySQLParameter(string parameterName, MySQLDbType type)
-		{
-			m_sParamName = parameterName;
-			m_dbType   = type;
-		}
-
-		public MySQLParameter(string parameterName, object value)
-		{
-			m_sParamName = parameterName;
-			this.Value = value;   
-			// Setting the value also infers the type.
-		}
-
-		public MySQLParameter( string parameterName, MySQLDbType dbType, string sourceColumn )
-		{
-			m_sParamName  = parameterName;
-			m_dbType    = dbType;
-			m_sSourceColumn = sourceColumn;
-		}
-
-		DbType IDataParameter.DbType 
-		{
-			get { return m_genericType; }
-			set { m_genericType = value; }
-		}
-
-		public MySQLDbType DbType 
-		{
-			get  { return m_dbType; }
-			set  { m_dbType = value;  }
-		}
-
-		public ParameterDirection Direction 
-		{
-			get { return m_direction; }
-			set { m_direction = value; }
-		}
-
-		public Boolean IsNullable 
-		{
-			get { return m_fNullable; }
-		}
-
-		public String ParameterName 
-		{
-			get { return m_sParamName; }
-			set { m_sParamName = value; }
-		}
-
-		public String SourceColumn 
-		{
-			get { return m_sSourceColumn; }
-			set { m_sSourceColumn = value; }
-		}
-
-		public DataRowVersion SourceVersion 
-		{
-			get { return m_sourceVersion; }
-			set { m_sourceVersion = value; }
-		}
-
-		public object Value 
-		{
-			get
-			{
-				return m_value;
-			}
-			set
-			{
-				m_value    = value;
-				m_dbType  = _inferType(value);
-			}
-		}
-
-		private string ObjectToString()
-		{
-			return "";
-		}
-
-		private void EscapeByteArray( byte[] bytes, System.IO.MemoryStream s )
-		{
-			byte[] newbytes = new byte[ bytes.Length * 2 ];
-
-			int newx=0;
-			for (int x=0; x < bytes.Length; x++)
-			{
-				byte b = bytes[x];
-				if (b == '\0') 
-				{
-					newbytes[newx++] = (byte)'\\';
-					newbytes[newx++] = (byte)'0';
-				}
-				else 
-				{
-					if (b == '\\' || b == '\'' || b == '"')
-						newbytes[newx++] = (byte)'\\';
-					newbytes[newx++] = b;
-				}
-			}
-			s.Write( newbytes, 0, newx );
-		}
-
-		private string EscapeString( string s )
-		{
-			StringBuilder sb = new StringBuilder();
-
-			foreach (char c in s) 
-			{
-				if (c == '\'')
-					sb.Append(c);
-				sb.Append(c);
-			}
-			return sb.ToString();
-		}
-
-		public void SerializeToBytes( System.IO.MemoryStream s )
-		{
-			string parm_string;
-
-			switch (m_dbType) 
-			{
-				case MySQLDbType.Null:
-					parm_string = "Null";
-					break;
-
-				case MySQLDbType.VarChar:
-					parm_string = "'" + EscapeString(Value.ToString()) + "'";
-					break;
-
-				case MySQLDbType.Date:
-				{
-					parm_string = "'" + ((DateTime)Value).ToString("yyyy-MM-dd") + "'";
-					break;
-				}
-
-				case MySQLDbType.Datetime:
-				{
-					parm_string = "'" + ((DateTime)Value).ToString("yyyy-MM-dd HH:mm:ss") + "'";
-					break;
-				}
-
-				case MySQLDbType.Blob:
-					if (m_value.GetType() == Type.GetType("System.Byte[]"))
-					{
-						s.WriteByte((byte)'\'');
-						EscapeByteArray( (byte[])m_value, s );
-						s.WriteByte((byte)'\'');
-					}
-					return;
-
-				default:
-					parm_string = Value.ToString();
-					break;
-			}
-			byte[] bytes = System.Text.Encoding.ASCII.GetBytes(parm_string);
-			s.Write(bytes, 0, bytes.Length);
-		}
-
-		private MySQLDbType _inferType(Object value)
-		{
-			switch (Type.GetTypeCode(value.GetType()))
-			{
-			case TypeCode.Empty:
-				throw new SystemException("Invalid data type");
-
-			case TypeCode.Object:
-				return MySQLDbType.Blob;
-
-			case TypeCode.DBNull:
-				return MySQLDbType.Null;
-
-			case TypeCode.Char:
-			case TypeCode.SByte:
-			case TypeCode.Boolean:
-			case TypeCode.Byte:
-				return MySQLDbType.Byte;
-
-			case TypeCode.Int16:
-			case TypeCode.UInt16:
-				return MySQLDbType.Int24;
-
-			case TypeCode.Int32:
-			case TypeCode.UInt32:
-				return MySQLDbType.Long;
-
-			case TypeCode.Int64:
-			case TypeCode.UInt64:
-				return MySQLDbType.LongLong;
-
-			case TypeCode.Single:
-				return MySQLDbType.Float;
-
-			case TypeCode.Double:
-				return MySQLDbType.Double;
-
-			case TypeCode.Decimal:
-				return MySQLDbType.Decimal;
-
-			case TypeCode.DateTime:
-				return MySQLDbType.Datetime;
-
-			case TypeCode.String:
-				return MySQLDbType.VarChar;
-
-			default:
-				throw new SystemException("Value is of unknown data type");
-			}
-		}
-
-		// implement methods of IDbDataParameter
-		public byte Precision 
-		{
-			get { return 0; }
-			set { }
-		}
-
-		public byte Scale 
-		{
-			get { return 0; }
-			set { }
-		}
-
-		public int Size 
-		{
-			get { return 0; }
-			set { }
-		}
-
-		#region ICloneable
-		public object Clone() 
-		{
-			MySQLParameter clone = new MySQLParameter( m_sParamName, m_dbType, m_direction,
-								m_sSourceColumn, m_sourceVersion, m_value );
-			return clone;
-		}
-		#endregion
-
-  }
-}
+// ByteFX.Data data access components for .Net
+// Copyright (C) 2002-2003  ByteFX, Inc.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+using System;
+using System.Data;
+using System.Text;
+using System.ComponentModel;
+using System.ComponentModel.Design.Serialization;
+using System.Reflection;
+
+namespace ByteFX.Data.MySqlClient
+{
+	[TypeConverter(typeof(MySqlParameter.MySqlParameterConverter))]
+	public sealed class MySqlParameter : MarshalByRefObject, IDataParameter, IDbDataParameter, ICloneable
+	{
+		MySqlDbType			dbType  = MySqlDbType.Null;
+		DbType				genericType;
+		ParameterDirection	direction = ParameterDirection.Input;
+		bool				isNullable  = false;
+		string				paramName;
+		string				sourceColumn;
+		DataRowVersion		sourceVersion = DataRowVersion.Current;
+		object				paramValue = DBNull.Value;
+		int					size;
+		byte				precision=0, scale=0;
+
+		#region Constructors
+		public MySqlParameter()
+		{
+		}
+
+		public MySqlParameter(string parameterName, object value)
+		{
+			ParameterName = parameterName;
+			paramValue = value;
+			dbType = GetMySqlType( paramValue.GetType() );
+			genericType = GetGenericType( paramValue.GetType() );
+		}
+
+		public MySqlParameter( string parameterName, MySqlDbType type)
+		{
+			ParameterName = parameterName;
+			dbType   = type;
+		}
+
+		public MySqlParameter( string parameterName, MySqlDbType type, int size )
+		{
+			ParameterName = parameterName;
+			dbType = type;
+			this.size = size;
+		}
+
+		public MySqlParameter( string name, MySqlDbType dbType, int size, string sourceCol )
+		{
+			ParameterName = name;
+			this.dbType = dbType;
+			this.size = size;
+			this.direction = ParameterDirection.Input;
+			this.precision = 0;
+			this.scale = 0;
+			this.sourceColumn = sourceCol;
+			this.sourceVersion = DataRowVersion.Current;
+			this.paramValue =null;
+		}
+
+		public MySqlParameter(string name, MySqlDbType type, ParameterDirection dir, string col, DataRowVersion ver, object val)
+		{
+			dbType = type;
+			direction = dir;
+			ParameterName = name;
+			sourceColumn = col;
+			sourceVersion = ver;
+			paramValue = val;
+		}
+
+		public MySqlParameter( string parameterName, MySqlDbType dbType, int size, ParameterDirection direction,
+			bool isNullable, byte precision, byte scale, string sourceColumn, DataRowVersion sourceVersion,
+			object value)
+		{
+			ParameterName = parameterName;
+			this.dbType = dbType;
+			this.size = size;
+			this.direction = direction;
+			this.precision = precision;
+			this.scale = scale;
+			this.sourceColumn = sourceColumn;
+			this.sourceVersion = sourceVersion;
+			this.paramValue = value;
+		}
+		#endregion
+
+		#region Properties
+		public DbType DbType 
+		{
+			get 
+			{ 
+				return genericType; 
+			}
+			set 
+			{ 
+				genericType = value; 
+				switch (genericType) 
+				{
+					case DbType.AnsiString:
+					case DbType.AnsiStringFixedLength:
+					case DbType.String:
+					case DbType.StringFixedLength:
+					case DbType.Guid:
+						MySqlDbType = MySqlDbType.VarChar; break;
+
+					case DbType.Byte:
+					case DbType.SByte:
+					case DbType.Boolean:
+						MySqlDbType = MySqlDbType.Byte; break;
+
+					case DbType.Int16:
+					case DbType.UInt16:
+						MySqlDbType = MySqlDbType.Short; break;
+
+					case DbType.Int32:
+					case DbType.UInt32:
+						MySqlDbType = MySqlDbType.Long; break;
+						
+					case DbType.Int64:
+					case DbType.UInt64:
+						MySqlDbType = MySqlDbType.LongLong; break;
+
+					case DbType.DateTime:
+						MySqlDbType = MySqlDbType.Datetime;	break;
+
+					case DbType.Date:
+						MySqlDbType = MySqlDbType.Date; break;
+
+					case DbType.Time:
+						MySqlDbType = MySqlDbType.Time; break;
+
+					case DbType.Single:
+						MySqlDbType = MySqlDbType.Float; break;
+					case DbType.Double:
+					case DbType.Currency:
+						MySqlDbType = MySqlDbType.Double; break;
+
+					case DbType.Decimal:
+					case DbType.VarNumeric:
+						MySqlDbType = MySqlDbType.Decimal; break;
+
+					case DbType.Binary:
+					case DbType.Object:
+						MySqlDbType = MySqlDbType.Blob; break;
+				}
+			}
+		}
+
+		[Category("Data")]
+		public MySqlDbType MySqlDbType 
+		{
+			get  
+			{ 
+				return dbType; 
+			}
+			set  
+			{ 
+				dbType = value;  
+			}
+		}
+
+		[Category("Data")]
+		public ParameterDirection Direction 
+		{
+			get { return direction; }
+			set { direction = value; }
+		}
+
+		[Browsable(false)]
+		public Boolean IsNullable 
+		{
+			get { return isNullable; }
+		}
+
+		[Category("Misc")]
+		public String ParameterName 
+		{
+			get { return paramName; }
+			set 
+			{ 
+				paramName = value; 
+				if (paramName[0] == '@')
+					paramName = paramName.Substring(1, paramName.Length-1);
+			}
+		}
+
+		[Category("Data")]
+		public String SourceColumn 
+		{
+			get { return sourceColumn; }
+			set { sourceColumn = value; }
+		}
+
+		[Category("Data")]
+		public DataRowVersion SourceVersion 
+		{
+			get { return sourceVersion; }
+			set { sourceVersion = value; }
+		}
+
+		[TypeConverter(typeof(StringConverter))]
+		[Category("Data")]
+		public object Value 
+		{
+			get	{ return paramValue; }
+			set	
+			{ 
+				paramValue = value; 
+				if (dbType == MySqlDbType.Null) 
+				{
+					dbType = GetMySqlType( paramValue.GetType() );
+					genericType = GetGenericType( paramValue.GetType() );
+				}
+			}
+		}
+
+		// implement methods of IDbDataParameter
+		[Category("Data")]
+		public byte Precision 
+		{
+			get { return precision; }
+			set { precision = value; }
+		}
+
+		[Category("Data")]
+		public byte Scale 
+		{
+			get { return scale; }
+			set { scale = value; }
+		}
+
+		[Category("Data")]
+		public int Size 
+		{
+			get { return size; }
+			set { size = value; }
+		}
+		#endregion
+
+		private void EscapeByteArray( byte[] bytes, System.IO.MemoryStream s )
+		{
+			byte[] newbytes = new byte[ bytes.Length * 2 ];
+
+			int newx=0;
+			for (int x=0; x < bytes.Length; x++)
+			{
+				byte b = bytes[x];
+				if (b == '\0') 
+				{
+					newbytes[newx++] = (byte)'\\';
+					newbytes[newx++] = (byte)'0';
+				}
+				else 
+				{
+					if (b == '\\' || b == '\'' || b == '"')
+						newbytes[newx++] = (byte)'\\';
+					newbytes[newx++] = b;
+				}
+			}
+			s.Write( newbytes, 0, newx );
+		}
+
+		public override string ToString() 
+		{
+			return paramName;
+		}
+
+		private string EscapeString( string s )
+		{
+			StringBuilder sb = new StringBuilder();
+
+			foreach (char c in s) 
+			{
+				if (c == '\'')
+					sb.Append(c);
+				sb.Append(c);
+			}
+			return sb.ToString();
+		}
+
+		public void SerializeToBytes( System.IO.MemoryStream s, MySqlConnection conn )
+		{
+			string	parm_string = null;
+			byte[]	bytes = null;
+
+			if (Value == DBNull.Value || Value == null)
+				parm_string = "Null";
+			else if (paramValue is bool)
+				parm_string = Convert.ToByte(paramValue).ToString();
+			else 
+			{
+				switch (dbType) 
+				{
+					case MySqlDbType.Null:
+						parm_string = "Null";
+						break;
+
+					case MySqlDbType.VarChar:
+					case MySqlDbType.String:
+						parm_string = "'" + EscapeString(Value.ToString()) + "'";
+						break;
+
+					case MySqlDbType.Double:
+						parm_string = Convert.ToDouble(Value).ToString( conn.NumberFormat );
+						break;
+
+					case MySqlDbType.Float:
+						parm_string = Convert.ToSingle(Value).ToString( conn.NumberFormat );
+						break;
+
+					case MySqlDbType.Decimal:
+						parm_string = Convert.ToDecimal(Value).ToString( conn.NumberFormat );
+						break;
+
+					case MySqlDbType.Time:
+						if (Value is DateTime)
+							parm_string = String.Format("'{0:HH:mm:ss}'", ((DateTime)Value));
+						else 
+							parm_string = String.Format("'{0}'", Value.ToString());
+						break;
+
+					case MySqlDbType.Date:
+						if (Value is DateTime)
+							parm_string = String.Format("'{0:yyyy-MM-dd}'", ((DateTime)Value));
+						else 
+							parm_string = "'" + Value.ToString() + "'";
+						break;
+
+					case MySqlDbType.Datetime:
+						if (Value is DateTime)
+							parm_string = String.Format("'{0:yyyy-MM-dd HH:mm:ss}'", ((DateTime)Value));
+						else
+							parm_string = "'" + Value + "'";
+						break;
+
+					case MySqlDbType.Blob:
+					case MySqlDbType.MediumBlob:
+					case MySqlDbType.LongBlob:
+					case MySqlDbType.TinyBlob:
+						Type t = paramValue.GetType();
+
+						if (t == typeof(System.Byte[]))
+						{
+							s.WriteByte((byte)'\'');
+							EscapeByteArray( (byte[])paramValue, s );
+							s.WriteByte((byte)'\'');
+							return;
+						}
+						else if(t == typeof(string)) 
+							parm_string = "'" + EscapeString((string)paramValue) + "'";
+						else if (t == typeof(System.Guid))
+						{
+							parm_string = "'" + paramValue.ToString() + "'";
+						}
+						break;
+
+					default:
+						parm_string = Value.ToString();
+						break;
+				}
+			}
+
+			bytes = conn.Encoding.GetBytes(parm_string);
+			s.Write(bytes, 0, bytes.Length);
+		}
+
+		private DbType GetGenericType( Type systemType )
+		{
+			switch ( Type.GetTypeCode(systemType) )
+			{
+				case TypeCode.Boolean: return DbType.Boolean;
+				case TypeCode.Byte: return DbType.Byte;
+				case TypeCode.Char: return DbType.StringFixedLength;
+				case TypeCode.DateTime: return DbType.DateTime;
+				case TypeCode.Decimal: return DbType.Decimal;
+				case TypeCode.Double: return DbType.Double;
+				case TypeCode.Int16: return DbType.Int16;
+				case TypeCode.Int32: return DbType.Int32;
+				case TypeCode.Int64: return DbType.Int64;
+				case TypeCode.Object: return DbType.Binary;
+				case TypeCode.SByte: return DbType.SByte;
+				case TypeCode.Single: return DbType.Single;
+				case TypeCode.String: return DbType.String;
+				case TypeCode.UInt16: return DbType.UInt16;
+				case TypeCode.UInt32: return DbType.UInt32;
+				case TypeCode.UInt64: return DbType.UInt64;
+			}
+			return DbType.Object;
+		}
+
+		private MySqlDbType GetMySqlType( Type systemType )
+		{
+			switch (Type.GetTypeCode( systemType ))
+			{
+				case TypeCode.Empty:
+					throw new SystemException("Invalid data type");
+
+				case TypeCode.Object: return MySqlDbType.Blob;
+				case TypeCode.DBNull: return MySqlDbType.Null;
+				case TypeCode.Char:
+				case TypeCode.SByte:
+				case TypeCode.Boolean:
+				case TypeCode.Byte: return MySqlDbType.Byte;
+				case TypeCode.Int16:
+				case TypeCode.UInt16: return MySqlDbType.Int24;
+				case TypeCode.Int32:
+				case TypeCode.UInt32: return MySqlDbType.Long;
+				case TypeCode.Int64:
+				case TypeCode.UInt64: return MySqlDbType.LongLong;
+				case TypeCode.Single: return MySqlDbType.Float;
+				case TypeCode.Double: return MySqlDbType.Double;
+				case TypeCode.Decimal: return MySqlDbType.Decimal;
+				case TypeCode.DateTime: return MySqlDbType.Datetime;
+				case TypeCode.String: return MySqlDbType.VarChar;
+
+				default:
+					throw new SystemException("Value is of unknown data type");
+			}
+		}
+
+
+		#region ICloneable
+		public object Clone() 
+		{
+			MySqlParameter clone = new MySqlParameter( paramName, dbType, direction,
+				sourceColumn, sourceVersion, paramValue );
+			return clone;
+		}
+		#endregion
+
+		/* A TypeConverter for the Triangle object.  Note that you can make it internal,
+				private, or any scope you want and the designers will still be able to use
+				it through the TypeDescriptor object.  This type converter provides the
+				capability to convert to an InstanceDescriptor.  This object can be used by 
+		   the .NET Framework to generate source code that creates an instance of a 
+		   Triangle object. */
+		internal class MySqlParameterConverter : TypeConverter
+		{
+			/* This method overrides CanConvertTo from TypeConverter. This is called when someone
+					wants to convert an instance of Triangle to another type.  Here,
+					only conversion to an InstanceDescriptor is supported. */
+			public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+			{
+				if (destinationType == typeof(InstanceDescriptor))
+				{
+					return true;
+				}
+
+				// Always call the base to see if it can perform the conversion.
+				return base.CanConvertTo(context, destinationType);
+			}
+
+			/* This code performs the actual conversion from a Triangle to an InstanceDescriptor. */
+			public override object ConvertTo(ITypeDescriptorContext context, 
+				System.Globalization.CultureInfo culture, object value, Type destinationType)
+			{
+				if (destinationType == typeof(InstanceDescriptor))
+				{
+					ConstructorInfo ci = typeof(MySqlParameter).GetConstructor(
+						new Type[]{typeof(string), typeof(MySqlDbType), typeof(int), typeof(ParameterDirection),
+						typeof(bool), typeof(byte), typeof(byte), typeof(string), typeof(DataRowVersion),
+						typeof(object)});
+					MySqlParameter p = (MySqlParameter) value;
+					return new InstanceDescriptor(ci,new object[]{ 
+						p.ParameterName, p.DbType, p.Size, p.Direction, p.IsNullable, p.Precision,
+						p.Scale, p.SourceColumn, p.SourceVersion, p.Value});
+				}
+
+				// Always call base, even if you can't convert.
+				return base.ConvertTo(context, culture, value, destinationType);
+			}
+		}
+	}
+}

+ 212 - 210
mcs/class/ByteFX.Data/mysqlclient/parameter_collection.cs

@@ -1,210 +1,212 @@
-// ByteFX.Data data access components for .Net
-// Copyright (C) 2002-2003  ByteFX, Inc.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-using System;
-using System.Data;
-using System.Collections;
-
-namespace ByteFX.Data.MySQLClient
-{
-	public sealed class MySQLParameterCollection : MarshalByRefObject, IDataParameterCollection, 
-		IList, ICollection, IEnumerable
-	{
-		private ArrayList	_parms = new ArrayList();
-
-		#region ICollection support
-		public int Count 
-		{
-			get { return _parms.Count; }
-		}
-
-		public void CopyTo( Array array, int index ) 
-		{
-/*			if (null == array) throw new ArgumentNullException("array", "Array must not be null");
-			if (index < 0) throw new ArgumentOutOfRangeException("index", index, "Index must be greater than or equal to zero");
-			if (array.Rank > 1) throw new ArgumentException("Array must not be multidimensional", "Array");
-			if (index >= array.Length) throw new ArgumentException("Index must start within the bounds of the array", "Index");
-			if ((index + Count) > array.Length) throw new ArgumentException("Not enough room to copy parameters", "Array");
-*/
-			_parms.CopyTo(array, index);
-		}
-
-		public bool IsSynchronized
-		{
-			get { return _parms.IsSynchronized; }
-		}
-
-		public object SyncRoot
-		{
-			get { return _parms.SyncRoot; }
-		}
-		#endregion
-
-		#region IList
-		public void Clear()
-		{
-			_parms.Clear();
-		}
-
-		public bool Contains(object value)
-		{
-			return _parms.Contains(value);
-		}
-
-		public int IndexOf(object value)
-		{
-			return _parms.IndexOf(value);
-		}
-
-		public void Insert(int index, object value)
-		{
-			_parms.Insert( index, value );
-		}
-
-		public bool IsFixedSize
-		{
-			get { return _parms.IsFixedSize; }
-		}
-
-		public bool IsReadOnly
-		{
-			get { return _parms.IsReadOnly; }
-		}
-
-		public void Remove( object value )
-		{
-			_parms.Remove( value );
-		}
-
-		public void RemoveAt( int index )
-		{
-			_parms.RemoveAt( index );
-		}
-
-		object IList.this[int index] 
-		{
-			get { return this[index]; }
-			set 
-			{ 
-				if (! (value is MySQLParameter)) throw new MySQLException("Only MySQLParameter objects may be stored");
-				this[index] = (MySQLParameter)value; 
-			}
-		}
-
-		public int Add( object value )
-		{
-			if (! (value is MySQLParameter)) throw new MySQLException("Only MySQLParameter objects may be stored");
-
-
-			if ( ((MySQLParameter)value).ParameterName == null ) 
-				throw new ArgumentException("parameter must be named");
-
-			return _parms.Add(value);
-		}
-
-		#endregion
-
-		#region IDataParameterCollection
-		public bool Contains(string name)
-		{
-			foreach (MySQLParameter p in _parms)
-			{
-				if (p.ParameterName.ToLower().Equals( name.ToLower() )) return true;
-			}
-			return false;
-		}
-
-		public int IndexOf( string name )
-		{
-			for (int x=0; x < _parms.Count; x++) 
-			{
-				MySQLParameter p = (MySQLParameter)_parms[x];
-				if (p.ParameterName.ToLower().Equals( name.ToLower() )) return x;
-			}
-			throw new MySQLException("Parameter '" + name + "' not found in collection");
-		}
-
-		public void RemoveAt( string name )
-		{
-			int index = IndexOf( name );
-			_parms.RemoveAt(index);
-		}
-
-		object IDataParameterCollection.this[string name]
-		{
-			get { return this[name]; }
-			set 
-			{ 
-				if (! (value is MySQLParameter)) throw new MySQLException("Only MySQLParameter objects may be stored");
-				this[name] = (MySQLParameter)value;
-			}
-		}
-		#endregion
-
-		#region IEnumerable
-		public IEnumerator GetEnumerator()
-		{
-			return ((IEnumerable)_parms).GetEnumerator();
-		}
-		#endregion
-
-		#region Public Methods
-		public MySQLParameter this[int index]
-		{
-			get { return (MySQLParameter)_parms[index]; }
-			set 
-			{ 
-				_parms[index] = value;
-			}
-		}
-
-		public MySQLParameter this[string name]
-		{
-			get { return (MySQLParameter)_parms[ IndexOf( name ) ]; }
-			set 
-			{ 
-				_parms[ IndexOf( name ) ] = value;
-			}
-		}
-
-		public MySQLParameter Add(MySQLParameter value)
-		{
-			if ( value.ParameterName == null ) throw new ArgumentException("parameter must be named");
-
-			_parms.Add(value);
-			return value;
-		}
-
-		public MySQLParameter Add(string parameterName, DbType type)
-		{
-			return Add(new MySQLParameter(parameterName, type));
-		}
-
-		public MySQLParameter Add(string parameterName, object value)
-		{
-			return Add(new MySQLParameter(parameterName, value));
-		}
-
-		public MySQLParameter Add(string parameterName, MySQLDbType dbType, string sourceColumn)
-		{
-			return Add(new MySQLParameter(parameterName, dbType, sourceColumn));
-		}
-
-		#endregion
-
-	}
-}
+// ByteFX.Data data access components for .Net
+// Copyright (C) 2002-2003  ByteFX, Inc.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+using System;
+using System.Data;
+using System.Collections;
+using System.ComponentModel;
+
+namespace ByteFX.Data.MySqlClient
+{
+	[Editor(typeof(ByteFX.Data.Common.DBParametersEditor), typeof(System.Drawing.Design.UITypeEditor))]
+	[ListBindable(true)]
+	public sealed class MySqlParameterCollection : MarshalByRefObject, IDataParameterCollection, 
+		IList, ICollection, IEnumerable
+	{
+		private ArrayList	_parms = new ArrayList();
+
+		#region ICollection support
+		public int Count 
+		{
+			get { return _parms.Count; }
+		}
+
+		public void CopyTo( Array array, int index ) 
+		{
+/*			if (null == array) throw new ArgumentNullException("array", "Array must not be null");
+			if (index < 0) throw new ArgumentOutOfRangeException("index", index, "Index must be greater than or equal to zero");
+			if (array.Rank > 1) throw new ArgumentException("Array must not be multidimensional", "Array");
+			if (index >= array.Length) throw new ArgumentException("Index must start within the bounds of the array", "Index");
+			if ((index + Count) > array.Length) throw new ArgumentException("Not enough room to copy parameters", "Array");
+*/
+			_parms.CopyTo(array, index);
+		}
+
+		public bool IsSynchronized
+		{
+			get { return _parms.IsSynchronized; }
+		}
+
+		public object SyncRoot
+		{
+			get { return _parms.SyncRoot; }
+		}
+		#endregion
+
+		#region IList
+		public void Clear()
+		{
+			_parms.Clear();
+		}
+
+		public bool Contains(object value)
+		{
+			return _parms.Contains(value);
+		}
+
+		public int IndexOf(object value)
+		{
+			return _parms.IndexOf(value);
+		}
+
+		public void Insert(int index, object value)
+		{
+			_parms.Insert( index, value );
+		}
+
+		public bool IsFixedSize
+		{
+			get { return _parms.IsFixedSize; }
+		}
+
+		public bool IsReadOnly
+		{
+			get { return _parms.IsReadOnly; }
+		}
+
+		public void Remove( object value )
+		{
+			_parms.Remove( value );
+		}
+
+		public void RemoveAt( int index )
+		{
+			_parms.RemoveAt( index );
+		}
+
+		object IList.this[int index] 
+		{
+			get { return this[index]; }
+			set 
+			{ 
+				if (! (value is MySqlParameter)) throw new MySqlException("Only MySqlParameter objects may be stored");
+				this[index] = (MySqlParameter)value; 
+			}
+		}
+
+		public int Add( object value )
+		{
+			if (! (value is MySqlParameter)) throw new MySqlException("Only MySqlParameter objects may be stored");
+
+			MySqlParameter p = (MySqlParameter)value;
+
+			if (p.ParameterName == null || p.ParameterName == String.Empty)
+				throw new MySqlException("Parameters must be named");
+
+			return _parms.Add(value);
+		}
+
+		#endregion
+
+		#region IDataParameterCollection
+		public bool Contains(string name)
+		{
+			if (name[0] == '@')
+				name = name.Substring(1, name.Length-1);
+			foreach (MySqlParameter p in _parms)
+			{
+				if (p.ParameterName.ToLower().Equals( name.ToLower() )) return true;
+			}
+			return false;
+		}
+
+		public int IndexOf( string name )
+		{
+			if (name[0] == '@')
+				name = name.Substring(1, name.Length-1);
+			for (int x=0; x < _parms.Count; x++) 
+			{
+				MySqlParameter p = (MySqlParameter)_parms[x];
+				if (p.ParameterName.ToLower().Equals( name.ToLower() )) return x;
+			}
+			throw new MySqlException("Parameter '" + name + "' not found in collection");
+		}
+
+		public void RemoveAt( string name )
+		{
+			int index = IndexOf( name );
+			_parms.RemoveAt(index);
+		}
+
+		object IDataParameterCollection.this[string name]
+		{
+			get { return this[name]; }
+			set 
+			{ 
+				if (! (value is MySqlParameter)) throw new MySqlException("Only MySqlParameter objects may be stored");
+				this[name] = (MySqlParameter)value;
+			}
+		}
+		#endregion
+
+		#region IEnumerable
+		public IEnumerator GetEnumerator()
+		{
+			return ((IEnumerable)_parms).GetEnumerator();
+		}
+		#endregion
+
+		#region Public Methods
+		public MySqlParameter this[int index]
+		{
+			get { return (MySqlParameter)_parms[index]; }
+			set { _parms[index] = value; }
+		}
+
+		public MySqlParameter this[string name]
+		{
+			get { return (MySqlParameter)_parms[ IndexOf( name ) ]; }
+			set { _parms[ IndexOf( name ) ] = value; }
+		}
+
+		public MySqlParameter Add(MySqlParameter value)
+		{
+			if ( value.ParameterName == null ) throw new ArgumentException("parameter must be named");
+
+			_parms.Add(value);
+			return value;
+		}
+
+		public MySqlParameter Add(string parameterName, MySqlDbType type)
+		{
+			return Add(new MySqlParameter(parameterName, type));
+		}
+
+		public MySqlParameter Add(string parameterName, MySqlDbType dbType, int size)
+		{
+			return Add(new MySqlParameter(parameterName, dbType, size ));
+		}
+
+		public MySqlParameter Add(string parameterName, MySqlDbType dbType, int size, string sourceColumn)
+		{
+			return Add(new MySqlParameter(parameterName, dbType, size, sourceColumn));
+		}
+
+		#endregion
+
+	}
+}

+ 26 - 26
mcs/class/ByteFX.Data/mysqlclient/todo.txt

@@ -1,27 +1,27 @@
-0.65
-====================
-[done]Protocol compression
-[done]Support for GetSchemaTable
-[done]Named pipes for Windows working
-[done]Fix issue with ASP.Net data grid  
-[done]Transactions
-[done]Fixed date/time handling
-MySQLCommandBuilder
- 
-0.7
-=================================
-Support for all CommandBehaviors
-make XSD internal only
-Different character sets
-
-0.8
-================================
-Designer support for MySQLCommandBuilder
-
-0.9
-===============================
-?????
-
-1.0
-====================
+0.65
+====================
+[done]Protocol compression
+[done]Support for GetSchemaTable
+[done]Named pipes for Windows working
+[done]Fix issue with ASP.Net data grid  
+[done]Transactions
+[done]Fixed date/time handling
+MySQLCommandBuilder
+ 
+0.7
+=================================
+Support for all CommandBehaviors
+make XSD internal only
+Different character sets
+
+0.8
+================================
+Designer support for MySQLCommandBuilder
+
+0.9
+===============================
+?????
+
+1.0
+====================
 Oh yeah!

+ 86 - 86
mcs/class/ByteFX.Data/mysqlclient/transcaction.cs

@@ -1,86 +1,86 @@
-// ByteFX.Data data access components for .Net
-// Copyright (C) 2002-2003  ByteFX, Inc.
-//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-using System;
-using System.Data;
-
-namespace ByteFX.Data.MySQLClient
-{
-	public class MySQLTransaction : IDbTransaction
-	{
-		private IsolationLevel	_level;
-		private MySQLConnection	_conn;
-		private bool			_open;
-
-		internal MySQLTransaction() 
-		{
-			_open = true;
-		}
-
-		public IsolationLevel IsolationLevel 
-		{
-			get { return _level; }
-			set { _level = value; }
-		}
-
-		public IDbConnection Connection
-		{
-			get { return _conn;	} 
-			set { _conn = (MySQLConnection)value; }
-		}
-
-		public void Dispose() 
-		{
-		}
-
-		public void Commit()
-		{
-			if (_conn == null || _conn.State != ConnectionState.Open)
-				throw new InvalidOperationException("Connection must be valid and open to commit transaction");
-			if (!_open)
-				throw new InvalidOperationException("Transaction has already been committed or is not pending");
-			Driver d = _conn.Driver;
-			try 
-			{
-				d.SendCommand(DBCmd.QUERY, "COMMIT");
-				_open = false;
-			}
-			catch (MySQLException ex) 
-			{
-				throw ex;
-			}
-		}
-
-		public void Rollback()
-		{
-			if (_conn == null || _conn.State != ConnectionState.Open)
-				throw new InvalidOperationException("Connection must be valid and open to commit transaction");
-			if (!_open)
-				throw new InvalidOperationException("Transaction has already been rolled back or is not pending");
-			Driver d = _conn.Driver;
-			try 
-			{
-				d.SendCommand(DBCmd.QUERY, "ROLLBACK");
-				_open = false;
-			}
-			catch (MySQLException ex) 
-			{
-				throw ex;
-			}
-		}
-	}
-}
+// ByteFX.Data data access components for .Net
+// Copyright (C) 2002-2003  ByteFX, Inc.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+using System;
+using System.Data;
+
+namespace ByteFX.Data.MySqlClient
+{
+	public class MySqlTransaction : IDbTransaction
+	{
+		private IsolationLevel	_level;
+		private MySqlConnection	_conn;
+		private bool			_open;
+
+		internal MySqlTransaction() 
+		{
+			_open = true;
+		}
+
+		public IsolationLevel IsolationLevel 
+		{
+			get { return _level; }
+			set { _level = value; }
+		}
+
+		public IDbConnection Connection
+		{
+			get { return _conn;	} 
+			set { _conn = (MySqlConnection)value; }
+		}
+
+		public void Dispose() 
+		{
+		}
+
+		public void Commit()
+		{
+			if (_conn == null || _conn.State != ConnectionState.Open)
+				throw new InvalidOperationException("Connection must be valid and open to commit transaction");
+			if (!_open)
+				throw new InvalidOperationException("Transaction has already been committed or is not pending");
+			Driver d = _conn.InternalConnection.Driver;
+			try 
+			{
+				d.SendCommand(DBCmd.QUERY, "COMMIT");
+				_open = false;
+			}
+			catch (MySqlException ex) 
+			{
+				throw ex;
+			}
+		}
+
+		public void Rollback()
+		{
+			if (_conn == null || _conn.State != ConnectionState.Open)
+				throw new InvalidOperationException("Connection must be valid and open to commit transaction");
+			if (!_open)
+				throw new InvalidOperationException("Transaction has already been rolled back or is not pending");
+			Driver d = _conn.InternalConnection.Driver;
+			try 
+			{
+				d.SendCommand(DBCmd.QUERY, "ROLLBACK");
+				_open = false;
+			}
+			catch (MySqlException ex) 
+			{
+				throw ex;
+			}
+		}
+	}
+}

+ 41 - 37
mcs/class/ByteFX.Data/readme.txt

@@ -1,37 +1,41 @@
-Managed Drivers for MySQL and PostgreSQL
-======================================
-
-Current Status of MySQL driver
-----------------------------------
-The driver is currently under heavy development.
-The driver is in beta form with most features working reasonably well, but
-is not very well tested.  Use at your own risk!
-
-
-
-The goal for version 0.7 is to use many more test cases and improve the stability
-of the driver greatly.
-
-
-Current status of the PostgreSQL driver
----------------------------------------
-The PostgreSQL driver is just starting and not really usable yet. 
-It can perform simple reads with a limited set of data types.
-Watch the project over the next few weeks to see much 
-improvement.
-
-
-Credit
----------------------------------------
-First of all, many thanks to the MySQL folks for creating such a great database.
-
-Next, I have to give a big thanks and kudos to Mark Matthews for his Java-based MySQL driver.
-As the protocol to MySQL is very poorly documented, his driver proved to be invaluable.
-
-Also, I have to give thanks for Jun Su for starting the SourceForge project and for his wonderful
-contribution of code and ideas.
-
-Thanks also go out to Peter Belbin, Timoth Parez, and Daniel Morgan for their input, testing, and all
-the other things that make open source projects successful!
-
-
+Managed Drivers for MySQL and PostgreSQL
+======================================
+
+Current Status of MySQL driver
+----------------------------------
+The driver is currently under heavy development.
+The driver is in beta form with most features working reasonably well.
+
+** Please note that the binaries distributed in the package are either
+compiled with Mono or .NET 1.1. **
+
+
+Current status of the PostgreSQL driver
+---------------------------------------
+The PostgreSQL driver is just starting and not really usable yet. 
+It can perform simple reads with a limited set of data types.
+Watch the project over the next few weeks to see much 
+improvement.
+
+
+Credit
+---------------------------------------
+First of all, many thanks to the MySQL folks for creating such a great database.
+
+Next, I have to give a big thanks and kudos to Mark Matthews for his Java-based MySQL driver.
+As the protocol to MySQL is very poorly documented, his driver proved to be invaluable.
+
+Also, I have to give thanks for Jun Su for starting the SourceForge project and for his wonderful
+contribution of code and ideas.
+
+Thanks also go out to Peter Belbin, Timoth Parez, and Daniel Morgan for their input, testing, and all
+the other things that make open source projects successful!
+
+I have started putting the names of people who post bugs, patches, suggestions, or anything else of value to the changelog.
+If you have posted and don't see your name, I apologize.  Please let me know who you are and I'll include you.
+The most important thing here is to understand that this is not a one man show.  So many people have provided input
+along the way.
+
+
+
+