/////////////////////////////////////////////////////////////////////////////////////////////// // It isn't necessary to cleanup any functions we've registered. If the connection // goes to the pool and is resurrected later, re-registered functions will overwrite the // previous functions. The SQLiteFunctionCookieHandle will take care of freeing unmanaged // resources belonging to the previously-registered functions. internal override void Close(bool canThrow) { if (_sql != null) { if (!_sql.OwnHandle) { _sql = null; return; } if (_usePool) { if (SQLiteBase.ResetConnection(_sql, _sql, canThrow)) { #if INTEROP_VIRTUAL_TABLE DisposeModules(); #endif SQLiteConnectionPool.Add(_fileName, _sql, _poolVersion); #if !NET_COMPACT_20 && TRACE_CONNECTION Trace.WriteLine(String.Format("Close (Pool) Success: {0}", _sql)); #endif } #if !NET_COMPACT_20 && TRACE_CONNECTION else { Trace.WriteLine(String.Format("Close (Pool) Failure: {0}", _sql)); } #endif } else { _sql.Dispose(); } _sql = null; } }
internal override void Open(string strFilename, SQLiteConnectionFlags connectionFlags, SQLiteOpenFlagsEnum openFlags, int maxPoolSize, bool usePool) { // // NOTE: If the database connection is currently open, attempt to // close it now. This must be done because the file name or // other parameters that may impact the underlying database // connection may have changed. // if (_sql != null) Close(true); // // NOTE: If the connection was not closed successfully, throw an // exception now. // if (_sql != null) throw new SQLiteException("connection handle is still active"); _usePool = usePool; _fileName = strFilename; if (usePool) { _sql = SQLiteConnectionPool.Remove(strFilename, maxPoolSize, out _poolVersion); #if !NET_COMPACT_20 && TRACE_CONNECTION Trace.WriteLine(String.Format("Open16 (Pool): {0}", (_sql != null) ? _sql.ToString() : "<null>")); #endif } if (_sql == null) { try { // do nothing. } finally /* NOTE: Thread.Abort() protection. */ { IntPtr db; SQLiteErrorCode n; #if !SQLITE_STANDARD if ((connectionFlags & SQLiteConnectionFlags.NoExtensionFunctions) != SQLiteConnectionFlags.NoExtensionFunctions) { n = UnsafeNativeMethods.sqlite3_open16_interop(ToUTF8(strFilename), openFlags, out db); } else #endif { // // NOTE: This flag check is designed to enforce the constraint that opening // a database file that does not already exist requires specifying the // "Create" flag, even when a native API is used that does not accept // a flags parameter. // if (((openFlags & SQLiteOpenFlagsEnum.Create) != SQLiteOpenFlagsEnum.Create) && !File.Exists(strFilename)) throw new SQLiteException(SQLiteErrorCode.CantOpen, strFilename); n = UnsafeNativeMethods.sqlite3_open16(strFilename, out db); } #if !NET_COMPACT_20 && TRACE_CONNECTION Trace.WriteLine(String.Format("Open16: {0}", db)); #endif if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, null); _sql = new SQLiteConnectionHandle(db, true); } lock (_sql) { /* HACK: Force the SyncBlock to be "created" now. */ } SQLiteConnection.OnChanged(null, new ConnectionEventArgs( SQLiteConnectionEventType.NewCriticalHandle, null, null, null, null, _sql, strFilename, new object[] { strFilename, connectionFlags, openFlags, maxPoolSize, usePool })); } // Bind functions to this connection. If any previous functions of the same name // were already bound, then the new bindings replace the old. if ((connectionFlags & SQLiteConnectionFlags.NoBindFunctions) != SQLiteConnectionFlags.NoBindFunctions) { if (_functions == null) _functions = new List<SQLiteFunction>(); _functions.AddRange(new List<SQLiteFunction>(SQLiteFunction.BindFunctions(this, connectionFlags))); } SetTimeout(0); GC.KeepAlive(_sql); }
/////////////////////////////////////////////////////////////////////// /// <summary> /// Adds a connection to the pool of those associated with the /// specified database file name. /// </summary> /// <param name="fileName"> /// The database file name. /// </param> /// <param name="handle"> /// The database connection handle. /// </param> /// <param name="version"> /// The connection pool version at the point the database connection /// handle was received from the connection pool. This is also the /// connection pool version that the database connection handle was /// created under. /// </param> internal static void Add( string fileName, SQLiteConnectionHandle handle, int version ) { ISQLiteConnectionPool connectionPool = GetConnectionPool(); if (connectionPool != null) { connectionPool.Add(fileName, handle, version); } else { lock (_syncRoot) { // // NOTE: If the queue does not exist in the pool, then it // must have been cleared sometime after the // connection was created. // PoolQueue queue; if (_queueList.TryGetValue(fileName, out queue) && (version == queue.PoolVersion)) { ResizePool(queue, true); Queue<WeakReference> poolQueue = queue.Queue; if (poolQueue == null) return; poolQueue.Enqueue(new WeakReference(handle, false)); Interlocked.Increment(ref _poolClosed); } else { handle.Close(); } GC.KeepAlive(handle); } } }
/////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Constructs the object used to interact with the SQLite core library /// using the UTF-8 text encoding. /// </summary> /// <param name="fmt"> /// The DateTime format to be used when converting string values to a /// DateTime and binding DateTime parameters. /// </param> /// <param name="kind"> /// The <see cref="DateTimeKind" /> to be used when creating DateTime /// values. /// </param> /// <param name="fmtString"> /// The format string to be used when parsing and formatting DateTime /// values. /// </param> /// <param name="db"> /// The native handle to be associated with the database connection. /// </param> /// <param name="fileName"> /// The fully qualified file name associated with <paramref name="db "/>. /// </param> /// <param name="ownHandle"> /// Non-zero if the newly created object instance will need to dispose /// of <paramref name="db" /> when it is no longer needed. /// </param> internal SQLite3( SQLiteDateFormats fmt, DateTimeKind kind, string fmtString, IntPtr db, string fileName, bool ownHandle ) : base(fmt, kind, fmtString) { if (db != IntPtr.Zero) { _sql = new SQLiteConnectionHandle(db, ownHandle); _fileName = fileName; SQLiteConnection.OnChanged(null, new ConnectionEventArgs( SQLiteConnectionEventType.NewCriticalHandle, null, null, null, null, _sql, fileName, new object[] { fmt, kind, fmtString, db, fileName, ownHandle })); } }
/////////////////////////////////////////////////////////////////////// internal SQLiteStatementHandle(SQLiteConnectionHandle cnn, IntPtr stmt) : this() { #if PLATFORM_COMPACTFRAMEWORK lock (syncRoot) #endif { this.cnn = cnn; SetHandle(stmt); } }
/////////////////////////////////////////////////////////////////////// internal SQLiteBackupHandle(SQLiteConnectionHandle cnn, IntPtr backup) : this() { #if PLATFORM_COMPACTFRAMEWORK lock (syncRoot) #endif { this.cnn = cnn; SetHandle(backup); } }
internal static bool IsAutocommit(SQLiteConnectionHandle hdl, IntPtr db) { if ((hdl == null) || (db == IntPtr.Zero)) return false; bool result = false; try { // do nothing. } finally /* NOTE: Thread.Abort() protection. */ { #if PLATFORM_COMPACTFRAMEWORK lock (hdl.syncRoot) #else lock (hdl) #endif { if (!hdl.IsInvalid && !hdl.IsClosed) result = (UnsafeNativeMethods.sqlite3_get_autocommit(db) == 1); } } GC.KeepAlive(hdl); /* NOTE: Unreachable code. */ return result; }
internal static bool ResetConnection(SQLiteConnectionHandle hdl, IntPtr db, bool canThrow) { if ((hdl == null) || (db == IntPtr.Zero)) return false; bool result = false; try { // do nothing. } finally /* NOTE: Thread.Abort() protection. */ { #if PLATFORM_COMPACTFRAMEWORK lock (hdl.syncRoot) #else lock (hdl) #endif { if (canThrow && hdl.IsInvalid) throw new InvalidOperationException("The connection handle is invalid."); if (canThrow && hdl.IsClosed) throw new InvalidOperationException("The connection handle is closed."); if (!hdl.IsInvalid && !hdl.IsClosed) { IntPtr stmt = IntPtr.Zero; SQLiteErrorCode n; do { stmt = UnsafeNativeMethods.sqlite3_next_stmt(db, stmt); if (stmt != IntPtr.Zero) { #if !SQLITE_STANDARD n = UnsafeNativeMethods.sqlite3_reset_interop(stmt); #else n = UnsafeNativeMethods.sqlite3_reset(stmt); #endif } } while (stmt != IntPtr.Zero); // // NOTE: Is a transaction NOT pending on the connection? // if (IsAutocommit(hdl, db)) { result = true; } else { n = UnsafeNativeMethods.sqlite3_exec( db, ToUTF8("ROLLBACK"), IntPtr.Zero, IntPtr.Zero, out stmt); if (n == SQLiteErrorCode.Ok) { result = true; } else if (canThrow) { throw new SQLiteException(n, GetLastError(hdl, db)); } } } } } GC.KeepAlive(hdl); return result; }
internal static void CloseConnectionV2(SQLiteConnectionHandle hdl, IntPtr db) { if ((hdl == null) || (db == IntPtr.Zero)) return; try { // do nothing. } finally /* NOTE: Thread.Abort() protection. */ { #if PLATFORM_COMPACTFRAMEWORK lock (hdl.syncRoot) #else lock (hdl) #endif { #if !SQLITE_STANDARD SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_close_interop(db); #else ResetConnection(hdl, db, false); SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_close_v2(db); #endif if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, GetLastError(hdl, db)); } } }
internal static void FinalizeStatement(SQLiteConnectionHandle hdl, IntPtr stmt) { if ((hdl == null) || (stmt == IntPtr.Zero)) return; try { // do nothing. } finally /* NOTE: Thread.Abort() protection. */ { #if PLATFORM_COMPACTFRAMEWORK lock (hdl.syncRoot) #else lock (hdl) #endif { #if !SQLITE_STANDARD SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_finalize_interop(stmt); #else SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_finalize(stmt); #endif if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, null); } } }
internal static string GetLastError(SQLiteConnectionHandle hdl, IntPtr db) { if ((hdl == null) || (db == IntPtr.Zero)) return "null connection or database handle"; string result = null; try { // do nothing. } finally /* NOTE: Thread.Abort() protection. */ { #if PLATFORM_COMPACTFRAMEWORK lock (hdl.syncRoot) #else lock (hdl) #endif { if (!hdl.IsInvalid && !hdl.IsClosed) { #if !SQLITE_STANDARD int len; result = UTF8ToString(UnsafeNativeMethods.sqlite3_errmsg_interop(db, out len), len); #else result = UTF8ToString(UnsafeNativeMethods.sqlite3_errmsg(db), -1); #endif } else { result = "closed or invalid connection handle"; } } } GC.KeepAlive(hdl); return result; }