/// <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> /// <param name="sqlbase">The base object on which the functions are to bind</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) { SqliteFunction f; List <SqliteFunction> lFunctions = new List <SqliteFunction>(); foreach (SqliteFunctionAttribute pr in _registeredFunctions) { f = (SqliteFunction)Activator.CreateInstance(pr._instanceType); f._base = sqlbase; 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; if (pr.FuncType != FunctionType.Collation) { sqlbase.CreateFunction(pr.Name, pr.Arguments, f._InvokeFunc, f._StepFunc, f._FinalFunc); } else { sqlbase.CreateCollation(pr.Name, f._CompareFunc); } lFunctions.Add(f); } SqliteFunction[] arFunctions = new SqliteFunction[lFunctions.Count]; lFunctions.CopyTo(arFunctions, 0); return(arFunctions); }
/// <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); }
/// <summary> /// Disposes and finalizes the statement /// </summary> public void Dispose() { _sql.FinalizeStatement(this); _paramNames = null; _paramValues = null; _sql = null; _sqlStatement = null; GC.SuppressFinalize(this); }
/// <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="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, IntPtr stmt, string strCommand, SqliteStatement previous) { _sql = sqlbase; _sqlite_stmt = stmt; _sqlStatement = strCommand; // Determine parameters for this statement (if any) and prepare space for them. int nCmdStart = 0; int n = _sql.Bind_ParamCount(this); 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, x + 1); if (String.IsNullOrEmpty(s)) { s = String.Format(CultureInfo.InvariantCulture, ";{0}", nCmdStart); nCmdStart++; _unnamedParameters++; } _paramNames[x] = s; _paramValues[x] = 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 string bt = FindKey (opts, "busy_timeout", "30"); try { _busyTimeout = Int32.Parse (bt); } catch (Exception) { // ignore } 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 (System.IO.File.Exists(fileName) == false) throw new System.IO.FileNotFoundException(String.Format(CultureInfo.CurrentCulture, "Unable to locate file \"{0}\", creating new database.", fileName)); } catch { } _sql.Open(fileName); _binaryGuid = (Convert.ToBoolean(FindKey(opts, "BinaryGUID", "True"), CultureInfo.InvariantCulture) == true); #if MONO_SUPPORT_PASSWORDS // Not used under mono now 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; #endif _dataSource = System.IO.Path.GetFileNameWithoutExtension(fileName); OnStateChange(ConnectionState.Open); _version++; 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' && System.Transactions.Transaction.Current != null) EnlistTransaction(System.Transactions.Transaction.Current); #endif } catch (SqliteException) { OnStateChange(ConnectionState.Broken); throw; } }
/// <summary> /// When the database connection is closed, all commands linked to this connection are automatically reset. /// </summary> public override void Close() { if (_sql != null) { // Force any commands associated with this connection to release their unmanaged // resources. The commands are still valid and will automatically re-acquire the // unmanaged resources the next time they are run -- provided this connection is // re-opened before then. lock (_commandList) { foreach (SqliteCommand cmd in _commandList) cmd.ClearCommands(); } #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; } else { _sql.Close(); } _enlistment = null; #else _sql.Close(); #endif _sql = null; _transactionLevel = 0; } OnStateChange(ConnectionState.Closed); }
/// <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; _busyTimeout = 30; _version = 0; _commandList = new List<SqliteCommand>(); if (connectionString != null) ConnectionString = connectionString; }
/// <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> /// <param name="sqlbase">The base object on which the functions are to bind</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) { SqliteFunction f; List<SqliteFunction> lFunctions = new List<SqliteFunction>(); foreach (SqliteFunctionAttribute pr in _registeredFunctions) { f = (SqliteFunction)Activator.CreateInstance(pr._instanceType); f._base = sqlbase; 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; if (pr.FuncType != FunctionType.Collation) sqlbase.CreateFunction(pr.Name, pr.Arguments, f._InvokeFunc, f._StepFunc, f._FinalFunc); else sqlbase.CreateCollation(pr.Name, f._CompareFunc); lFunctions.Add(f); } SqliteFunction[] arFunctions = new SqliteFunction[lFunctions.Count]; lFunctions.CopyTo(arFunctions, 0); return arFunctions; }
/// <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); }
/// <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="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, IntPtr stmt, string strCommand, SqliteStatement previous) { _sql = sqlbase; _sqlite_stmt = stmt; _sqlStatement = strCommand; // Determine parameters for this statement (if any) and prepare space for them. int nCmdStart = 0; int n = _sql.Bind_ParamCount(this); 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, x + 1); if (String.IsNullOrEmpty(s)) { s = String.Format(CultureInfo.InvariantCulture, ";{0}", nCmdStart); nCmdStart++; _unnamedParameters++; } _paramNames[x] = s; _paramValues[x] = null; } } }
/// <summary> /// Disposes and finalizes the statement /// </summary> public void Dispose() { _sql.FinalizeStatement(this); _paramNames = null; _paramValues = null; _sql = null; _sqlStatement = null; GC.SuppressFinalize(this); }