Преглед изворни кода

2005-06-14 Thomas Zoechling <[email protected]>

	* Sqlite.cs:
	- Added sqlite3_bind_* for native Sqlite3 Parameters
	* SqliteCommand.cs
	- Added methods for parameter processing/binding (sqlite3 uses bind / sqlite2 uses regEx to extract parameters)
	- Sqlite uses ':' as delimeter!
	* SqliteParameterCollection.cs
	- Chris Turchin fixed a problem in the Parameter Hashmap
	* SqliteTransaction.cs
	- The CommandText for the Rollback Command was "COMMIT" ! ->changed :)

Patch from 
	Chris Turchin <[email protected]>, Jeroen Zwartepoorte <[email protected]>, Thomas Zoechling <[email protected]>


svn path=/trunk/mcs/; revision=45942
Sureshkumar T пре 20 година
родитељ
комит
584e7c011c

+ 12 - 0
mcs/class/Mono.Data.SqliteClient/Mono.Data.SqliteClient/ChangeLog

@@ -1,3 +1,15 @@
+2005-06-14  Thomas Zoechling <[email protected]>
+
+	* Sqlite.cs:
+	- Added sqlite3_bind_* for native Sqlite3 Parameters
+	* SqliteCommand.cs
+	- Added methods for parameter processing/binding (sqlite3 uses bind / sqlite2 uses regEx to extract parameters)
+	- Sqlite uses ':' as delimeter!
+	* SqliteParameterCollection.cs
+	- Chris Turchin fixed a problem in the Parameter Hashmap
+	* SqliteTransaction.cs
+	- The CommandText for the Rollback Command was "COMMIT" ! ->changed :)
+
 2005-05-20  Sureshkumar T  <[email protected]>
 
 	* SqliteConnection.cs:

+ 42 - 3
mcs/class/Mono.Data.SqliteClient/Mono.Data.SqliteClient/Sqlite.cs

@@ -3,7 +3,10 @@
 //
 // Provides C# bindings to the library sqlite.dll
 //
-// Author(s): Everaldo Canuto  <[email protected]>
+//            	Everaldo Canuto  <[email protected]>
+//			Chris Turchin <[email protected]>
+//			Jeroen Zwartepoorte <[email protected]>
+//			Thomas Zoechling <[email protected]>
 //
 // Copyright (C) 2004  Everaldo Canuto
 //
@@ -129,7 +132,7 @@ namespace Mono.Data.SqliteClient
 		internal static extern SqliteError sqlite_finalize (IntPtr pVm, out IntPtr pzErrMsg);
 
 		[DllImport ("sqlite")]
-                internal static extern SqliteError sqlite_exec (IntPtr handle, string sql, IntPtr callback, IntPtr user_data, out IntPtr errstr_ptr);
+		internal static extern SqliteError sqlite_exec (IntPtr handle, string sql, IntPtr callback, IntPtr user_data, out IntPtr errstr_ptr);
 		
 		[DllImport("sqlite3")]
 		internal static extern int sqlite3_open (string dbname, out IntPtr handle);
@@ -156,24 +159,60 @@ namespace Mono.Data.SqliteClient
 		internal static extern SqliteError sqlite3_finalize (IntPtr pVm, out IntPtr pzErrMsg);
 
 		[DllImport ("sqlite3")]
-                internal static extern SqliteError sqlite3_exec (IntPtr handle, string sql, IntPtr callback, IntPtr user_data, out IntPtr errstr_ptr);
+		internal static extern SqliteError sqlite3_exec (IntPtr handle, string sql, IntPtr callback, IntPtr user_data, out IntPtr errstr_ptr);
 	
 		[DllImport ("sqlite3")]
 		internal static extern IntPtr sqlite3_column_name (IntPtr pVm, int col);
+		
 		[DllImport ("sqlite3")]
 		internal static extern IntPtr sqlite3_column_text (IntPtr pVm, int col);
+		
 		[DllImport ("sqlite3")]
 		internal static extern IntPtr sqlite3_column_blob (IntPtr pVm, int col);
+		
 		[DllImport ("sqlite3")]
 		internal static extern int sqlite3_column_bytes (IntPtr pVm, int col);
