Index: System.Data.SQLite/SQLite3.cs ================================================================== --- System.Data.SQLite/SQLite3.cs +++ System.Data.SQLite/SQLite3.cs @@ -190,11 +190,11 @@ internal override bool AutoCommit { get { - return IsAutocommit(_sql); + return IsAutocommit(_sql, _sql); } } internal override long LastInsertRowId { @@ -274,11 +274,16 @@ Trace.WriteLine(String.Format("Open: {0}", db)); #endif if (n > 0) throw new SQLiteException(n, null); - _sql = db; + _sql = new SQLiteConnectionHandle(db); + + lock (_sql) + { + // do nothing. + } } // Bind functions to this connection. If any previous functions of the same name // were already bound, then the new bindings replace the old. _functionsArray = SQLiteFunction.BindFunctions(this, connectionFlags); SetTimeout(0); @@ -531,11 +536,11 @@ if (n > 0) throw new SQLiteException(n, GetLastError()); strRemain = UTF8ToString(ptr, len); - if (stmt != IntPtr.Zero) cmd = new SQLiteStatement(this, flags, stmt, strSql.Substring(0, strSql.Length - strRemain.Length), previous); + if (stmt != IntPtr.Zero) cmd = new SQLiteStatement(this, flags, new SQLiteStatementHandle(_sql, stmt), strSql.Substring(0, strSql.Length - strRemain.Length), previous); return cmd; } finally { @@ -1473,11 +1478,12 @@ if (backup == IntPtr.Zero) throw new SQLiteException(ResultCode(), GetLastError()); return new SQLiteBackup( - this, backup, destHandle, zDestName, sourceHandle, zSourceName); + this, new SQLiteBackupHandle(destHandle, backup), + destHandle, zDestName, sourceHandle, zSourceName); } /// /// Copies up to N pages from the source database to the destination /// database associated with the specified backup object. Index: System.Data.SQLite/SQLite3_UTF16.cs ================================================================== --- System.Data.SQLite/SQLite3_UTF16.cs +++ System.Data.SQLite/SQLite3_UTF16.cs @@ -119,13 +119,18 @@ #if DEBUG && !NET_COMPACT_20 Trace.WriteLine(String.Format("Open: {0}", db)); #endif - if (n > 0) throw new SQLiteException(n, null); - - _sql = db; + if (n > 0) throw new SQLiteException(n, null); + + _sql = new SQLiteConnectionHandle(db); + + lock (_sql) + { + // do nothing. + } } _functionsArray = SQLiteFunction.BindFunctions(this, connectionFlags); SetTimeout(0); } Index: System.Data.SQLite/SQLiteBase.cs ================================================================== --- System.Data.SQLite/SQLiteBase.cs +++ System.Data.SQLite/SQLiteBase.cs @@ -345,11 +345,14 @@ // Therefore these functions have to be static, and have to be low-level. internal static string GetLastError(SQLiteConnectionHandle hdl, IntPtr db) { if ((hdl == null) || (db == IntPtr.Zero)) - return "invalid connection or database handle"; + return "null connection or database handle"; + + if (hdl.IsClosed || hdl.IsInvalid) + return "closed or invalid connection handle"; lock (hdl) { #if !SQLITE_STANDARD int len; @@ -358,26 +361,34 @@ return UTF8ToString(UnsafeNativeMethods.sqlite3_errmsg(db), -1); #endif } } - internal static void FinishBackup(IntPtr backup) - { - if (backup == IntPtr.Zero) return; - int n = UnsafeNativeMethods.sqlite3_backup_finish(backup); - if (n > 0) throw new SQLiteException(n, null); - } - - internal static void FinalizeStatement(IntPtr stmt) - { - if (stmt == IntPtr.Zero) return; -#if !SQLITE_STANDARD - int n = UnsafeNativeMethods.sqlite3_finalize_interop(stmt); -#else - int n = UnsafeNativeMethods.sqlite3_finalize(stmt); -#endif - if (n > 0) throw new SQLiteException(n, null); + internal static void FinishBackup(SQLiteConnectionHandle hdl, IntPtr backup) + { + if ((hdl == null) || (backup == IntPtr.Zero)) return; + if (hdl.IsClosed || hdl.IsInvalid) return; + lock (hdl) + { + int n = UnsafeNativeMethods.sqlite3_backup_finish(backup); + if (n > 0) throw new SQLiteException(n, null); + } + } + + internal static void FinalizeStatement(SQLiteConnectionHandle hdl, IntPtr stmt) + { + if ((hdl == null) || (stmt == IntPtr.Zero)) return; + if (hdl.IsClosed || hdl.IsInvalid) return; + lock (hdl) + { +#if !SQLITE_STANDARD + int n = UnsafeNativeMethods.sqlite3_finalize_interop(stmt); +#else + int n = UnsafeNativeMethods.sqlite3_finalize(stmt); +#endif + if (n > 0) throw new SQLiteException(n, null); + } } internal static void CloseConnection(SQLiteConnectionHandle hdl, IntPtr db) { if ((hdl == null) || (db == IntPtr.Zero)) return; @@ -394,10 +405,11 @@ } internal static void ResetConnection(SQLiteConnectionHandle hdl, IntPtr db) { if ((hdl == null) || (db == IntPtr.Zero)) return; + if (hdl.IsClosed || hdl.IsInvalid) return; lock (hdl) { IntPtr stmt = IntPtr.Zero; int n; do @@ -411,24 +423,27 @@ n = UnsafeNativeMethods.sqlite3_reset(stmt); #endif } } while (stmt != IntPtr.Zero); - if (IsAutocommit(db) == false) // a transaction is pending on the connection + if (IsAutocommit(hdl, db) == false) // a transaction is pending on the connection { n = UnsafeNativeMethods.sqlite3_exec(db, ToUTF8("ROLLBACK"), IntPtr.Zero, IntPtr.Zero, out stmt); if (n > 0) throw new SQLiteException(n, GetLastError(hdl, db)); } } } - internal static bool IsAutocommit(IntPtr db) + internal static bool IsAutocommit(SQLiteConnectionHandle hdl, IntPtr db) { - if (db == IntPtr.Zero) return false; - return (UnsafeNativeMethods.sqlite3_get_autocommit(db) == 1); + if ((hdl == null) || (db == IntPtr.Zero)) return false; + if (hdl.IsClosed || hdl.IsInvalid) return false; + lock (hdl) + { + return (UnsafeNativeMethods.sqlite3_get_autocommit(db) == 1); + } } - } internal interface ISQLiteSchemaExtensions { void BuildTempSchema(SQLiteConnection cnn); Index: System.Data.SQLite/UnsafeNativeMethods.cs ================================================================== --- System.Data.SQLite/UnsafeNativeMethods.cs +++ System.Data.SQLite/UnsafeNativeMethods.cs @@ -1353,37 +1353,30 @@ public abstract bool IsInvalid { get; } - } - #endif // Handles the unmanaged database pointer, and provides finalization support for it. - internal class SQLiteConnectionHandle : CriticalHandle + internal class SQLiteConnectionHandle : SafeHandle { public static implicit operator IntPtr(SQLiteConnectionHandle db) { return (db != null) ? db.handle : IntPtr.Zero; } - public static implicit operator SQLiteConnectionHandle(IntPtr db) + private SQLiteConnectionHandle() + : base(IntPtr.Zero, true) { - return new SQLiteConnectionHandle(db); } - private SQLiteConnectionHandle(IntPtr db) + internal SQLiteConnectionHandle(IntPtr db) : this() { SetHandle(db); - } - - internal SQLiteConnectionHandle() - : base(IntPtr.Zero) - { } protected override bool ReleaseHandle() { try @@ -1460,29 +1453,36 @@ } // Provides finalization support for unmanaged SQLite statements. internal class SQLiteStatementHandle : CriticalHandle { + internal SQLiteConnectionHandle cnn; + private bool releaseNeeded; + public static implicit operator IntPtr(SQLiteStatementHandle stmt) { return (stmt != null) ? stmt.handle : IntPtr.Zero; } - public static implicit operator SQLiteStatementHandle(IntPtr stmt) + private SQLiteStatementHandle() + : base(IntPtr.Zero) { - return new SQLiteStatementHandle(stmt); } private SQLiteStatementHandle(IntPtr stmt) : this() { SetHandle(stmt); } - internal SQLiteStatementHandle() - : base(IntPtr.Zero) + internal SQLiteStatementHandle(SQLiteConnectionHandle cnn, IntPtr stmt) + : this(stmt) { + if (cnn != null) + cnn.DangerousAddRef(ref releaseNeeded); + + this.cnn = cnn; } protected override bool ReleaseHandle() { try @@ -1490,11 +1490,14 @@ #if !PLATFORM_COMPACTFRAMEWORK IntPtr localHandle = Interlocked.Exchange( ref handle, IntPtr.Zero); if (localHandle != IntPtr.Zero) - SQLiteBase.FinalizeStatement(localHandle); + SQLiteBase.FinalizeStatement(cnn, localHandle); + + if ((cnn != null) && releaseNeeded) + cnn.DangerousRelease(); #if DEBUG && !NET_COMPACT_20 try { Trace.WriteLine(String.Format( @@ -1505,11 +1508,11 @@ } #endif #else if (handle != IntPtr.Zero) { - SQLiteBase.FinalizeStatement(handle); + SQLiteBase.FinalizeStatement(cnn, handle); SetHandle(IntPtr.Zero); } #endif #if DEBUG @@ -1559,29 +1562,36 @@ } // Provides finalization support for unmanaged SQLite backup objects. internal class SQLiteBackupHandle : CriticalHandle { + internal SQLiteConnectionHandle cnn; + private bool releaseNeeded; + public static implicit operator IntPtr(SQLiteBackupHandle backup) { return (backup != null) ? backup.handle : IntPtr.Zero; } - public static implicit operator SQLiteBackupHandle(IntPtr backup) + private SQLiteBackupHandle() + : base(IntPtr.Zero) { - return new SQLiteBackupHandle(backup); } private SQLiteBackupHandle(IntPtr backup) : this() { SetHandle(backup); } - internal SQLiteBackupHandle() - : base(IntPtr.Zero) + internal SQLiteBackupHandle(SQLiteConnectionHandle cnn, IntPtr backup) + : this(backup) { + if (cnn != null) + cnn.DangerousAddRef(ref releaseNeeded); + + this.cnn = cnn; } protected override bool ReleaseHandle() { try @@ -1589,11 +1599,14 @@ #if !PLATFORM_COMPACTFRAMEWORK IntPtr localHandle = Interlocked.Exchange( ref handle, IntPtr.Zero); if (localHandle != IntPtr.Zero) - SQLiteBase.FinishBackup(localHandle); + SQLiteBase.FinishBackup(cnn, localHandle); + + if ((cnn != null) && releaseNeeded) + cnn.DangerousRelease(); #if DEBUG && !NET_COMPACT_20 try { Trace.WriteLine(String.Format( @@ -1604,11 +1617,11 @@ } #endif #else if (handle != IntPtr.Zero) { - SQLiteBase.FinishBackup(handle); + SQLiteBase.FinishBackup(cnn, handle); SetHandle(IntPtr.Zero); } #endif #if DEBUG