/////////////////////////////////////////////////////////////////////////////////////////////// private void Dispose(bool disposing) { if (!disposed) { if (disposing) { //////////////////////////////////// // dispose managed resources here... //////////////////////////////////// if (_sqlite_stmt != null) { _sqlite_stmt.Dispose(); _sqlite_stmt = null; } _paramNames = null; _paramValues = null; _sql = null; _sqlStatement = null; } ////////////////////////////////////// // release unmanaged resources here... ////////////////////////////////////// disposed = true; } }
/// <summary> /// Called by SQLiteBase derived classes, this function binds all user-defined functions to a connection. /// It is done this way so that all user-defined functions will access the database using the same encoding scheme /// as the connection (UTF-8 or UTF-16). /// </summary> /// <remarks> /// The wrapper functions that interop with SQLite will create a unique cookie value, which internally is a pointer to /// all the wrapped callback functions. The interop function uses it to map CDecl callbacks to StdCall callbacks. /// </remarks> /// <param name="sqlbase">The base object on which the functions are to bind</param> /// <param name="flags">The flags associated with the parent connection object</param> /// <returns>Returns an array of functions which the connection object should retain until the connection is closed.</returns> internal static SQLiteFunction[] BindFunctions(SQLiteBase sqlbase, SQLiteConnectionFlags flags) { SQLiteFunction f; List <SQLiteFunction> lFunctions = new List <SQLiteFunction>(); foreach (SQLiteFunctionAttribute pr in _registeredFunctions) { f = (SQLiteFunction)Activator.CreateInstance(pr._instanceType); f._base = sqlbase; f._flags = flags; f._InvokeFunc = (pr.FuncType == FunctionType.Scalar) ? new SQLiteCallback(f.ScalarCallback) : null; f._StepFunc = (pr.FuncType == FunctionType.Aggregate) ? new SQLiteCallback(f.StepCallback) : null; f._FinalFunc = (pr.FuncType == FunctionType.Aggregate) ? new SQLiteFinalCallback(f.FinalCallback) : null; f._CompareFunc = (pr.FuncType == FunctionType.Collation) ? new SQLiteCollation(f.CompareCallback) : null; f._CompareFunc16 = (pr.FuncType == FunctionType.Collation) ? new SQLiteCollation(f.CompareCallback16) : null; if (pr.FuncType != FunctionType.Collation) { sqlbase.CreateFunction(pr.Name, pr.Arguments, (f is SQLiteFunctionEx), f._InvokeFunc, f._StepFunc, f._FinalFunc); } else { sqlbase.CreateCollation(pr.Name, f._CompareFunc, f._CompareFunc16); } lFunctions.Add(f); } SQLiteFunction[] arFunctions = new SQLiteFunction[lFunctions.Count]; lFunctions.CopyTo(arFunctions, 0); return(arFunctions); }
/////////////////////////////////////////////////////////////////////// /// <summary> /// Internal proxy function that calls any registered application log /// event handlers. /// /// WARNING: This method is used more-or-less directly by native code, /// do not modify its type signature. /// </summary> /// <param name="pUserData"> /// The extra data associated with this message, if any. /// </param> /// <param name="errorCode"> /// The error code associated with this message. /// </param> /// <param name="pMessage"> /// The message string to be logged. /// </param> private static void LogCallback( IntPtr pUserData, int errorCode, IntPtr pMessage ) { bool enabled; SQLiteLogEventHandler handlers; lock (syncRoot) { enabled = _enabled; if (_handlers != null) { handlers = _handlers.Clone() as SQLiteLogEventHandler; } else { handlers = null; } } if (enabled && (handlers != null)) { handlers(null, new LogEventArgs(pUserData, errorCode, SQLiteBase.PtrToString(pMessage, -1), null)); } }
/////////////////////////////////////////////////////////////////////////////////////////////// private void Dispose(bool disposing) { if (!disposed) { if (disposing) { //////////////////////////////////// // dispose managed resources here... //////////////////////////////////// if (_sqlite_backup != null) { _sqlite_backup.Dispose(); _sqlite_backup = null; } _zSourceName = null; _sourceDb = IntPtr.Zero; _zDestName = null; _destDb = IntPtr.Zero; _sql = null; } ////////////////////////////////////// // release unmanaged resources here... ////////////////////////////////////// disposed = true; } }
/// <summary> /// Disposes of any active contextData variables that were not automatically cleaned up. Sometimes this can happen if /// someone closes the connection while a DataReader is open. /// </summary> public void Dispose() { Dispose(true); IDisposable disp; foreach (KeyValuePair <long, object> kv in _contextDataList) { disp = kv.Value as IDisposable; if (disp != null) { disp.Dispose(); } } _contextDataList.Clear(); _InvokeFunc = null; _StepFunc = null; _FinalFunc = null; _CompareFunc = null; _base = null; _contextDataList = null; GC.SuppressFinalize(this); }
/////////////////////////////////////////////////////////////////////////////////////////////// private void Dispose(bool disposing) { if (!disposed) { if (disposing) { //////////////////////////////////// // dispose managed resources here... //////////////////////////////////// if (_sqlite_blob != null) { _sqlite_blob.Dispose(); _sqlite_blob = null; } _sql = null; } ////////////////////////////////////// // release unmanaged resources here... ////////////////////////////////////// disposed = true; } }
internal SQLiteStatement(SQLiteBase sqlbase, SQLiteStatementHandle stmt, string strCommand, SQLiteStatement previous) { this._sql = sqlbase; this._sqlite_stmt = stmt; this._sqlStatement = strCommand; int num = 0; int num2 = this._sql.Bind_ParamCount(this); if (num2 > 0) { if (previous != null) { num = previous._unnamedParameters; } this._paramNames = new string[num2]; this._paramValues = new SQLiteParameter[num2]; for (int i = 0; i < num2; i++) { string str = this._sql.Bind_ParamName(this, i + 1); if (string.IsNullOrEmpty(str)) { str = string.Format(CultureInfo.InvariantCulture, ";{0}", new object[] { num }); num++; this._unnamedParameters++; } this._paramNames[i] = str; this._paramValues[i] = null; } } }
internal static SQLiteFunction[] BindFunctions(SQLiteBase sqlbase) { List <SQLiteFunction> list = new List <SQLiteFunction>(); foreach (SQLiteFunctionAttribute attribute in _registeredFunctions) { SQLiteFunction item = (SQLiteFunction)Activator.CreateInstance(attribute._instanceType); item._base = sqlbase; item._InvokeFunc = (attribute.FuncType == FunctionType.Scalar) ? new SQLiteCallback(item.ScalarCallback) : null; item._StepFunc = (attribute.FuncType == FunctionType.Aggregate) ? new SQLiteCallback(item.StepCallback) : null; item._FinalFunc = (attribute.FuncType == FunctionType.Aggregate) ? new SQLiteFinalCallback(item.FinalCallback) : null; item._CompareFunc = (attribute.FuncType == FunctionType.Collation) ? new SQLiteCollation(item.CompareCallback) : null; item._CompareFunc16 = (attribute.FuncType == FunctionType.Collation) ? new SQLiteCollation(item.CompareCallback16) : null; if (attribute.FuncType != FunctionType.Collation) { sqlbase.CreateFunction(attribute.Name, attribute.Arguments, item is SQLiteFunctionEx, item._InvokeFunc, item._StepFunc, item._FinalFunc); } else { sqlbase.CreateCollation(attribute.Name, item._CompareFunc, item._CompareFunc16); } list.Add(item); } SQLiteFunction[] array = new SQLiteFunction[list.Count]; list.CopyTo(array, 0); return(array); }
/// <summary> /// Initializes the statement and attempts to get all information about parameters in the statement /// </summary> /// <param name="sqlbase">The base SQLite object</param> /// <param name="flags">The flags associated with the parent connection object</param> /// <param name="stmt">The statement</param> /// <param name="strCommand">The command text for this statement</param> /// <param name="previous">The previous command in a multi-statement command</param> internal SQLiteStatement(SQLiteBase sqlbase, SQLiteConnectionFlags flags, SQLiteStatementHandle stmt, string strCommand, SQLiteStatement previous) { _sql = sqlbase; _sqlite_stmt = stmt; _sqlStatement = strCommand; _flags = flags; // Determine parameters for this statement (if any) and prepare space for them. int nCmdStart = 0; int n = _sql.Bind_ParamCount(this, _flags); int x; string s; if (n > 0) { if (previous != null) nCmdStart = previous._unnamedParameters; _paramNames = new string[n]; _paramValues = new SQLiteParameter[n]; for (x = 0; x < n; x++) { s = _sql.Bind_ParamName(this, _flags, x + 1); if (String.IsNullOrEmpty(s)) { s = String.Format(CultureInfo.InvariantCulture, ";{0}", nCmdStart); nCmdStart++; _unnamedParameters++; } _paramNames[x] = s; _paramValues[x] = null; } } }
/// <summary> /// This function binds a user-defined functions to a connection. /// </summary> /// <param name="sqliteBase"> /// The <see cref="SQLiteBase" /> object instance associated with the /// <see cref="SQLiteConnection" /> that the function should be bound to. /// </param> /// <param name="functionAttribute"> /// The <see cref="SQLiteFunctionAttribute"/> object instance containing /// the metadata for the function to be bound. /// </param> /// <param name="function"> /// The <see cref="SQLiteFunction"/> object instance that implements the /// function to be bound. /// </param> /// <param name="flags"> /// The flags associated with the parent connection object. /// </param> internal static void BindFunction( SQLiteBase sqliteBase, SQLiteFunctionAttribute functionAttribute, SQLiteFunction function, SQLiteConnectionFlags flags ) { if (sqliteBase == null) { throw new ArgumentNullException("sqliteBase"); } if (functionAttribute == null) { throw new ArgumentNullException("functionAttribute"); } if (function == null) { throw new ArgumentNullException("function"); } FunctionType functionType = functionAttribute.FuncType; function._base = sqliteBase; function._flags = flags; function._InvokeFunc = (functionType == FunctionType.Scalar) ? new SQLiteCallback(function.ScalarCallback) : null; function._StepFunc = (functionType == FunctionType.Aggregate) ? new SQLiteCallback(function.StepCallback) : null; function._FinalFunc = (functionType == FunctionType.Aggregate) ? new SQLiteFinalCallback(function.FinalCallback) : null; function._CompareFunc = (functionType == FunctionType.Collation) ? new SQLiteCollation(function.CompareCallback) : null; function._CompareFunc16 = (functionType == FunctionType.Collation) ? new SQLiteCollation(function.CompareCallback16) : null; string name = functionAttribute.Name; if (functionType != FunctionType.Collation) { bool needCollSeq = (function is SQLiteFunctionEx); sqliteBase.CreateFunction( name, functionAttribute.Arguments, needCollSeq, function._InvokeFunc, function._StepFunc, function._FinalFunc); } else { sqliteBase.CreateCollation( name, function._CompareFunc, function._CompareFunc16); } }
/////////////////////////////////////////////////////////////////////////////////////////////// #region Private Constructors /// <summary> /// Initializes the blob. /// </summary> /// <param name="sqlbase">The base SQLite object.</param> /// <param name="blob">The blob handle.</param> private SQLiteBlob( SQLiteBase sqlbase, SQLiteBlobHandle blob ) { _sql = sqlbase; _sqlite_blob = blob; }
protected override bool ReleaseHandle() { try { SQLiteBase.CloseConnection(this); } catch (SQLiteException) { } return(true); }
/// <summary> /// Disposes and finalizes the statement /// </summary> public void Dispose() { _sql.FinalizeStatement(this); _paramNames = null; _paramValues = null; _sql = null; _sqlStatement = null; GC.SuppressFinalize(this); }
protected override bool ReleaseHandle() { try { SQLiteBase.FinalizeStatement(this); } catch (SQLiteException) { } return(true); }
public void Dispose() { if (this._sqlite_stmt != null) { this._sqlite_stmt.Dispose(); } this._sqlite_stmt = null; this._paramNames = null; this._paramValues = null; this._sql = null; this._sqlStatement = null; }
/// <summary> /// Called by SQLiteBase derived classes, this function binds all user-defined functions to a connection. /// It is done this way so that all user-defined functions will access the database using the same encoding scheme /// as the connection (UTF-8 or UTF-16). /// </summary> /// <remarks> /// The wrapper functions that interop with SQLite will create a unique cookie value, which internally is a pointer to /// all the wrapped callback functions. The interop function uses it to map CDecl callbacks to StdCall callbacks. /// </remarks> /// <param name="sqlbase">The base object on which the functions are to bind</param> /// <param name="flags">The flags associated with the parent connection object</param> /// <returns>Returns a logical list of functions which the connection should retain until it is closed.</returns> internal static IEnumerable <SQLiteFunction> BindFunctions(SQLiteBase sqlbase, SQLiteConnectionFlags flags) { List <SQLiteFunction> lFunctions = new List <SQLiteFunction>(); foreach (SQLiteFunctionAttribute pr in _registeredFunctions) { SQLiteFunction f = (SQLiteFunction)Activator.CreateInstance(pr.InstanceType); BindFunction(sqlbase, pr, f, flags); lFunctions.Add(f); } return(lFunctions); }
/// <summary> /// Disposes and finalizes the statement /// </summary> public void Dispose() { if (_sqlite_stmt != null) { _sqlite_stmt.Dispose(); } _sqlite_stmt = null; _paramNames = null; _paramValues = null; _sql = null; _sqlStatement = null; }
/// <summary> /// This method resets all the prepared statements held by this instance /// back to their initial states, ready to be re-executed. /// </summary> /// <param name="clearBindings"> /// Non-zero if the parameter bindings should be cleared as well. /// </param> /// <param name="ignoreErrors"> /// If this is zero, a <see cref="SQLiteException" /> may be thrown for /// any unsuccessful return codes from the native library; otherwise, a /// <see cref="SQLiteException" /> will only be thrown if the connection /// or its state is invalid. /// </param> public void Reset( bool clearBindings, bool ignoreErrors ) { CheckDisposed(); SQLiteConnection.Check(_cnn); if (clearBindings && (_parameterCollection != null)) { _parameterCollection.Unbind(); } ClearDataReader(); if (_statementList == null) { return; } SQLiteBase sqlBase = _cnn._sql; SQLiteErrorCode rc; foreach (SQLiteStatement item in _statementList) { if (item == null) { continue; } SQLiteStatementHandle stmt = item._sqlite_stmt; if (stmt == null) { continue; } rc = sqlBase.Reset(item); if ((rc == SQLiteErrorCode.Ok) && clearBindings && (SQLite3.SQLiteVersionNumber >= 3003007)) { rc = UnsafeNativeMethods.sqlite3_clear_bindings(stmt); } if (!ignoreErrors && (rc != SQLiteErrorCode.Ok)) { throw new SQLiteException(rc, sqlBase.GetLastError()); } } }
/// <summary> /// Issued after the base connection is closed, this function cleans up all user-defined functions and disposes of them. /// </summary> /// <remarks> /// Cleaning up here is done mainly because of the interop wrapper. It allocated memory to hold a reference to all the /// delegates, and now must free that memory. /// Freeing is done after the connection is closed to ensure no callbacks get hit after we've freed the cookie. /// </remarks> /// <param name="sqlbase">The base SQLite connection object</param> /// <param name="ar">An array of user-defined functions for this object</param> internal static void UnbindFunctions(SQLiteBase sqlbase, SQLiteFunction[] ar) { if (ar == null) { return; } int x = ar.Length; for (int n = 0; n < x; n++) { sqlbase.FreeFunction(ar[n]._interopCookie); ar[n].Dispose(); } }
/// <summary> /// Initializes the backup. /// </summary> /// <param name="sqlbase">The base SQLite object.</param> /// <param name="backup">The backup handle.</param> /// <param name="destDb">The destination database for the backup.</param> /// <param name="zDestName">The destination database name for the backup.</param> /// <param name="sourceDb">The source database for the backup.</param> /// <param name="zSourceName">The source database name for the backup.</param> internal SQLiteBackup( SQLiteBase sqlbase, SQLiteBackupHandle backup, IntPtr destDb, byte[] zDestName, IntPtr sourceDb, byte[] zSourceName ) { _sql = sqlbase; _sqlite_backup = backup; _destDb = destDb; _zDestName = zDestName; _sourceDb = sourceDb; _zSourceName = zSourceName; }
internal override void Close() { if (this._sql != null) { if (this._usePool) { SQLiteBase.ResetConnection(this._sql); SQLiteConnectionPool.Add(this._fileName, this._sql, this._poolVersion); } else { this._sql.Dispose(); } } this._sql = null; }
/// <summary> /// Constructs an instance of this class using the specified data-type /// conversion parameters. /// </summary> /// <param name="format"> /// 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="formatString"> /// The format string to be used when parsing and formatting DateTime /// values. /// </param> /// <param name="utf16"> /// Non-zero to create a UTF-16 data-type conversion context; otherwise, /// a UTF-8 data-type conversion context will be created. /// </param> protected SQLiteFunction( SQLiteDateFormats format, DateTimeKind kind, string formatString, bool utf16 ) : this() { if (utf16) { _base = new SQLite3_UTF16(format, kind, formatString, IntPtr.Zero, null, false); } else { _base = new SQLite3(format, kind, formatString, IntPtr.Zero, null, false); } }
// 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() { if (_sql != null) { if (_usePool) { SQLiteBase.ResetConnection(_sql); SQLiteConnectionPool.Add(_fileName, _sql, _poolVersion); } else { _sql.Dispose(); } } _sql = null; }
protected virtual void Dispose(bool disposing) { if (disposing) { foreach (KeyValuePair <long, AggregateData> pair in this._contextDataList) { IDisposable disposable = pair.Value._data as IDisposable; if (disposable != null) { disposable.Dispose(); } } this._contextDataList.Clear(); this._InvokeFunc = null; this._StepFunc = null; this._FinalFunc = null; this._CompareFunc = null; this._base = null; this._contextDataList = null; } }
/////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Placeholder for a user-defined disposal routine /// </summary> /// <param name="disposing">True if the object is being disposed explicitly</param> protected virtual void Dispose(bool disposing) { if (!disposed) { if (disposing) { //////////////////////////////////// // dispose managed resources here... //////////////////////////////////// IDisposable disp; foreach (KeyValuePair <IntPtr, AggregateData> kv in _contextDataList) { disp = kv.Value._data as IDisposable; if (disp != null) { disp.Dispose(); } } _contextDataList.Clear(); _contextDataList = null; _flags = SQLiteConnectionFlags.None; _InvokeFunc = null; _StepFunc = null; _FinalFunc = null; _CompareFunc = null; _base = null; } ////////////////////////////////////// // release unmanaged resources here... ////////////////////////////////////// disposed = true; } }
/// <summary> /// Returns the error message for the specified SQLite return code. /// </summary> /// <param name="errorCode">The SQLite return code.</param> /// <returns>The error message or null if it cannot be found.</returns> private static string GetErrorString( SQLiteErrorCode errorCode ) { #if !PLATFORM_COMPACTFRAMEWORK // // HACK: This must be done via reflection in order to prevent // the RuntimeHelpers.PrepareDelegate method from over- // eagerly attempting to locate the new (and optional) // sqlite3_errstr() function in the SQLite core library // because it happens to be in the static call graph for // the AppDomain.DomainUnload event handler registered // by the SQLiteLog class. // BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod; return(typeof(SQLiteBase).InvokeMember("GetErrorString", flags, null, null, new object[] { errorCode }) as string); #else return(SQLiteBase.GetErrorString(errorCode)); #endif }
/// <summary> /// Initializes the statement and attempts to get all information about parameters in the statement /// </summary> /// <param name="sqlbase">The base SQLite object</param> /// <param name="flags">The flags associated with the parent connection object</param> /// <param name="stmt">The statement</param> /// <param name="strCommand">The command text for this statement</param> /// <param name="previous">The previous command in a multi-statement command</param> internal SQLiteStatement(SQLiteBase sqlbase, SQLiteConnectionFlags flags, SQLiteStatementHandle stmt, string strCommand, SQLiteStatement previous) { _sql = sqlbase; _sqlite_stmt = stmt; _sqlStatement = strCommand; _flags = flags; // Determine parameters for this statement (if any) and prepare space for them. int nCmdStart = 0; int n = _sql.Bind_ParamCount(this, _flags); int x; string s; if (n > 0) { if (previous != null) { nCmdStart = previous._unnamedParameters; } _paramNames = new string[n]; _paramValues = new SQLiteParameter[n]; for (x = 0; x < n; x++) { s = _sql.Bind_ParamName(this, _flags, x + 1); if (String.IsNullOrEmpty(s)) { s = HelperMethods.StringFormat(CultureInfo.InvariantCulture, ";{0}", nCmdStart); nCmdStart++; _unnamedParameters++; } _paramNames[x] = s; _paramValues[x] = null; } } }
/// <summary> /// Placeholder for a user-defined disposal routine /// </summary> /// <param name="disposing">True if the object is being disposed explicitly</param> protected virtual void Dispose(bool disposing) { if (disposing) { IDisposable disp; foreach (KeyValuePair <long, AggregateData> kv in _contextDataList) { disp = kv.Value._data as IDisposable; if (disp != null) { disp.Dispose(); } } _contextDataList.Clear(); _InvokeFunc = null; _StepFunc = null; _FinalFunc = null; _CompareFunc = null; _base = null; _contextDataList = null; } }
/// <summary> /// Called by SQLiteBase derived classes, this function binds all user-defined functions to a connection. /// It is done this way so that all user-defined functions will access the database using the same encoding scheme /// as the connection (UTF-8 or UTF-16). /// </summary> /// <remarks> /// The wrapper functions that interop with SQLite will create a unique cookie value, which internally is a pointer to /// all the wrapped callback functions. The interop function uses it to map CDecl callbacks to StdCall callbacks. /// </remarks> /// <param name="sqlbase">The base object on which the functions are to bind</param> /// <param name="flags">The flags associated with the parent connection object</param> /// <returns>Returns a logical list of functions which the connection should retain until it is closed.</returns> internal static IEnumerable<SQLiteFunction> BindFunctions(SQLiteBase sqlbase, SQLiteConnectionFlags flags) { List<SQLiteFunction> lFunctions = new List<SQLiteFunction>(); foreach (SQLiteFunctionAttribute pr in _registeredFunctions) { SQLiteFunction f = (SQLiteFunction)Activator.CreateInstance(pr.InstanceType); BindFunction(sqlbase, pr, f, flags); lFunctions.Add(f); } return lFunctions; }
/// <summary> /// Constructs an instance of this class using the specified data-type /// conversion parameters. /// </summary> /// <param name="format"> /// 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="formatString"> /// The format string to be used when parsing and formatting DateTime /// values. /// </param> /// <param name="utf16"> /// Non-zero to create a UTF-16 data-type conversion context; otherwise, /// a UTF-8 data-type conversion context will be created. /// </param> protected SQLiteFunction( SQLiteDateFormats format, DateTimeKind kind, string formatString, bool utf16 ) : this() { if (utf16) _base = new SQLite3_UTF16(format, kind, formatString, IntPtr.Zero, null, false); else _base = new SQLite3(format, kind, formatString, IntPtr.Zero, null, false); }
/// <summary> /// Called by the SQLiteBase derived classes, this method unbinds all registered (known) /// functions -OR- all previously bound user-defined functions from a connection. /// </summary> /// <param name="sqlbase">The base object from which the functions are to be unbound.</param> /// <param name="flags">The flags associated with the parent connection object.</param> /// <param name="registered"> /// Non-zero to unbind all registered (known) functions -OR- zero to unbind all functions /// currently bound to the connection. /// </param> /// <returns>Non-zero if all the specified user-defined functions were unbound.</returns> internal static bool UnbindAllFunctions( SQLiteBase sqlbase, SQLiteConnectionFlags flags, bool registered ) { if (sqlbase == null) return false; IDictionary<SQLiteFunctionAttribute, SQLiteFunction> lFunctions = sqlbase.Functions; if (lFunctions == null) return false; bool result = true; if (registered) { foreach (KeyValuePair<SQLiteFunctionAttribute, object> pair in _registeredFunctions) { SQLiteFunctionAttribute pr = pair.Key; if (pr == null) continue; SQLiteFunction f; if (!lFunctions.TryGetValue(pr, out f) || (f == null) || !UnbindFunction(sqlbase, pr, f, flags)) { result = false; } } } else { // // NOTE: Need to use a copy of the function dictionary in this method // because the dictionary is modified within the UnbindFunction // method, which is called inside the loop. // lFunctions = new Dictionary<SQLiteFunctionAttribute, SQLiteFunction>( lFunctions); foreach (KeyValuePair<SQLiteFunctionAttribute, SQLiteFunction> pair in lFunctions) { SQLiteFunctionAttribute pr = pair.Key; if (pr == null) continue; SQLiteFunction f = pair.Value; if ((f == null) || !UnbindFunction(sqlbase, pr, f, flags)) { result = false; } } } return result; }
/// <summary> /// Initializes the connection with a pre-existing native connection handle. /// </summary> /// <param name="db"> /// The native connection handle to use. /// </param> /// <param name="fileName"> /// The file name corresponding to the native connection handle. /// </param> /// <param name="ownHandle"> /// Non-zero if this instance owns the native connection handle and /// should dispose of it when it is no longer needed. /// </param> internal SQLiteConnection(IntPtr db, string fileName, bool ownHandle) : this() { _sql = new SQLite3( SQLiteDateFormats.Default, DateTimeKind.Unspecified, null, db, fileName, ownHandle); _flags = SQLiteConnectionFlags.None; _connectionState = (db != IntPtr.Zero) ? ConnectionState.Open : ConnectionState.Closed; _connectionString = null; /* unknown */ }
/// <summary> /// When the database connection is closed, all commands linked to this connection are automatically reset. /// </summary> public override void Close() { if (_sql != null) { int x = _commandList.Count; for (int n = 0; n < x; n++) { _commandList[n].ClearCommands(); } _sql.Close(); _sql = null; } OnStateChange(ConnectionState.Closed); }
/// <summary> /// Opens the connection using the parameters found in the <see cref="ConnectionString" />. /// </summary> public override void Open() { CheckDisposed(); OnChanged(this, new ConnectionEventArgs( SQLiteConnectionEventType.Opening, null, null, null, null, null)); if (_connectionState != ConnectionState.Closed) throw new InvalidOperationException(); Close(); SortedList<string, string> opts = _parseViaFramework ? ParseConnectionStringViaFramework(_connectionString, false) : ParseConnectionString(_connectionString); OnChanged(this, new ConnectionEventArgs( SQLiteConnectionEventType.ConnectionString, null, null, null, _connectionString, opts)); object enumValue; enumValue = TryParseEnum(typeof(SQLiteConnectionFlags), FindKey(opts, "Flags", DefaultFlags.ToString()), true); _flags = (enumValue is SQLiteConnectionFlags) ? (SQLiteConnectionFlags)enumValue : DefaultFlags; bool fullUri = false; string fileName; if (Convert.ToInt32(FindKey(opts, "Version", DefaultVersion.ToString()), CultureInfo.InvariantCulture) != DefaultVersion) throw new NotSupportedException(String.Format(CultureInfo.CurrentCulture, "Only SQLite Version {0} is supported at this time", DefaultVersion)); fileName = FindKey(opts, "Data Source", DefaultDataSource); if (String.IsNullOrEmpty(fileName)) { fileName = FindKey(opts, "Uri", DefaultUri); if (String.IsNullOrEmpty(fileName)) { fileName = FindKey(opts, "FullUri", DefaultFullUri); if (String.IsNullOrEmpty(fileName)) throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, "Data Source cannot be empty. Use {0} to open an in-memory database", MemoryFileName)); else fullUri = true; } else fileName = MapUriPath(fileName); } bool isMemory = (String.Compare(fileName, MemoryFileName, StringComparison.OrdinalIgnoreCase) == 0); if (!fullUri) { if (isMemory) fileName = MemoryFileName; else { #if PLATFORM_COMPACTFRAMEWORK if (fileName.StartsWith("./") || fileName.StartsWith(".\\")) fileName = Path.GetDirectoryName(System.Reflection.Assembly.GetCallingAssembly().GetName().CodeBase) + fileName.Substring(1); #endif bool toFullPath = SQLiteConvert.ToBoolean(FindKey(opts, "ToFullPath", DefaultToFullPath.ToString())); fileName = ExpandFileName(fileName, toFullPath); } } try { bool usePooling = SQLiteConvert.ToBoolean(FindKey(opts, "Pooling", DefaultPooling.ToString())); int maxPoolSize = Convert.ToInt32(FindKey(opts, "Max Pool Size", DefaultMaxPoolSize.ToString()), CultureInfo.InvariantCulture); _defaultTimeout = Convert.ToInt32(FindKey(opts, "Default Timeout", DefaultConnectionTimeout.ToString()), CultureInfo.InvariantCulture); enumValue = TryParseEnum(typeof(IsolationLevel), FindKey(opts, "Default IsolationLevel", DefaultIsolationLevel.ToString()), true); _defaultIsolation = (enumValue is IsolationLevel) ? (IsolationLevel)enumValue : DefaultIsolationLevel; if (_defaultIsolation != IsolationLevel.Serializable && _defaultIsolation != IsolationLevel.ReadCommitted) throw new NotSupportedException("Invalid Default IsolationLevel specified"); _baseSchemaName = FindKey(opts, "BaseSchemaName", DefaultBaseSchemaName); if (_sql == null) { enumValue = TryParseEnum(typeof(SQLiteDateFormats), FindKey(opts, "DateTimeFormat", DefaultDateTimeFormat.ToString()), true); SQLiteDateFormats dateFormat = (enumValue is SQLiteDateFormats) ? (SQLiteDateFormats)enumValue : DefaultDateTimeFormat; enumValue = TryParseEnum(typeof(DateTimeKind), FindKey(opts, "DateTimeKind", DefaultDateTimeKind.ToString()), true); DateTimeKind kind = (enumValue is DateTimeKind) ? (DateTimeKind)enumValue : DefaultDateTimeKind; // // NOTE: SQLite automatically sets the encoding of the database to // UTF16 if called from sqlite3_open16(). // if (SQLiteConvert.ToBoolean(FindKey(opts, "UseUTF16Encoding", DefaultUseUTF16Encoding.ToString()))) { _sql = new SQLite3_UTF16(dateFormat, kind); } else { _sql = new SQLite3(dateFormat, kind); } } SQLiteOpenFlagsEnum flags = SQLiteOpenFlagsEnum.None; if (!SQLiteConvert.ToBoolean(FindKey(opts, "FailIfMissing", DefaultFailIfMissing.ToString()))) flags |= SQLiteOpenFlagsEnum.Create; if (SQLiteConvert.ToBoolean(FindKey(opts, "Read Only", DefaultReadOnly.ToString()))) { flags |= SQLiteOpenFlagsEnum.ReadOnly; // SQLite will return SQLITE_MISUSE on ReadOnly and Create flags &= ~SQLiteOpenFlagsEnum.Create; } else { flags |= SQLiteOpenFlagsEnum.ReadWrite; } if (fullUri) flags |= SQLiteOpenFlagsEnum.Uri; _sql.Open(fileName, _flags, flags, maxPoolSize, usePooling); _binaryGuid = SQLiteConvert.ToBoolean(FindKey(opts, "BinaryGUID", DefaultBinaryGUID.ToString())); #if INTEROP_CODEC string password = FindKey(opts, "Password", DefaultPassword); if (!String.IsNullOrEmpty(password)) _sql.SetPassword(System.Text.UTF8Encoding.UTF8.GetBytes(password)); else if (_password != null) _sql.SetPassword(_password); _password = null; #endif if (!fullUri) _dataSource = Path.GetFileNameWithoutExtension(fileName); else _dataSource = fileName; _version++; ConnectionState oldstate = _connectionState; _connectionState = ConnectionState.Open; try { string strValue; bool boolValue; strValue = FindKey(opts, "SetDefaults", DefaultSetDefaults.ToString()); boolValue = SQLiteConvert.ToBoolean(strValue); if (boolValue) { using (SQLiteCommand cmd = CreateCommand()) { int intValue; if (!fullUri && !isMemory) { strValue = FindKey(opts, "Page Size", DefaultPageSize.ToString()); intValue = Convert.ToInt32(strValue, CultureInfo.InvariantCulture); if (intValue != DefaultPageSize) { cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA page_size={0}", intValue); cmd.ExecuteNonQuery(); } } strValue = FindKey(opts, "Max Page Count", DefaultMaxPageCount.ToString()); intValue = Convert.ToInt32(strValue, CultureInfo.InvariantCulture); if (intValue != DefaultMaxPageCount) { cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA max_page_count={0}", intValue); cmd.ExecuteNonQuery(); } strValue = FindKey(opts, "Legacy Format", DefaultLegacyFormat.ToString()); boolValue = SQLiteConvert.ToBoolean(strValue); if (boolValue != DefaultLegacyFormat) { cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA legacy_file_format={0}", boolValue ? "ON" : "OFF"); cmd.ExecuteNonQuery(); } strValue = FindKey(opts, "Synchronous", DefaultSynchronous.ToString()); enumValue = TryParseEnum(typeof(SQLiteSynchronousEnum), strValue, true); if (!(enumValue is SQLiteSynchronousEnum) || ((SQLiteSynchronousEnum)enumValue != DefaultSynchronous)) { cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA synchronous={0}", strValue); cmd.ExecuteNonQuery(); } strValue = FindKey(opts, "Cache Size", DefaultCacheSize.ToString()); intValue = Convert.ToInt32(strValue, CultureInfo.InvariantCulture); if (intValue != DefaultCacheSize) { cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA cache_size={0}", intValue); cmd.ExecuteNonQuery(); } strValue = FindKey(opts, "Journal Mode", DefaultJournalMode.ToString()); enumValue = TryParseEnum(typeof(SQLiteJournalModeEnum), strValue, true); if (!(enumValue is SQLiteJournalModeEnum) || ((SQLiteJournalModeEnum)enumValue != DefaultJournalMode)) { cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA journal_mode={0}", strValue); cmd.ExecuteNonQuery(); } strValue = FindKey(opts, "Foreign Keys", DefaultForeignKeys.ToString()); boolValue = Convert.ToBoolean(strValue, CultureInfo.InvariantCulture); if (boolValue != DefaultForeignKeys) { cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA foreign_keys={0}", boolValue ? "ON" : "OFF"); cmd.ExecuteNonQuery(); } } } if (_commitHandler != null) _sql.SetCommitHook(_commitCallback); if (_updateHandler != null) _sql.SetUpdateHook(_updateCallback); if (_rollbackHandler != null) _sql.SetRollbackHook(_rollbackCallback); #if !PLATFORM_COMPACTFRAMEWORK System.Transactions.Transaction transaction = Transactions.Transaction.Current; if (transaction != null && SQLiteConvert.ToBoolean(FindKey(opts, "Enlist", DefaultEnlist.ToString()))) { EnlistTransaction(transaction); } #endif _connectionState = oldstate; StateChangeEventArgs eventArgs = null; OnStateChange(ConnectionState.Open, ref eventArgs); OnChanged(this, new ConnectionEventArgs( SQLiteConnectionEventType.Opened, eventArgs, null, null, null, null)); } catch { _connectionState = oldstate; throw; } } catch (SQLiteException) { Close(); throw; } }
/// <summary> /// Placeholder for a user-defined disposal routine /// </summary> /// <param name="disposing">True if the object is being disposed explicitly</param> protected virtual void Dispose(bool disposing) { if (disposing) { IDisposable disp; foreach (KeyValuePair<long, AggregateData> kv in _contextDataList) { disp = kv.Value._data as IDisposable; if (disp != null) disp.Dispose(); } _contextDataList.Clear(); _InvokeFunc = null; _StepFunc = null; _FinalFunc = null; _CompareFunc = null; _base = null; _contextDataList = null; } }
/// Passes a shutdown request off to SQLite. public SQLiteErrorCode Shutdown() { CheckDisposed(); // make sure we have an instance of the base class if (_sql == null) { SortedList<string, string> opts = _parseViaFramework ? ParseConnectionStringViaFramework(_connectionString, false) : ParseConnectionString(_connectionString); object enumValue; enumValue = TryParseEnum(typeof(SQLiteDateFormats), FindKey(opts, "DateTimeFormat", DefaultDateTimeFormat.ToString()), true); SQLiteDateFormats dateFormat = (enumValue is SQLiteDateFormats) ? (SQLiteDateFormats)enumValue : DefaultDateTimeFormat; enumValue = TryParseEnum(typeof(DateTimeKind), FindKey(opts, "DateTimeKind", DefaultDateTimeKind.ToString()), true); DateTimeKind kind = (enumValue is DateTimeKind) ? (DateTimeKind)enumValue : DefaultDateTimeKind; // // NOTE: SQLite automatically sets the encoding of the database to // UTF16 if called from sqlite3_open16(). // if (SQLiteConvert.ToBoolean(FindKey(opts, "UseUTF16Encoding", DefaultUseUTF16Encoding.ToString()))) { _sql = new SQLite3_UTF16(dateFormat, kind); } else { _sql = new SQLite3(dateFormat, kind); } } if (_sql != null) return _sql.Shutdown(); throw new InvalidOperationException("Database connection not active."); }
/////////////////////////////////////////////////////////////////////// /// <summary> /// Initializes the SQLite logging facilities. /// </summary> /// <param name="className"> /// The name of the managed class that called this method. This /// parameter may be null. /// </param> internal static void Initialize( string className ) { // // NOTE: See if the logging subsystem has been totally disabled. // If so, do nothing. // if (UnsafeNativeMethods.GetSettingValue( "No_SQLiteLog", null) != null) { return; } /////////////////////////////////////////////////////////////// // // NOTE: Keep track of exactly how many times this method is // called (i.e. per-AppDomain, of course). // Interlocked.Increment(ref _initializeCallCount); /////////////////////////////////////////////////////////////// // // NOTE: First, check if the managed logging subsystem is always // supposed to at least attempt to initialize itself. In // order to do this, several fairly complex steps must be // taken, including calling a P/Invoke (interop) method; // therefore, by default, attempt to perform these steps // once. // if (UnsafeNativeMethods.GetSettingValue( "Initialize_SQLiteLog", null) == null) { if (Interlocked.Increment(ref _attemptedInitialize) > 1) { Interlocked.Decrement(ref _attemptedInitialize); return; } } /////////////////////////////////////////////////////////////////// // // BUFXIX: Cannot initialize the logging interface if the SQLite // core library has already been initialized anywhere in // the process (see ticket [2ce0870fad]). // if (SQLite3.StaticIsInitialized()) { return; } /////////////////////////////////////////////////////////////////// #if !PLATFORM_COMPACTFRAMEWORK // // BUGFIX: To avoid nasty situations where multiple AppDomains are // attempting to initialize and/or shutdown what is really // a shared native resource (i.e. the SQLite core library // is loaded per-process and has only one logging callback, // not one per-AppDomain, which it knows nothing about), // prevent all non-default AppDomains from registering a // log handler unless the "Force_SQLiteLog" environment // variable is used to manually override this safety check. // if (!AppDomain.CurrentDomain.IsDefaultAppDomain() && UnsafeNativeMethods.GetSettingValue("Force_SQLiteLog", null) == null) { return; } #endif /////////////////////////////////////////////////////////////////// lock (syncRoot) { #if !PLATFORM_COMPACTFRAMEWORK // // NOTE: Add an event handler for the DomainUnload event so // that we can unhook our logging managed function // pointer from the native SQLite code prior to it // being invalidated. // // BUGFIX: Make sure this event handler is only added one // time (per-AppDomain). // if (_domainUnload == null) { _domainUnload = new EventHandler(DomainUnload); AppDomain.CurrentDomain.DomainUnload += _domainUnload; } #endif /////////////////////////////////////////////////////////////// #if USE_INTEROP_DLL && INTEROP_LOG // // NOTE: Attempt to setup interop assembly log callback. // This may fail, e.g. if the SQLite core library // has somehow been initialized. An exception will // be raised in that case. // SQLiteErrorCode rc = SQLite3.ConfigureLogForInterop( className); if (rc != SQLiteErrorCode.Ok) { throw new SQLiteException(rc, "Failed to configure interop assembly logging."); } #else // // NOTE: Create an instance of the SQLite wrapper class. // if (_sql == null) { _sql = new SQLite3( SQLiteDateFormats.Default, DateTimeKind.Unspecified, null, IntPtr.Zero, null, false); } // // NOTE: Create a single "global" (i.e. per-process) callback // to register with SQLite. This callback will pass the // event on to any registered handler. We only want to // do this once. // if (_callback == null) { _callback = new SQLiteLogCallback(LogCallback); SQLiteErrorCode rc = _sql.SetLogCallback(_callback); if (rc != SQLiteErrorCode.Ok) { _callback = null; /* UNDO */ throw new SQLiteException(rc, "Failed to configure managed assembly logging."); } } #endif /////////////////////////////////////////////////////////////// // // NOTE: Logging is enabled by default unless the configuration // setting "Disable_SQLiteLog" is present. // if (UnsafeNativeMethods.GetSettingValue( "Disable_SQLiteLog", null) == null) { _enabled = true; } /////////////////////////////////////////////////////////////// // // NOTE: For now, always setup the default log event handler. // AddDefaultHandler(); } }
/// <summary> /// This function unbinds a user-defined functions from a connection. /// </summary> /// <param name="sqliteBase"> /// The <see cref="SQLiteBase" /> object instance associated with the /// <see cref="SQLiteConnection" /> that the function should be bound to. /// </param> /// <param name="functionAttribute"> /// The <see cref="SQLiteFunctionAttribute"/> object instance containing /// the metadata for the function to be bound. /// </param> /// <param name="function"> /// The <see cref="SQLiteFunction"/> object instance that implements the /// function to be bound. /// </param> /// <param name="flags"> /// The flags associated with the parent connection object. /// </param> /// <returns>Non-zero if the function was unbound.</returns> internal static bool UnbindFunction( SQLiteBase sqliteBase, SQLiteFunctionAttribute functionAttribute, SQLiteFunction function, SQLiteConnectionFlags flags /* NOT USED */ ) { if (sqliteBase == null) throw new ArgumentNullException("sqliteBase"); if (functionAttribute == null) throw new ArgumentNullException("functionAttribute"); if (function == null) throw new ArgumentNullException("function"); FunctionType functionType = functionAttribute.FuncType; string name = functionAttribute.Name; if (functionType != FunctionType.Collation) { bool needCollSeq = (function is SQLiteFunctionEx); return sqliteBase.CreateFunction( name, functionAttribute.Arguments, needCollSeq, null, null, null, false) == SQLiteErrorCode.Ok; } else { return sqliteBase.CreateCollation( name, null, null, false) == SQLiteErrorCode.Ok; } }
/// <summary> /// This function binds a user-defined functions to a connection. /// </summary> /// <param name="sqliteBase"> /// The <see cref="SQLiteBase" /> object instance associated with the /// <see cref="SQLiteConnection" /> that the function should be bound to. /// </param> /// <param name="functionAttribute"> /// The <see cref="SQLiteFunctionAttribute"/> object instance containing /// the metadata for the function to be bound. /// </param> /// <param name="function"> /// The <see cref="SQLiteFunction"/> object instance that implements the /// function to be bound. /// </param> /// <param name="flags"> /// The flags associated with the parent connection object. /// </param> internal static void BindFunction( SQLiteBase sqliteBase, SQLiteFunctionAttribute functionAttribute, SQLiteFunction function, SQLiteConnectionFlags flags ) { if (sqliteBase == null) throw new ArgumentNullException("sqliteBase"); if (functionAttribute == null) throw new ArgumentNullException("functionAttribute"); if (function == null) throw new ArgumentNullException("function"); FunctionType functionType = functionAttribute.FuncType; function._base = sqliteBase; function._flags = flags; function._InvokeFunc = (functionType == FunctionType.Scalar) ? new SQLiteCallback(function.ScalarCallback) : null; function._StepFunc = (functionType == FunctionType.Aggregate) ? new SQLiteCallback(function.StepCallback) : null; function._FinalFunc = (functionType == FunctionType.Aggregate) ? new SQLiteFinalCallback(function.FinalCallback) : null; function._CompareFunc = (functionType == FunctionType.Collation) ? new SQLiteCollation(function.CompareCallback) : null; function._CompareFunc16 = (functionType == FunctionType.Collation) ? new SQLiteCollation(function.CompareCallback16) : null; string name = functionAttribute.Name; if (functionType != FunctionType.Collation) { bool needCollSeq = (function is SQLiteFunctionEx); sqliteBase.CreateFunction( name, functionAttribute.Arguments, needCollSeq, function._InvokeFunc, function._StepFunc, function._FinalFunc); } else { sqliteBase.CreateCollation( name, function._CompareFunc, function._CompareFunc16); } }
/// <summary> /// Issued after the base connection is closed, this function cleans up all user-defined functions and disposes of them. /// </summary> /// <remarks> /// Cleaning up here is done mainly because of the interop wrapper. It allocated memory to hold a reference to all the /// delegates, and now must free that memory. /// Freeing is done after the connection is closed to ensure no callbacks get hit after we've freed the cookie. /// </remarks> /// <param name="sqlbase">The base SQLite connection object</param> /// <param name="ar">An array of user-defined functions for this object</param> internal static void UnbindFunctions(SQLiteBase sqlbase, SQLiteFunction[] ar) { if (ar == null) return; int x = ar.Length; for (int n = 0; n < x; n++) { sqlbase.FreeFunction(ar[n]._interopCookie); ar[n].Dispose(); } }
/// <summary> /// Called by the SQLiteBase derived classes, this method binds all registered (known) user-defined functions to a connection. /// It is done this way so that all user-defined functions will access the database using the same encoding scheme /// as the connection (UTF-8 or UTF-16). /// </summary> /// <remarks> /// The wrapper functions that interop with SQLite will create a unique cookie value, which internally is a pointer to /// all the wrapped callback functions. The interop function uses it to map CDecl callbacks to StdCall callbacks. /// </remarks> /// <param name="sqlbase">The base object on which the functions are to bind.</param> /// <param name="flags">The flags associated with the parent connection object.</param> /// <returns>Returns a logical list of functions which the connection should retain until it is closed.</returns> internal static IDictionary<SQLiteFunctionAttribute, SQLiteFunction> BindFunctions( SQLiteBase sqlbase, SQLiteConnectionFlags flags ) { IDictionary<SQLiteFunctionAttribute, SQLiteFunction> lFunctions = new Dictionary<SQLiteFunctionAttribute, SQLiteFunction>(); foreach (KeyValuePair<SQLiteFunctionAttribute, object> pair in _registeredFunctions) { SQLiteFunctionAttribute pr = pair.Key; if (pr == null) continue; SQLiteFunction f; if (CreateFunction(pr, out f)) { BindFunction(sqlbase, pr, f, flags); lFunctions[pr] = f; } else { lFunctions[pr] = null; } } return lFunctions; }
/// <summary> /// Disposes of any active contextData variables that were not automatically cleaned up. Sometimes this can happen if /// someone closes the connection while a DataReader is open. /// </summary> public void Dispose() { Dispose(true); IDisposable disp; foreach (KeyValuePair<long, object> kv in _contextDataList) { disp = kv.Value as IDisposable; if (disp != null) disp.Dispose(); } _contextDataList.Clear(); _InvokeFunc = null; _StepFunc = null; _FinalFunc = null; _CompareFunc = null; _base = null; _contextDataList = null; GC.SuppressFinalize(this); }
/////////////////////////////////////////////////////////////////////////////////////////////// private void SetupSQLiteBase(SortedList<string, string> opts) { object enumValue; enumValue = TryParseEnum( typeof(SQLiteDateFormats), FindKey(opts, "DateTimeFormat", DefaultDateTimeFormat.ToString()), true); SQLiteDateFormats dateFormat = (enumValue is SQLiteDateFormats) ? (SQLiteDateFormats)enumValue : DefaultDateTimeFormat; enumValue = TryParseEnum( typeof(DateTimeKind), FindKey(opts, "DateTimeKind", DefaultDateTimeKind.ToString()), true); DateTimeKind kind = (enumValue is DateTimeKind) ? (DateTimeKind)enumValue : DefaultDateTimeKind; string dateTimeFormat = FindKey(opts, "DateTimeFormatString", DefaultDateTimeFormatString); // // NOTE: SQLite automatically sets the encoding of the database // to UTF16 if called from sqlite3_open16(). // if (SQLiteConvert.ToBoolean(FindKey(opts, "UseUTF16Encoding", DefaultUseUTF16Encoding.ToString()))) { _sql = new SQLite3_UTF16( dateFormat, kind, dateTimeFormat, IntPtr.Zero, null, false); } else { _sql = new SQLite3( dateFormat, kind, dateTimeFormat, IntPtr.Zero, null, false); } }
/////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Placeholder for a user-defined disposal routine /// </summary> /// <param name="disposing">True if the object is being disposed explicitly</param> protected virtual void Dispose(bool disposing) { if (!disposed) { if (disposing) { //////////////////////////////////// // dispose managed resources here... //////////////////////////////////// IDisposable disp; foreach (KeyValuePair<IntPtr, AggregateData> kv in _contextDataList) { disp = kv.Value._data as IDisposable; if (disp != null) disp.Dispose(); } _contextDataList.Clear(); _contextDataList = null; _flags = SQLiteConnectionFlags.None; _InvokeFunc = null; _StepFunc = null; _FinalFunc = null; _CompareFunc = null; _base = null; } ////////////////////////////////////// // release unmanaged resources here... ////////////////////////////////////// disposed = true; } }
/// <summary> /// When the database connection is closed, all commands linked to this connection are automatically reset. /// </summary> public override void Close() { CheckDisposed(); if (_sql != null) { #if !PLATFORM_COMPACTFRAMEWORK if (_enlistment != null) { // If the connection is enlisted in a transaction scope and the scope is still active, // we cannot truly shut down this connection until the scope has completed. Therefore make a // hidden connection temporarily to hold open the connection until the scope has completed. SQLiteConnection cnn = new SQLiteConnection(); cnn._sql = _sql; cnn._transactionLevel = _transactionLevel; cnn._enlistment = _enlistment; cnn._connectionState = _connectionState; cnn._version = _version; cnn._enlistment._transaction._cnn = cnn; cnn._enlistment._disposeConnection = true; _sql = null; _enlistment = null; } #endif if (_sql != null) { _sql.Close(); _sql = null; } _transactionLevel = 0; } OnStateChange(ConnectionState.Closed); }
/// <summary> /// Verifies that all SQL queries associated with the current command text /// can be successfully compiled. A <see cref="SQLiteException" /> will be /// raised if any errors occur. /// </summary> public void VerifyOnly() { CheckDisposed(); SQLiteConnection connection = _cnn; SQLiteConnection.Check(connection); /* throw */ SQLiteBase sqlBase = connection._sql; if ((connection == null) || (sqlBase == null)) { throw new SQLiteException("invalid or unusable connection"); } List <SQLiteStatement> statements = null; SQLiteStatement currentStatement = null; try { string text = _commandText; uint timeout = (uint)(_commandTimeout * 1000); SQLiteStatement previousStatement = null; while ((text != null) && (text.Length > 0)) { currentStatement = sqlBase.Prepare( connection, text, previousStatement, timeout, ref text); /* throw */ previousStatement = currentStatement; if (currentStatement != null) { if (statements == null) { statements = new List <SQLiteStatement>(); } statements.Add(currentStatement); currentStatement = null; } if (text == null) { continue; } text = text.Trim(); } } finally { if (currentStatement != null) { currentStatement.Dispose(); currentStatement = null; } if (statements != null) { foreach (SQLiteStatement statement in statements) { if (statement == null) { continue; } statement.Dispose(); } statements.Clear(); statements = null; } } }
/// <summary> /// Opens the connection using the parameters found in the <see cref="ConnectionString">ConnectionString</see> /// </summary> public override void Open() { if (_connectionState != ConnectionState.Closed) throw new InvalidOperationException(); Close(); KeyValuePair<string, string>[] opts = ParseConnectionString(); string fileName; if (Convert.ToInt32(FindKey(opts, "Version", "3"), CultureInfo.InvariantCulture) != 3) throw new NotSupportedException("Only SQLite Version 3 is supported at this time"); fileName = FindKey(opts, "Data Source", ""); if (String.IsNullOrEmpty(fileName)) throw new ArgumentException("Data Source cannot be empty. Use :memory: to open an in-memory database"); if (String.Compare(fileName, ":MEMORY:", true, CultureInfo.InvariantCulture) == 0) fileName = ":memory:"; #if PLATFORM_COMPACTFRAMEWORK else if (fileName.StartsWith(".\\")) fileName = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetCallingAssembly().GetName().CodeBase) + fileName.Substring(1); #endif try { bool bUTF16 = (Convert.ToBoolean(FindKey(opts, "UseUTF16Encoding", "False"), CultureInfo.InvariantCulture) == true); SQLiteDateFormats dateFormat = String.Compare(FindKey(opts, "DateTimeFormat", "ISO8601"), "ticks", true, CultureInfo.InvariantCulture) == 0 ? SQLiteDateFormats.Ticks : SQLiteDateFormats.ISO8601; if (bUTF16) // SQLite automatically sets the encoding of the database to UTF16 if called from sqlite3_open16() _sql = new SQLite3_UTF16(dateFormat); else _sql = new SQLite3(dateFormat); fileName = ExpandFileName(fileName); try { if (IO.File.Exists(fileName) == false) throw new IO.FileNotFoundException(String.Format(CultureInfo.CurrentCulture, "Unable to locate file \"{0}\", creating new database.", fileName)); } catch { } _sql.Open(fileName); string password = FindKey(opts, "Password", null); if (String.IsNullOrEmpty(password) == false) _sql.SetPassword(System.Text.UTF8Encoding.UTF8.GetBytes(password)); else if (_password != null) _sql.SetPassword(_password); _password = null; _dataSource = System.IO.Path.GetFileNameWithoutExtension(fileName); OnStateChange(ConnectionState.Open); using (SQLiteCommand cmd = CreateCommand()) { string defValue; defValue = FindKey(opts, "Synchronous", "Normal"); if (String.Compare(defValue, "Normal", true, CultureInfo.InvariantCulture) != 0) { cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA Synchronous={0}", defValue); cmd.ExecuteNonQuery(); } defValue = FindKey(opts, "Cache Size", "2000"); if (Convert.ToInt32(defValue) != 2000) { cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA Cache_Size={0}", defValue); cmd.ExecuteNonQuery(); } if (fileName != ":memory:") { defValue = FindKey(opts, "Page Size", "1024"); if (Convert.ToInt32(defValue) != 1024) { cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA Page_Size={0}", defValue); cmd.ExecuteNonQuery(); } } } #if !PLATFORM_COMPACTFRAMEWORK if (FindKey(opts, "Enlist", "Y").ToUpper()[0] == 'Y' && Transactions.Transaction.Current != null) EnlistTransaction(Transactions.Transaction.Current); #endif } catch (SQLiteException) { OnStateChange(ConnectionState.Broken); throw; } }
/// Passes a shutdown request off to SQLite. public int Shutdown() { CheckDisposed(); // make sure we have an instance of the base class if (_sql == null) { SortedList<string, string> opts = ParseConnectionString(_connectionString); bool bUTF16 = (SQLiteConvert.ToBoolean(FindKey(opts, "UseUTF16Encoding", Boolean.FalseString)) == true); SQLiteDateFormats dateFormat = (SQLiteDateFormats)Enum.Parse(typeof(SQLiteDateFormats), FindKey(opts, "DateTimeFormat", "ISO8601"), true); DateTimeKind kind = (DateTimeKind)Enum.Parse(typeof(DateTimeKind), FindKey(opts, "DateTimeKind", "Unspecified"), true); if (bUTF16) // SQLite automatically sets the encoding of the database to UTF16 if called from sqlite3_open16() _sql = new SQLite3_UTF16(dateFormat, kind); else _sql = new SQLite3(dateFormat, kind); } if (_sql != null) return _sql.Shutdown(); throw new InvalidOperationException("Database connection not active."); }
/// <summary> /// Initializes the SQLite logging facilities. /// </summary> public static void Initialize() { // // BUFXIX: We cannot initialize the logging interface if the SQLite // core library has already been initialized anywhere in // the process (see ticket [2ce0870fad]). // if (SQLite3.StaticIsInitialized()) return; // // BUGFIX: To avoid nasty situations where multiple AppDomains are // attempting to initialize and/or shutdown what is really // a shared native resource (i.e. the SQLite core library // is loaded per-process and has only one logging callback, // not one per-AppDomain, which it knows nothing about), // prevent all non-default AppDomains from registering a // log handler unless the "Force_SQLiteLog" environment // variable is used to manually override this safety check. // if (!AppDomain.CurrentDomain.IsDefaultAppDomain() && Environment.GetEnvironmentVariable("Force_SQLiteLog") == null) { return; } lock (syncRoot) { // // NOTE: Add an event handler for the DomainUnload event so // that we can unhook our logging managed function // pointer from the native SQLite code prior to it // being invalidated. // // BUGFIX: Make sure this event handler is only added one // time (per-AppDomain). // if (_domainUnload == null) { _domainUnload = new EventHandler(DomainUnload); AppDomain.CurrentDomain.DomainUnload += _domainUnload; } // // NOTE: Create an instance of the SQLite wrapper class. // if (_sql == null) _sql = new SQLite3(SQLiteDateFormats.Default, DateTimeKind.Unspecified); // // NOTE: Create a single "global" (i.e. per-process) callback // to register with SQLite. This callback will pass the // event on to any registered handler. We only want to // do this once. // if (_callback == null) { _callback = new SQLiteLogCallback(LogCallback); int rc = _sql.SetLogCallback(_callback); if (rc != 0) throw new SQLiteException(rc, "Failed to initialize logging."); } // // NOTE: Logging is enabled by default. // _enabled = true; // // NOTE: For now, always setup the default log event handler. // AddDefaultHandler(); } }
/// <summary> /// Opens the connection using the parameters found in the <see cref="ConnectionString">ConnectionString</see> /// </summary> public override void Open() { CheckDisposed(); if (_connectionState != ConnectionState.Closed) throw new InvalidOperationException(); Close(); SortedList<string, string> opts = ParseConnectionString(_connectionString); _flags = (SQLiteConnectionFlags)Enum.Parse(typeof(SQLiteConnectionFlags), FindKey(opts, "Flags", "Default"), true); string fileName; if (Convert.ToInt32(FindKey(opts, "Version", "3"), CultureInfo.InvariantCulture) != 3) throw new NotSupportedException("Only SQLite Version 3 is supported at this time"); fileName = FindKey(opts, "Data Source", ""); if (String.IsNullOrEmpty(fileName)) { fileName = FindKey(opts, "Uri", ""); if (String.IsNullOrEmpty(fileName)) throw new ArgumentException("Data Source cannot be empty. Use :memory: to open an in-memory database"); else fileName = MapUriPath(fileName); } if (String.Compare(fileName, ":MEMORY:", StringComparison.OrdinalIgnoreCase) == 0) fileName = ":memory:"; else { #if PLATFORM_COMPACTFRAMEWORK if (fileName.StartsWith("./") || fileName.StartsWith(".\\")) fileName = Path.GetDirectoryName(System.Reflection.Assembly.GetCallingAssembly().GetName().CodeBase) + fileName.Substring(1); #endif fileName = ExpandFileName(fileName); } try { bool usePooling = (SQLiteConvert.ToBoolean(FindKey(opts, "Pooling", Boolean.FalseString)) == true); int maxPoolSize = Convert.ToInt32(FindKey(opts, "Max Pool Size", "100"), CultureInfo.InvariantCulture); _defaultTimeout = Convert.ToInt32(FindKey(opts, "Default Timeout", "30"), CultureInfo.CurrentCulture); _defaultIsolation = (IsolationLevel)Enum.Parse(typeof(IsolationLevel), FindKey(opts, "Default IsolationLevel", "Serializable"), true); if (_defaultIsolation != IsolationLevel.Serializable && _defaultIsolation != IsolationLevel.ReadCommitted) throw new NotSupportedException("Invalid Default IsolationLevel specified"); _baseSchemaName = FindKey(opts, "BaseSchemaName", DefaultBaseSchemaName); //string temp = FindKey(opts, "DateTimeFormat", "ISO8601"); //if (String.Compare(temp, "ticks", StringComparison.OrdinalIgnoreCase) == 0) dateFormat = SQLiteDateFormats.Ticks; //else if (String.Compare(temp, "julianday", StringComparison.OrdinalIgnoreCase) == 0) dateFormat = SQLiteDateFormats.JulianDay; if (_sql == null) { bool bUTF16 = (SQLiteConvert.ToBoolean(FindKey(opts, "UseUTF16Encoding", Boolean.FalseString)) == true); SQLiteDateFormats dateFormat = (SQLiteDateFormats)Enum.Parse(typeof(SQLiteDateFormats), FindKey(opts, "DateTimeFormat", "ISO8601"), true); DateTimeKind kind = (DateTimeKind)Enum.Parse(typeof(DateTimeKind), FindKey(opts, "DateTimeKind", "Unspecified"), true); if (bUTF16) // SQLite automatically sets the encoding of the database to UTF16 if called from sqlite3_open16() _sql = new SQLite3_UTF16(dateFormat, kind); else _sql = new SQLite3(dateFormat, kind); } SQLiteOpenFlagsEnum flags = SQLiteOpenFlagsEnum.None; if (SQLiteConvert.ToBoolean(FindKey(opts, "FailIfMissing", Boolean.FalseString)) == false) flags |= SQLiteOpenFlagsEnum.Create; if (SQLiteConvert.ToBoolean(FindKey(opts, "Read Only", Boolean.FalseString)) == true) { flags |= SQLiteOpenFlagsEnum.ReadOnly; // SQLite will return SQLITE_MISUSE on ReadOnly and Create flags &= ~SQLiteOpenFlagsEnum.Create; } else { flags |= SQLiteOpenFlagsEnum.ReadWrite; } _sql.Open(fileName, _flags, flags, maxPoolSize, usePooling); _binaryGuid = (SQLiteConvert.ToBoolean(FindKey(opts, "BinaryGUID", Boolean.TrueString)) == true); string password = FindKey(opts, "Password", null); if (String.IsNullOrEmpty(password) == false) _sql.SetPassword(System.Text.UTF8Encoding.UTF8.GetBytes(password)); else if (_password != null) _sql.SetPassword(_password); _password = null; _dataSource = Path.GetFileNameWithoutExtension(fileName); _version++; ConnectionState oldstate = _connectionState; _connectionState = ConnectionState.Open; try { using (SQLiteCommand cmd = CreateCommand()) { string defValue; if (fileName != ":memory:") { defValue = FindKey(opts, "Page Size", "1024"); if (Convert.ToInt32(defValue, CultureInfo.InvariantCulture) != 1024) { cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA page_size={0}", defValue); cmd.ExecuteNonQuery(); } } defValue = FindKey(opts, "Max Page Count", "0"); if (Convert.ToInt32(defValue, CultureInfo.InvariantCulture) != 0) { cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA max_page_count={0}", defValue); cmd.ExecuteNonQuery(); } defValue = FindKey(opts, "Legacy Format", Boolean.FalseString); cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA legacy_file_format={0}", SQLiteConvert.ToBoolean(defValue) == true ? "ON" : "OFF"); cmd.ExecuteNonQuery(); defValue = FindKey(opts, "Synchronous", "Normal"); if (String.Compare(defValue, "Full", StringComparison.OrdinalIgnoreCase) != 0) { cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA synchronous={0}", defValue); cmd.ExecuteNonQuery(); } defValue = FindKey(opts, "Cache Size", "2000"); if (Convert.ToInt32(defValue, CultureInfo.InvariantCulture) != 2000) { cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA cache_size={0}", defValue); cmd.ExecuteNonQuery(); } defValue = FindKey(opts, "Journal Mode", "Default"); if (String.Compare(defValue, "Default", StringComparison.OrdinalIgnoreCase) != 0) { cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA journal_mode={0}", defValue); cmd.ExecuteNonQuery(); } defValue = FindKey(opts, "Foreign Keys", Boolean.FalseString); cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA foreign_keys={0}", SQLiteConvert.ToBoolean(defValue) == true ? "ON" : "OFF"); cmd.ExecuteNonQuery(); } if (_commitHandler != null) _sql.SetCommitHook(_commitCallback); if (_updateHandler != null) _sql.SetUpdateHook(_updateCallback); if (_rollbackHandler != null) _sql.SetRollbackHook(_rollbackCallback); #if !PLATFORM_COMPACTFRAMEWORK if (Transactions.Transaction.Current != null && SQLiteConvert.ToBoolean(FindKey(opts, "Enlist", Boolean.TrueString)) == true) EnlistTransaction(Transactions.Transaction.Current); #endif _connectionState = oldstate; OnStateChange(ConnectionState.Open); } catch { _connectionState = oldstate; throw; } } catch (SQLiteException) { Close(); throw; } }
/// <summary> /// Initializes the SQLite logging facilities. /// </summary> public static void Initialize() { // // BUFXIX: We cannot initialize the logging interface if the SQLite // core library has already been initialized anywhere in // the process (see ticket [2ce0870fad]). // if (SQLite3.StaticIsInitialized()) { return; } // // BUGFIX: To avoid nasty situations where multiple AppDomains are // attempting to initialize and/or shutdown what is really // a shared native resource (i.e. the SQLite core library // is loaded per-process and has only one logging callback, // not one per-AppDomain, which it knows nothing about), // prevent all non-default AppDomains from registering a // log handler unless the "Force_SQLiteLog" environment // variable is used to manually override this safety check. // if (!AppDomain.CurrentDomain.IsDefaultAppDomain() && Environment.GetEnvironmentVariable("Force_SQLiteLog") == null) { return; } lock (syncRoot) { // // NOTE: Add an event handler for the DomainUnload event so // that we can unhook our logging managed function // pointer from the native SQLite code prior to it // being invalidated. // // BUGFIX: Make sure this event handler is only added one // time (per-AppDomain). // if (_domainUnload == null) { _domainUnload = new EventHandler(DomainUnload); AppDomain.CurrentDomain.DomainUnload += _domainUnload; } // // NOTE: Create an instance of the SQLite wrapper class. // if (_sql == null) { _sql = new SQLite3(SQLiteDateFormats.Default, DateTimeKind.Unspecified); } // // NOTE: Create a single "global" (i.e. per-process) callback // to register with SQLite. This callback will pass the // event on to any registered handler. We only want to // do this once. // if (_callback == null) { _callback = new SQLiteLogCallback(LogCallback); SQLiteErrorCode rc = _sql.SetLogCallback(_callback); if (rc != SQLiteErrorCode.Ok) { throw new SQLiteException(rc, "Failed to initialize logging."); } } // // NOTE: Logging is enabled by default. // _enabled = true; // // NOTE: For now, always setup the default log event handler. // AddDefaultHandler(); } }
/// <summary> /// Called by SQLiteBase derived classes, this function binds all user-defined functions to a connection. /// It is done this way so that all user-defined functions will access the database using the same encoding scheme /// as the connection (UTF-8 or UTF-16). /// </summary> /// <remarks> /// The wrapper functions that interop with SQLite will create a unique cookie value, which internally is a pointer to /// all the wrapped callback functions. The interop function uses it to map CDecl callbacks to StdCall callbacks. /// </remarks> /// <param name="sqlbase">The base object on which the functions are to bind</param> /// <param name="flags">The flags associated with the parent connection object</param> /// <returns>Returns an array of functions which the connection object should retain until the connection is closed.</returns> internal static SQLiteFunction[] BindFunctions(SQLiteBase sqlbase, SQLiteConnectionFlags flags) { SQLiteFunction f; List<SQLiteFunction> lFunctions = new List<SQLiteFunction>(); foreach (SQLiteFunctionAttribute pr in _registeredFunctions) { f = (SQLiteFunction)Activator.CreateInstance(pr._instanceType); f._base = sqlbase; f._flags = flags; f._InvokeFunc = (pr.FuncType == FunctionType.Scalar) ? new SQLiteCallback(f.ScalarCallback) : null; f._StepFunc = (pr.FuncType == FunctionType.Aggregate) ? new SQLiteCallback(f.StepCallback) : null; f._FinalFunc = (pr.FuncType == FunctionType.Aggregate) ? new SQLiteFinalCallback(f.FinalCallback) : null; f._CompareFunc = (pr.FuncType == FunctionType.Collation) ? new SQLiteCollation(f.CompareCallback) : null; f._CompareFunc16 = (pr.FuncType == FunctionType.Collation) ? new SQLiteCollation(f.CompareCallback16) : null; if (pr.FuncType != FunctionType.Collation) sqlbase.CreateFunction(pr.Name, pr.Arguments, (f is SQLiteFunctionEx), f._InvokeFunc, f._StepFunc, f._FinalFunc); else sqlbase.CreateCollation(pr.Name, f._CompareFunc, f._CompareFunc16); lFunctions.Add(f); } SQLiteFunction[] arFunctions = new SQLiteFunction[lFunctions.Count]; lFunctions.CopyTo(arFunctions, 0); return arFunctions; }
/// <summary> /// Initializes the connection with the specified connection string /// </summary> /// <param name="connectionString">The connection string to use on the connection</param> public SQLiteConnection(string connectionString) { _sql = null; _connectionState = ConnectionState.Closed; _connectionString = ""; _transactionLevel = 0; _commandList = new List<SQLiteCommand>(); if (connectionString != null) ConnectionString = connectionString; }