+		
 		[DllImport ("sqlite3")]
 		internal static extern int sqlite3_column_count (IntPtr pVm);
+		
 		[DllImport ("sqlite3")]
 		internal static extern int sqlite3_column_type (IntPtr pVm, int col);
+		
 		[DllImport ("sqlite3")]
 		internal static extern Int64 sqlite3_column_int64 (IntPtr pVm, int col);
+		
 		[DllImport ("sqlite3")]
 		internal static extern double sqlite3_column_double (IntPtr pVm, int col);
+		
+ 		[DllImport ("sqlite3")]
+		internal static extern int sqlite3_bind_parameter_count (IntPtr pStmt);
+
+		[DllImport ("sqlite3")]
+		internal static extern String sqlite3_bind_parameter_name (IntPtr pStmt, int n);
+
+		[DllImport ("sqlite3")]
+		internal static extern SqliteError sqlite3_bind_blob (IntPtr pStmt, int n, byte[] blob, int length, IntPtr freetype);
+
+		[DllImport ("sqlite3")]
+		internal static extern SqliteError sqlite3_bind_double (IntPtr pStmt, int n, double value);
+
+		[DllImport ("sqlite3")]
+		internal static extern SqliteError sqlite3_bind_int (IntPtr pStmt, int n, int value);
+
+		[DllImport ("sqlite3")]
+		internal static extern SqliteError sqlite3_bind_int64 (IntPtr pStmt, Int64 n, long value);
+
+		[DllImport ("sqlite3")]
+		internal static extern SqliteError sqlite3_bind_null (IntPtr pStmt, int n);
+
+		[DllImport ("sqlite3")]
+		internal static extern SqliteError sqlite3_bind_text (IntPtr pStmt, int n, string value, int length, IntPtr freetype);
+
+		[DllImport ("sqlite3")]
+		internal static extern SqliteError sqlite3_bind_text16 (IntPtr pStmt, int n, byte[] value, int length, IntPtr freetype);
+		
 		#endregion
+
 	}
 }

+ 240 - 54
mcs/class/Mono.Data.SqliteClient/Mono.Data.SqliteClient/SqliteCommand.cs

@@ -4,8 +4,11 @@
 // Represents a Transact-SQL statement or stored procedure to execute against 
 // a Sqlite database file.
 //
-// Author(s): Vladimir Vukicevic  <[email protected]>
-//            Everaldo Canuto  <[email protected]>
+// Author(s): 	Vladimir Vukicevic  <[email protected]>
+//		Everaldo Canuto  <[email protected]>
+//		Chris Turchin <[email protected]>
+//		Jeroen Zwartepoorte <[email protected]>
+//		Thomas Zoechling <[email protected]>
 //
 // Copyright (C) 2002  Vladimir Vukicevic
 //
@@ -32,13 +35,14 @@
 using System;
 using System.Text;
 using System.Runtime.InteropServices;
+using System.Text.RegularExpressions;
 using System.Data;
