Merge recent SqliteClient changes into our fork Index: Sqlite.cs =================================================================== RCS file: /cvs/gnome/beagle/beagled/Mono.Data.SqliteClient/Sqlite.cs,v retrieving revision 1.1 diff -u -B -p -r1.1 Sqlite.cs --- Sqlite.cs 7 Jun 2005 20:50:14 -0000 1.1 +++ Sqlite.cs 22 Oct 2005 11:24:22 -0000 @@ -3,7 +3,10 @@ // // Provides C# bindings to the library sqlite.dll // -// Author(s): Everaldo Canuto +// Everaldo Canuto +// Chris Turchin +// Jeroen Zwartepoorte +// Thomas Zoechling // // Copyright (C) 2004 Everaldo Canuto // @@ -120,7 +123,7 @@ namespace Mono.Data.SqliteClient internal static extern void sqliteFree (IntPtr ptr); [DllImport ("sqlite")] - internal static extern SqliteError sqlite_compile (IntPtr sqlite_handle, string zSql, out IntPtr pzTail, out IntPtr pVm, out IntPtr errstr); + internal static extern SqliteError sqlite_compile (IntPtr sqlite_handle, IntPtr zSql, out IntPtr pzTail, out IntPtr pVm, out IntPtr errstr); [DllImport ("sqlite")] internal static extern SqliteError sqlite_step (IntPtr pVm, out int pN, out IntPtr pazValue, out IntPtr pazColName); @@ -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); @@ -138,7 +141,7 @@ namespace Mono.Data.SqliteClient internal static extern void sqlite3_close (IntPtr sqlite_handle); [DllImport("sqlite3")] - internal static extern string sqlite3_errmsg (IntPtr sqlite_handle); + internal static extern IntPtr sqlite3_errmsg (IntPtr sqlite_handle); [DllImport("sqlite3")] internal static extern int sqlite3_changes (IntPtr handle); @@ -147,33 +150,69 @@ namespace Mono.Data.SqliteClient internal static extern int sqlite3_last_insert_rowid (IntPtr sqlite_handle); [DllImport ("sqlite3")] - internal static extern SqliteError sqlite3_prepare (IntPtr sqlite_handle, string zSql, int zSqllen, out IntPtr pVm, out IntPtr pzTail); + internal static extern SqliteError sqlite3_prepare (IntPtr sqlite_handle, IntPtr zSql, int zSqllen, out IntPtr pVm, out IntPtr pzTail); [DllImport ("sqlite3")] internal static extern SqliteError sqlite3_step (IntPtr pVm); [DllImport ("sqlite3")] - internal static extern SqliteError sqlite3_finalize (IntPtr pVm, out IntPtr pzErrMsg); + internal static extern SqliteError sqlite3_finalize (IntPtr pVm); [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 + } } Index: SqliteCommand.cs =================================================================== RCS file: /cvs/gnome/beagle/beagled/Mono.Data.SqliteClient/SqliteCommand.cs,v retrieving revision 1.1 diff -u -B -p -r1.1 SqliteCommand.cs --- SqliteCommand.cs 7 Jun 2005 20:50:14 -0000 1.1 +++ SqliteCommand.cs 22 Oct 2005 11:24:23 -0000 @@ -4,8 +4,11 @@ // Represents a Transact-SQL statement or stored procedure to execute against // a Sqlite database file. // -// Author(s): Vladimir Vukicevic -// Everaldo Canuto +// Author(s): Vladimir Vukicevic +// Everaldo Canuto +// Chris Turchin +// Jeroen Zwartepoorte +// Thomas Zoechling // // Copyright (C) 2002 Vladimir Vukicevic // @@ -30,15 +33,64 @@ // using System; +using System.Collections; using System.Text; +using Mono.Unix; using System.Runtime.InteropServices; +using System.Text.RegularExpressions; using System.Data; +using System.Diagnostics; +using Group = System.Text.RegularExpressions.Group; namespace Mono.Data.SqliteClient { public class SqliteCommand : IDbCommand { + // FIXME: This won't be added to upstream, but Mono.Unix.UnixMarshal.StringToAlloc is not available in any mono releases yet. + public static IntPtr StringToAlloc (string s) + { + return StringToAlloc (s, Encoding.Default); + } + + public static IntPtr StringToAlloc (string s, Encoding encoding) + { + return StringToAlloc (s, 0, s.Length, encoding); + } + + public static IntPtr StringToAlloc (string s, int index, int count) + { + return StringToAlloc (s, index, count, Encoding.Default); + } + + public static IntPtr StringToAlloc (string s, int index, int count, Encoding encoding) + { + int min_byte_count = encoding.GetMaxByteCount(1); + char[] copy = s.ToCharArray (index, count); + byte[] marshal = new byte [encoding.GetByteCount (copy) + min_byte_count]; + + int bytes_copied = encoding.GetBytes (copy, 0, copy.Length, marshal, 0); + + if (bytes_copied != (marshal.Length-min_byte_count)) + throw new NotSupportedException ("encoding.GetBytes() doesn't equal encoding.GetByteCount()!"); + + IntPtr mem = UnixMarshal.Alloc (marshal.Length); + if (mem == IntPtr.Zero) + throw new OutOfMemoryException (); + + bool copied = false; + try { + Marshal.Copy (marshal, 0, mem, marshal.Length); + copied = true; + } + finally { + if (!copied) + UnixMarshal.Free (mem); + } + + return mem; + } + #region Fields private SqliteConnection parent_conn; @@ -49,7 +101,9 @@ namespace Mono.Data.SqliteClient private CommandType type; private UpdateRowSource upd_row_source; private SqliteParameterCollection sql_params; - + private bool prepared = false; + private ArrayList pStmts; + #endregion #region Constructors and destructors @@ -57,20 +111,17 @@ namespace Mono.Data.SqliteClient public SqliteCommand () { sql = ""; - sql_params = new SqliteParameterCollection (); } - + public SqliteCommand (string sqlText) { sql = sqlText; - sql_params = new SqliteParameterCollection (); } public SqliteCommand (string sqlText, SqliteConnection dbConn) { sql = sqlText; parent_conn = dbConn; - sql_params = new SqliteParameterCollection (); } public SqliteCommand (string sqlText, SqliteConnection dbConn, IDbTransaction trans) @@ -78,7 +129,6 @@ namespace Mono.Data.SqliteClient sql = sqlText; parent_conn = dbConn; transaction = trans; - sql_params = new SqliteParameterCollection (); } public void Dispose () @@ -89,50 +139,68 @@ 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 { - get { return sql_params; } + public SqliteParameterCollection Parameters + { + get + { + if (sql_params == null) sql_params = new SqliteParameterCollection(); + 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 +217,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 +248,155 @@ 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/sqlite-users@sqlite.org/msg01851.html + //Regex r = new Regex(@"(('[^']*?\@[^']*')*[^'@]*?)*(?@\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(@"(('[^']*?\:[^']*')*[^':]*?)*(?:\w+)+([^':]*?('[^']*?\:[^']*'))*",RegexOptions.ExplicitCapture); + MatchEvaluator me = new MatchEvaluator(ReplaceParams); + processedText = r.Replace(sql, me); + return processedText; + } + public void Prepare () { + pStmts = new ArrayList(); + string sqlcmds = sql; + + if (Parameters.Count > 0 && parent_conn.Version == 2) + { + sqlcmds = ProcessParameters(); + } + + SqliteError err = SqliteError.OK; + IntPtr psql = StringToAlloc(sqlcmds); + IntPtr pzTail = psql; + try { + do { // sql may contain multiple sql commands, loop until they're all processed + IntPtr pStmt = IntPtr.Zero; + if (parent_conn.Version == 3) + { + err = Sqlite.sqlite3_prepare (parent_conn.Handle, pzTail, sql.Length, out pStmt, out pzTail); + if (err != SqliteError.OK) { + string msg = Marshal.PtrToStringAnsi (Sqlite.sqlite3_errmsg (parent_conn.Handle)); + throw new SqliteException (err, msg); + } + } + else + { + IntPtr errMsg; + err = Sqlite.sqlite_compile (parent_conn.Handle, pzTail, out pzTail, out pStmt, out errMsg); + + if (err != SqliteError.OK) + { + string msg = "unknown error"; + if (errMsg != IntPtr.Zero) + { + msg = Marshal.PtrToStringAnsi (errMsg); + Sqlite.sqliteFree (errMsg); + } + throw new SqliteException (err, msg); + } + } + + pStmts.Add(pStmt); + + if (parent_conn.Version == 3) + { + int pcount = Sqlite.sqlite3_bind_parameter_count (pStmt); + if (sql_params == null) pcount = 0; + + 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); + } + } + } + } while ((int)pzTail - (int)psql < sql.Length); + } finally { + UnixMarshal.Free(psql); + } + prepared=true; } - IDbDataParameter IDbCommand.CreateParameter () + + IDbDataParameter IDbCommand.CreateParameter() { return CreateParameter (); } @@ -216,45 +451,72 @@ 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); - else - throw new SqliteException (err); - - } 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 (); + } + for (int i = 0; i < pStmts.Count; i++) { + IntPtr pStmt = (IntPtr)pStmts[i]; + + // If want_results, return the results of the last statement + // via the SqliteDataReader, and execute but ignore the results + // of the other statements. + if (i == pStmts.Count-1 && want_results) + { + reader = new SqliteDataReader (this, pStmt, parent_conn.Version); + break; + } + + // Execute but ignore the results of these statements. + + 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); + } + // On error, misuse, or busy, don't bother with the rest of the statements. + if (err != SqliteError.ROW && err != SqliteError.DONE) break; } - } finally { - parent_conn.EndExec (); } + finally + { + if (! want_results) + foreach (IntPtr pStmt in pStmts) { + if (parent_conn.Version == 3) + { + err = Sqlite.sqlite3_finalize (pStmt); + } + else + { + err = Sqlite.sqlite_finalize (pStmt, out errMsg); + } + } - if (err != SqliteError.OK) { - if (errMsg != IntPtr.Zero) { - msg = Marshal.PtrToStringAnsi (errMsg); - if (parent_conn.Version != 3) - Sqlite.sqliteFree (errMsg); - } - throw new SqliteException (err, msg); + parent_conn.EndExec (); + prepared = false; } + if (err != SqliteError.OK && + err != SqliteError.DONE && + err != SqliteError.ROW) + { + if (errMsg != IntPtr.Zero) + { + // TODO: Get the message text + } + throw new SqliteException (err); + } rows_affected = NumChanges (); - return reader; } @@ -265,8 +527,6 @@ namespace Mono.Data.SqliteClient else return Sqlite.sqlite_last_insert_rowid(parent_conn.Handle); } - - #endregion - + #endregion } } Index: SqliteConnection.cs =================================================================== RCS file: /cvs/gnome/beagle/beagled/Mono.Data.SqliteClient/SqliteConnection.cs,v retrieving revision 1.1 diff -u -B -p -r1.1 SqliteConnection.cs --- SqliteConnection.cs 7 Jun 2005 20:50:14 -0000 1.1 +++ SqliteConnection.cs 22 Oct 2005 11:24:24 -0000 @@ -243,7 +243,7 @@ namespace Mono.Data.SqliteClient if (Version == 3) { int err = Sqlite.sqlite3_open(db_file, out sqlite_handle); if (err == (int)SqliteError.ERROR) - throw new ApplicationException (Sqlite.sqlite3_errmsg (sqlite_handle)); + throw new ApplicationException (Marshal.PtrToStringAnsi( Sqlite.sqlite3_errmsg (sqlite_handle))); } else { sqlite_handle = Sqlite.sqlite_open(db_file, db_mode, out errmsg); Index: SqliteDataReader.cs =================================================================== RCS file: /cvs/gnome/beagle/beagled/Mono.Data.SqliteClient/SqliteDataReader.cs,v retrieving revision 1.1 diff -u -B -p -r1.1 SqliteDataReader.cs --- SqliteDataReader.cs 7 Jun 2005 20:50:14 -0000 1.1 +++ SqliteDataReader.cs 22 Oct 2005 11:24:25 -0000 @@ -190,7 +190,7 @@ namespace Mono.Data.SqliteClient if (pVm != IntPtr.Zero) { IntPtr errMsg; if (version == 3) - Sqlite.sqlite3_finalize (pVm, out errMsg); + Sqlite.sqlite3_finalize (pVm); else Sqlite.sqlite_finalize (pVm, out errMsg); pVm = IntPtr.Zero; Index: SqliteParameterCollection.cs =================================================================== RCS file: /cvs/gnome/beagle/beagled/Mono.Data.SqliteClient/SqliteParameterCollection.cs,v retrieving revision 1.1 diff -u -B -p -r1.1 SqliteParameterCollection.cs --- SqliteParameterCollection.cs 7 Jun 2005 20:50:14 -0000 1.1 +++ SqliteParameterCollection.cs 22 Oct 2005 11:24:31 -0000 @@ -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 -// Everaldo Canuto +//Author(s): Vladimir Vukicevic +// Everaldo Canuto +// Chris Turchin +// Jeroen Zwartepoorte +// Thomas Zoechling // // 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 } } - Index: SqliteTransaction.cs =================================================================== RCS file: /cvs/gnome/beagle/beagled/Mono.Data.SqliteClient/SqliteTransaction.cs,v retrieving revision 1.1 diff -u -B -p -r1.1 SqliteTransaction.cs --- SqliteTransaction.cs 7 Jun 2005 20:50:14 -0000 1.1 +++ SqliteTransaction.cs 22 Oct 2005 11:24:31 -0000 @@ -100,7 +100,7 @@ namespace Mono.Data.SqliteClient try { SqliteCommand cmd = _connection.CreateCommand(); - cmd.CommandText = "COMMIT"; + cmd.CommandText = "ROLLBACK"; cmd.ExecuteNonQuery(); _open = false; }