+using System.Diagnostics; 
 
 namespace Mono.Data.SqliteClient 
 {
 	public class SqliteCommand : IDbCommand
 	{
-
 		#region Fields
 		
 		private SqliteConnection parent_conn;
@@ -49,7 +53,9 @@ namespace Mono.Data.SqliteClient
 		private CommandType type;
 		private UpdateRowSource upd_row_source;
 		private SqliteParameterCollection sql_params;
-		
+		private bool prepared = false;
+		private IntPtr pStmt;
+
 		#endregion
 
 		#region Constructors and destructors
@@ -59,7 +65,7 @@ namespace Mono.Data.SqliteClient
 			sql = "";
 			sql_params = new SqliteParameterCollection ();
 		}
-		
+				
 		public SqliteCommand (string sqlText)
 		{
 			sql = sqlText;
@@ -89,50 +95,64 @@ namespace Mono.Data.SqliteClient
 
 		#region Properties
 		
-		public string CommandText {
+		public string CommandText 
+		{
 			get { return sql; }
 			set { sql = value; }
 		}
 		
-		public int CommandTimeout {
+		public int CommandTimeout
+		{
 			get { return timeout; }
 			set { timeout = value; }
 		}
 		
-		public CommandType CommandType {
+		public CommandType CommandType 
+		{
 			get { return type; }
 			set { type = value; }
 		}
 		
-		IDbConnection IDbCommand.Connection {
-			get { return parent_conn; }
-			set {
-					if (!(value is SqliteConnection)) {
-						throw new InvalidOperationException ("Can't set Connection to something other than a SqliteConnection");
-					}
-					parent_conn = (SqliteConnection) value;
+		IDbConnection IDbCommand.Connection 
+		{
+			get 
+			{ 
+				return parent_conn; 
+			}
+			set 
+			{
+				if (!(value is SqliteConnection)) 
+				{
+					throw new InvalidOperationException ("Can't set Connection to something other than a SqliteConnection");
+				}
+				parent_conn = (SqliteConnection) value;
 			}
 		}
 		
-		public SqliteConnection Connection {
+		public SqliteConnection Connection
+		{
 			get { return parent_conn; }
 			set { parent_conn = value; }
 		}
 		
-		IDataParameterCollection IDbCommand.Parameters {
+		IDataParameterCollection IDbCommand.Parameters 
+		{
 			get { return Parameters; }
 		}
 		
-		public SqliteParameterCollection Parameters {
+		public SqliteParameterCollection Parameters 
+		{
 			get { return sql_params; }
 		}
 		
-		public IDbTransaction Transaction {
+		public IDbTransaction Transaction 
+		{
 			get { return transaction; }
 			set { transaction = value; }
 		}
 		
-		public UpdateRowSource UpdatedRowSource {
+		public UpdateRowSource UpdatedRowSource 
+		{
 			get { return upd_row_source; }
 			set { upd_row_source = value; }
 		}
@@ -149,6 +169,29 @@ namespace Mono.Data.SqliteClient
 				return Sqlite.sqlite_changes(parent_conn.Handle);
 		}
 		
+		private string ReplaceParams(Match m)
+		{
+			string input = m.Value;                                                                                                                
+			if (m.Groups["param"].Success)
+			{
+				Group g = m.Groups["param"];
+				string find = g.Value;
+				//FIXME: sqlite works internally only with strings, so this assumtion is mostly legit, but what about date formatting, etc?
+				//Need to fix SqlLiteDataReader first to acurately describe the tables
+				SqliteParameter sqlp = Parameters[find];
+				string replace = Convert.ToString(sqlp.Value);
+				if(sqlp.DbType == DbType.String)
+				{
+					replace =  "\"" + replace + "\"";
+				}
+				
+				input = Regex.Replace(input,find,replace);
+				return input;
+			}
+			else
+			return m.Value;
+		}
+		
 		#endregion
 
 		#region Public Methods
@@ -157,11 +200,136 @@ namespace Mono.Data.SqliteClient
 		{
 		}
 		
+		public string ProcessParameters()
+		{
+			string processedText = sql;
+
+			//Regex looks odd perhaps, but it works - same impl. as in the firebird db provider
+			//the named parameters are using the ADO.NET standard @-prefix but sqlite is considering ":" as a prefix for v.3...
+			//ref: http://www.mail-archive.com/[email protected]/msg01851.html
+			//Regex r = new Regex(@"(('[^']*?\@[^']*')*[^'@]*?)*(?<param>@\w+)+([^'@]*?('[^']*?\@[^']*'))*",RegexOptions.ExplicitCapture);
+			
+			//The above statement is true for the commented regEx, but I changed it to use the :-prefix, because now (12.05.2005 sqlite3) 
+			//sqlite is using : as Standard Parameterprefix
+			
+			Regex r = new Regex(@"(('[^']*?\:[^']*')*[^':]*?)*(?<param>:\w+)+([^':]*?('[^']*?\:[^']*'))*",RegexOptions.ExplicitCapture);
+			MatchEvaluator me = new MatchEvaluator(ReplaceParams);
+			processedText = r.Replace(sql, me);
+			return processedText;
+		}
+		
 		public void Prepare ()
 		{
+			SqliteError err = SqliteError.OK;
+			IntPtr pzTail = IntPtr.Zero;
+			pStmt = IntPtr.Zero;	
+			if (parent_conn.Version == 3)  
+			{
+				err = Sqlite.sqlite3_prepare (parent_conn.Handle, sql, sql.Length, out pStmt, out pzTail);
+				if (err != SqliteError.OK)
+					throw new ApplicationException ("Sqlite error in prepare " + err);
+				int pcount = Sqlite.sqlite3_bind_parameter_count (pStmt);
+
+				for (int i = 1; i <= pcount; i++) 
+				{
+					String name = Sqlite.sqlite3_bind_parameter_name (pStmt, i);
+					SqliteParameter param = sql_params[name];
+					Type ptype = param.Value.GetType ();
+					
+					if (ptype.Equals (typeof (String))) 
+					{
+						String s = (String)param.Value;
+						err = Sqlite.sqlite3_bind_text (pStmt, i, s, s.Length, (IntPtr)(-1));
+					} 
+					else if (ptype.Equals (typeof (DBNull))) 
+					{
+						err = Sqlite.sqlite3_bind_null (pStmt, i);
+					}
+					else if (ptype.Equals (typeof (Boolean))) 
+					{
+						bool b = (bool)param.Value;
+						err = Sqlite.sqlite3_bind_int (pStmt, i, b ? 1 : 0);
+					} else if (ptype.Equals (typeof (Byte))) 
+					{
+						err = Sqlite.sqlite3_bind_int (pStmt, i, (Byte)param.Value);
+					}
+					else if (ptype.Equals (typeof (Char))) 
+					{
+						err = Sqlite.sqlite3_bind_int (pStmt, i, (Char)param.Value);
+					} 
+					else if (ptype.Equals (typeof (Int16))) 
+					{
+						err = Sqlite.sqlite3_bind_int (pStmt, i, (Int16)param.Value);
+					} 
+					else if (ptype.Equals (typeof (Int32))) 
+					{
+						err = Sqlite.sqlite3_bind_int (pStmt, i, (Int32)param.Value);
+					}
+					else if (ptype.Equals (typeof (SByte))) 
+					{
+						err = Sqlite.sqlite3_bind_int (pStmt, i, (SByte)param.Value);
+					} 
+					else if (ptype.Equals (typeof (UInt16))) 
+					{
+						err = Sqlite.sqlite3_bind_int (pStmt, i, (UInt16)param.Value);
+					}
+					else if (ptype.Equals (typeof (DateTime))) 
+					{
+						DateTime dt = (DateTime)param.Value;
+						err = Sqlite.sqlite3_bind_int64 (pStmt, i, dt.ToFileTime ());
+					} 
+					else if (ptype.Equals (typeof (Double))) 
+					{
+						err = Sqlite.sqlite3_bind_double (pStmt, i, (Double)param.Value);
+					}
+					else if (ptype.Equals (typeof (Single))) 
+					{
+						err = Sqlite.sqlite3_bind_double (pStmt, i, (Single)param.Value);
+					} 
+					else if (ptype.Equals (typeof (UInt32))) 
+					{
+						err = Sqlite.sqlite3_bind_int64 (pStmt, i, (UInt32)param.Value);
+					}
+					else if (ptype.Equals (typeof (Int64))) 
+					{
+						err = Sqlite.sqlite3_bind_int64 (pStmt, i, (Int64)param.Value);
+					} 
+					else 
+					{
+						throw new ApplicationException("Unkown Parameter Type");
+					}
+					if (err != SqliteError.OK) 
+					{
+						throw new ApplicationException ("Sqlite error in bind " + err);
+					}
+				}
+			}
+			else 
+			{
+				IntPtr errMsg = IntPtr.Zero;
+				string msg = "";
+				string sqlData = sql;
+				if (Parameters.Count > 0)
+				{
+					sqlData = ProcessParameters();
+				}
+				err = Sqlite.sqlite_compile (parent_conn.Handle, sqlData, out pzTail, out pStmt, out errMsg);
+				
+				if (err != SqliteError.OK) 
+				{
+					if (errMsg != IntPtr.Zero) 
+					{
+						msg = Marshal.PtrToStringAnsi (errMsg);
+						Sqlite.sqliteFree (errMsg);
+					}
+					throw new ApplicationException ("Sqlite error " + msg);
+				}
+			}
+			prepared=true;
 		}
 		
-		IDbDataParameter IDbCommand.CreateParameter ()
+		
+		IDbDataParameter IDbCommand.CreateParameter()
 		{
 			return CreateParameter ();
 		}
@@ -215,46 +383,66 @@ namespace Mono.Data.SqliteClient
 			SqliteDataReader reader = null;
 			SqliteError err = SqliteError.OK;
 			IntPtr errMsg = IntPtr.Zero; 
-			
 			parent_conn.StartExec ();
-			
+		  
 			string msg = "";
-
-			try {
-				if (want_results) {
-					IntPtr pVm = IntPtr.Zero;
-					IntPtr pzTail = IntPtr.Zero;
-					if (parent_conn.Version == 3)
-						err = Sqlite.sqlite3_prepare (parent_conn.Handle, sql, sql.Length, out pVm, out pVm);
-					else
-						err = Sqlite.sqlite_compile (parent_conn.Handle, sql, out pzTail, out pVm, out errMsg);
-					if (err == SqliteError.OK)
-						reader = new SqliteDataReader (this, pVm, parent_conn.Version);
-					if (parent_conn.Version == 3)
-						err = Sqlite.sqlite3_finalize (pVm, out errMsg);
-					else
-						err = Sqlite.sqlite_finalize (pVm, out errMsg);
-				} else {
-					if (parent_conn.Version == 3)
-						err = Sqlite.sqlite3_exec (parent_conn.Handle, sql, IntPtr.Zero, IntPtr.Zero, out errMsg);
-					else
-						err = Sqlite.sqlite_exec (parent_conn.Handle, sql, IntPtr.Zero, IntPtr.Zero, out errMsg);
+			try 
+			{
+				if (!prepared)
+				{
+					Prepare ();
+				}
+				if (want_results) 
+				{
+					reader = new SqliteDataReader (this, pStmt, parent_conn.Version);
+				} 
+				else 
+				{
+					if (parent_conn.Version == 3) 
+					{
+						err = Sqlite.sqlite3_step (pStmt);
+					} 
+					else 
+					{
+						int cols;
+						IntPtr pazValue = IntPtr.Zero;
+						IntPtr pazColName = IntPtr.Zero;
+						err = Sqlite.sqlite_step (pStmt, out cols, out pazValue, out pazColName);
+					}
+				}
+			}
+			finally 
+			{	
+				if (parent_conn.Version == 3) 
+				{}
+				else
+				{
+					err = Sqlite.sqlite_finalize (pStmt, out errMsg);
 				}
-			} finally {			
 				parent_conn.EndExec ();
+				prepared = false;
 			}
-
-			if (err != SqliteError.OK) {
-				if (errMsg != IntPtr.Zero) {
-					msg = Marshal.PtrToStringAnsi (errMsg);
-					if (parent_conn.Version != 3)
+			
+			if (err != SqliteError.OK &&
+			    err != SqliteError.DONE &&
+			    err != SqliteError.ROW) 
+			{
+ 				if (errMsg != IntPtr.Zero) 
+				{
+ 					//msg = Marshal.PtrToStringAnsi (errMsg);
+					if (parent_conn.Version == 3)
+					{
+						err = Sqlite.sqlite3_finalize (pStmt, out errMsg);
+					}
+					else
+					{
+						err = Sqlite.sqlite_finalize (pStmt, out errMsg);
 						Sqlite.sqliteFree (errMsg);
+					}
 				}
 				throw new ApplicationException ("Sqlite error " + msg);
 			}
-			
 			rows_affected = NumChanges ();
-			
 			return reader;
 		}
 		
@@ -265,8 +453,6 @@ namespace Mono.Data.SqliteClient
 			else
 				return Sqlite.sqlite_last_insert_rowid(parent_conn.Handle);
 		}
-		
-		#endregion
-
+	#endregion
 	}
 }

+ 118 - 51
mcs/class/Mono.Data.SqliteClient/Mono.Data.SqliteClient/SqliteParameterCollection.cs

@@ -4,8 +4,11 @@
 // Represents a collection of parameters relevant to a SqliteCommand as well as 
 // their respective mappings to columns in a DataSet.
 //
-// Author(s): Vladimir Vukicevic  <[email protected]>
-//            Everaldo Canuto  <[email protected]>
+//Author(s):		Vladimir Vukicevic  <[email protected]>
+//			Everaldo Canuto  <[email protected]>
+//			Chris Turchin <[email protected]>
+//			Jeroen Zwartepoorte <[email protected]>
+//			Thomas Zoechling <[email protected]>
 //
 // Copyright (C) 2002  Vladimir Vukicevic
 //
@@ -46,85 +49,148 @@ namespace Mono.Data.SqliteClient
 		#endregion
 
 		#region Private Methods
-		
+
 		private void CheckSqliteParam (object value)
 		{
 			if (!(value is SqliteParameter))
-				throw new InvalidCastException("Can only use SqliteParameter objects");
-		}
+				throw new InvalidCastException ("Can only use SqliteParameter objects");
+			SqliteParameter sqlp = value as SqliteParameter;
+			if (sqlp.ParameterName == null || sqlp.ParameterName.Length == 0)
+				sqlp.ParameterName = this.GenerateParameterName();
+                 }
 
 		private void RecreateNamedHash ()
 		{
-			for (int i = 0; i < numeric_param_list.Count; i++) {
+			for (int i = 0; i < numeric_param_list.Count; i++) 
+			{
 				named_param_hash[((SqliteParameter) numeric_param_list[i]).ParameterName] = i;
 			}
 		}
-		
+
+		//FIXME: if the user is calling Insert at various locations with unnamed parameters, this is not going to work....
+		private string GenerateParameterName()
+		{
+			int		index	= this.Count + 1;
+			string	name	= String.Empty;
+
+			while (index > 0)
+			{
+				name = ":" + index.ToString();
+					if (this.IndexOf(name) == -1)
+					index = -1;
+				else
+				index++;
+			}
+			return name;
+		}
+
 		#endregion
 
 		#region Properties
 		
 		object IList.this[int index] {
-			get {
+			get 
+			{
 				return this[index];
 			}
-			set {
+			set 
+			{
 				CheckSqliteParam (value);
 				this[index] = (SqliteParameter) value;
 			}
 		}
 		
 		object IDataParameterCollection.this[string parameterName] {
-			get {
+			get 
+			{
 				return this[parameterName];
 			}
-			set {
+			set 
+			{
 				CheckSqliteParam (value);
 				this[parameterName] = (SqliteParameter) value;
 			}
 		}
 		
-		public SqliteParameter this[string parameterName] {
-			get {
-				return this[(int) named_param_hash[parameterName]];
+		public SqliteParameter this[string parameterName] 
+		{
+			get 
+			{
+				if (this.Contains(parameterName))
+					return this[(int) named_param_hash[parameterName]];
+				else
+					throw new IndexOutOfRangeException("The specified name does not exist: " + parameterName);
 			}
-			set {
-				if (this.Contains (parameterName))
+			set
+			{
+				if (this.Contains(parameterName))
 					numeric_param_list[(int) named_param_hash[parameterName]] = value;
-				else          // uhm, do we add it if it doesn't exist? what does ms do?
-					Add (value);
+				else
+					throw new IndexOutOfRangeException("The specified name does not exist: " + parameterName);
 			}
 		}
-		
-		public SqliteParameter this[int parameterIndex] {
-			get {
-				return (SqliteParameter) numeric_param_list[parameterIndex];
+
+		public SqliteParameter this[int parameterIndex]
+		{
+			get
+			{
+				if (this.Count >= parameterIndex+1)
+					return (SqliteParameter) numeric_param_list[parameterIndex];
+				else          
+					throw new IndexOutOfRangeException("The specified parameter index does not exist: " + parameterIndex.ToString());
 			}
-			set {
-				numeric_param_list[parameterIndex] = value;
+			set
+			{
+				if (this.Count >= parameterIndex+1)
+					numeric_param_list[parameterIndex] = value;
+				else          
+					throw new IndexOutOfRangeException("The specified parameter index does not exist: " + parameterIndex.ToString());
 			}
 		}
-		
-		public int Count {
-			get { return numeric_param_list.Count; }
+
+
+		public int Count 
+		{
+			get
+			{
+				return this.numeric_param_list.Count;
+			}
 		}
-		
-		public bool IsFixedSize {
-			get { return false; }
+
+		bool IList.IsFixedSize
+		{
+			get
+			{
+				return this.numeric_param_list.IsFixedSize;
+			}
 		}
-		
-		public bool IsReadOnly {
-			get { return false; }
+
+		bool IList.IsReadOnly
+		{
+			get
+			{
+				return this.numeric_param_list.IsReadOnly;
+			}
 		}
-		
-		public bool IsSynchronized {
-			get { return false; }
+
+
+		bool ICollection.IsSynchronized 
+		{
+			get
+			{
+				return this.numeric_param_list.IsSynchronized;
+			}
 		}
 		
-		public object SyncRoot {
-			get { return null; }
+
+		object ICollection.SyncRoot 
+		{
+			get
+			{
+				return this.numeric_param_list.SyncRoot;
+			}
 		}
-		
+
 		#endregion
 
 		#region Public Methods
@@ -132,15 +198,13 @@ namespace Mono.Data.SqliteClient
 		public int Add (object value)
 		{
 			CheckSqliteParam (value);
-			SqliteParameter sqlp = (SqliteParameter) value;
+			SqliteParameter sqlp = value as SqliteParameter;
 			if (named_param_hash.Contains (sqlp.ParameterName))
-				throw new DuplicateNameException ("Parameter collection already contains given value.");
-			
-			named_param_hash[value] = numeric_param_list.Add (value);
-			
-			return (int) named_param_hash[value];
+				throw new DuplicateNameException ("Parameter collection already contains the a SqliteParameter with the given ParameterName.");
+			named_param_hash[sqlp.ParameterName] = numeric_param_list.Add(value);
+				return (int) named_param_hash[sqlp.ParameterName];
 		}
-		
+
 		public SqliteParameter Add (SqliteParameter param)
 		{
 			Add ((object)param);
@@ -165,7 +229,7 @@ namespace Mono.Data.SqliteClient
 		
 		public void CopyTo (Array array, int index)
 		{
-			throw new NotImplementedException ();
+			this.numeric_param_list.CopyTo(array, index);
 		}
 		
 		bool IList.Contains (object value)
@@ -185,7 +249,7 @@ namespace Mono.Data.SqliteClient
 		
 		public IEnumerator GetEnumerator ()
 		{
-			throw new NotImplementedException ();
+			return this.numeric_param_list.GetEnumerator();
 		}
 		
 		int IList.IndexOf (object param)
@@ -195,7 +259,10 @@ namespace Mono.Data.SqliteClient
 		
 		public int IndexOf (string parameterName)
 		{
-			return (int) named_param_hash[parameterName];
+			if (named_param_hash.Contains(parameterName))
+				return (int) named_param_hash[parameterName];
+			else
+				return -1;
 		}
 		
 		public int IndexOf (SqliteParameter param)
@@ -206,7 +273,8 @@ namespace Mono.Data.SqliteClient
 		public void Insert (int index, object value)
 		{
 			CheckSqliteParam (value);
-			if (numeric_param_list.Count == index) {
+			if (numeric_param_list.Count == index) 
+			{
 				Add (value);
 				return;
 			}
@@ -245,4 +313,3 @@ namespace Mono.Data.SqliteClient
 		#endregion
 	}
 }
-                

+ 1 - 1
mcs/class/Mono.Data.SqliteClient/Mono.Data.SqliteClient/SqliteTransaction.cs

@@ -100,7 +100,7 @@ namespace Mono.Data.SqliteClient
 			try 
 			{
 				SqliteCommand cmd = _connection.CreateCommand();
-				cmd.CommandText = "COMMIT";
+				cmd.CommandText = "ROLLBACK";
 				cmd.ExecuteNonQuery();
 				_open = false;
 			}