/******************************************************** * ADO.NET 2.0 Data Provider for SQLite Version 3.X * Written by Robert Simpson (robert@blackcastlesoft.com) * * Released to the public domain, use at your own risk! ********************************************************/ namespace System.Data.SQLite { using System; using System.Collections.Generic; #if !PLATFORM_COMPACTFRAMEWORK using System.Runtime.InteropServices; #endif /// /// This internal class provides the foundation of SQLite support. It defines all the abstract members needed to implement /// a SQLite data provider, and inherits from SQLiteConvert which allows for simple translations of string to and from SQLite. /// internal abstract class SQLiteBase : SQLiteConvert, IDisposable { #region Private Constants /// /// The error code used for logging exceptions caught in user-provided /// code. /// internal const int COR_E_EXCEPTION = unchecked((int)0x80131500); #endregion ///////////////////////////////////////////////////////////////////////// internal SQLiteBase(SQLiteDateFormats fmt, DateTimeKind kind, string fmtString) : base(fmt, kind, fmtString) { } /// /// Returns a string representing the active version of SQLite /// internal abstract string Version { get; } /// /// Returns an integer representing the active version of SQLite /// internal abstract int VersionNumber { get; } /// /// Returns non-zero if this connection to the database is read-only. /// internal abstract bool IsReadOnly(string name); /// /// Returns the rowid of the most recent successful INSERT into the database from this connection. /// internal abstract long LastInsertRowId { get; } /// /// Returns the number of changes the last executing insert/update caused. /// internal abstract int Changes { get; } /// /// Returns the amount of memory (in bytes) currently in use by the SQLite core library. This is not really a per-connection /// value, it is global to the process. /// internal abstract long MemoryUsed { get; } /// /// Returns the maximum amount of memory (in bytes) used by the SQLite core library since the high-water mark was last reset. /// This is not really a per-connection value, it is global to the process. /// internal abstract long MemoryHighwater { get; } /// /// Returns non-zero if the underlying native connection handle is owned by this instance. /// internal abstract bool OwnHandle { get; } /// /// Returns the logical list of functions associated with this connection. /// internal abstract IDictionary Functions { get; } /// /// Sets the status of the memory usage tracking subsystem in the SQLite core library. By default, this is enabled. /// If this is disabled, memory usage tracking will not be performed. This is not really a per-connection value, it is /// global to the process. /// /// Non-zero to enable memory usage tracking, zero otherwise. /// A standard SQLite return code (i.e. zero for success and non-zero for failure). internal abstract SQLiteErrorCode SetMemoryStatus(bool value); /// /// Attempts to free as much heap memory as possible for the database connection. /// /// A standard SQLite return code (i.e. zero for success and non-zero for failure). internal abstract SQLiteErrorCode ReleaseMemory(); /// /// Shutdown the SQLite engine so that it can be restarted with different config options. /// We depend on auto initialization to recover. /// internal abstract SQLiteErrorCode Shutdown(); /// /// Determines if the associated native connection handle is open. /// /// /// Non-zero if a database connection is open. /// internal abstract bool IsOpen(); /// /// Returns the fully qualified path and file name for the currently open /// database, if any. /// /// /// The name of the attached database to query. /// /// /// The fully qualified path and file name for the currently open database, /// if any. /// internal abstract string GetFileName(string dbName); /// /// Opens a database. /// /// /// Implementers should call SQLiteFunction.BindFunctions() and save the array after opening a connection /// to bind all attributed user-defined functions and collating sequences to the new connection. /// /// The filename of the database to open. SQLite automatically creates it if it doesn't exist. /// The name of the VFS to use -OR- null to use the default VFS. /// The flags associated with the parent connection object /// The open flags to use when creating the connection /// The maximum size of the pool for the given filename /// If true, the connection can be pulled from the connection pool internal abstract void Open(string strFilename, string vfsName, SQLiteConnectionFlags connectionFlags, SQLiteOpenFlagsEnum openFlags, int maxPoolSize, bool usePool); /// /// Closes the currently-open database. /// /// /// After the database has been closed implemeters should call SQLiteFunction.UnbindFunctions() to deallocate all interop allocated /// memory associated with the user-defined functions and collating sequences tied to the closed connection. /// /// Non-zero if connection is being disposed, zero otherwise. internal abstract void Close(bool disposing); /// /// Sets the busy timeout on the connection. SQLiteCommand will call this before executing any command. /// /// The number of milliseconds to wait before returning SQLITE_BUSY internal abstract void SetTimeout(int nTimeoutMS); /// /// Returns the text of the last error issued by SQLite /// /// internal abstract string GetLastError(); /// /// Returns the text of the last error issued by SQLite -OR- the specified default error text if /// none is available from the SQLite core library. /// /// /// The error text to return in the event that one is not available from the SQLite core library. /// /// /// The error text. /// internal abstract string GetLastError(string defValue); /// /// When pooling is enabled, force this connection to be disposed rather than returned to the pool /// internal abstract void ClearPool(); /// /// When pooling is enabled, returns the number of pool entries matching the current file name. /// /// The number of pool entries matching the current file name. internal abstract int CountPool(); /// /// Prepares a SQL statement for execution. /// /// The source connection preparing the command. Can be null for any caller except LINQ /// The SQL command text to prepare /// The previous statement in a multi-statement command, or null if no previous statement exists /// The timeout to wait before aborting the prepare /// The remainder of the statement that was not processed. Each call to prepare parses the /// SQL up to to either the end of the text or to the first semi-colon delimiter. The remaining text is returned /// here for a subsequent call to Prepare() until all the text has been processed. /// Returns an initialized SQLiteStatement. internal abstract SQLiteStatement Prepare(SQLiteConnection cnn, string strSql, SQLiteStatement previous, uint timeoutMS, ref string strRemain); /// /// Steps through a prepared statement. /// /// The SQLiteStatement to step through /// True if a row was returned, False if not. internal abstract bool Step(SQLiteStatement stmt); /// /// Returns non-zero if the specified statement is read-only in nature. /// /// The statement to check. /// True if the outer query is read-only. internal abstract bool IsReadOnly(SQLiteStatement stmt); /// /// Resets a prepared statement so it can be executed again. If the error returned is SQLITE_SCHEMA, /// transparently attempt to rebuild the SQL statement and throw an error if that was not possible. /// /// The statement to reset /// Returns -1 if the schema changed while resetting, 0 if the reset was sucessful or 6 (SQLITE_LOCKED) if the reset failed due to a lock internal abstract SQLiteErrorCode Reset(SQLiteStatement stmt); /// /// Attempts to interrupt the query currently executing on the associated /// native database connection. /// internal abstract void Cancel(); /// /// This function binds a user-defined function to the connection. /// /// /// The object instance containing /// the metadata for the function to be bound. /// /// /// The object instance that implements the /// function to be bound. /// /// /// The flags associated with the parent connection object. /// internal abstract void BindFunction(SQLiteFunctionAttribute functionAttribute, SQLiteFunction function, SQLiteConnectionFlags flags); /// /// This function unbinds a user-defined function from the connection. /// /// /// The object instance containing /// the metadata for the function to be unbound. /// /// /// The flags associated with the parent connection object. /// /// Non-zero if the function was unbound. internal abstract bool UnbindFunction(SQLiteFunctionAttribute functionAttribute, SQLiteConnectionFlags flags); internal abstract void Bind_Double(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, double value); internal abstract void Bind_Int32(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, Int32 value); internal abstract void Bind_UInt32(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, UInt32 value); internal abstract void Bind_Int64(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, Int64 value); internal abstract void Bind_UInt64(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, UInt64 value); internal abstract void Bind_Boolean(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, bool value); internal abstract void Bind_Text(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, string value); internal abstract void Bind_Blob(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, byte[] blobData); internal abstract void Bind_DateTime(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, DateTime dt); internal abstract void Bind_Null(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index); internal abstract int Bind_ParamCount(SQLiteStatement stmt, SQLiteConnectionFlags flags); internal abstract string Bind_ParamName(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index); internal abstract int Bind_ParamIndex(SQLiteStatement stmt, SQLiteConnectionFlags flags, string paramName); internal abstract int ColumnCount(SQLiteStatement stmt); internal abstract string ColumnName(SQLiteStatement stmt, int index); internal abstract TypeAffinity ColumnAffinity(SQLiteStatement stmt, int index); internal abstract string ColumnType(SQLiteStatement stmt, int index, ref TypeAffinity nAffinity); internal abstract int ColumnIndex(SQLiteStatement stmt, string columnName); internal abstract string ColumnOriginalName(SQLiteStatement stmt, int index); internal abstract string ColumnDatabaseName(SQLiteStatement stmt, int index); internal abstract string ColumnTableName(SQLiteStatement stmt, int index); internal abstract bool DoesTableExist(string dataBase, string table); internal abstract bool ColumnMetaData(string dataBase, string table, string column, bool canThrow, ref string dataType, ref string collateSequence, ref bool notNull, ref bool primaryKey, ref bool autoIncrement); internal abstract void GetIndexColumnExtendedInfo(string database, string index, string column, ref int sortMode, ref int onError, ref string collationSequence); internal abstract object GetObject(SQLiteStatement stmt, int index); internal abstract double GetDouble(SQLiteStatement stmt, int index); internal abstract Boolean GetBoolean(SQLiteStatement stmt, int index); internal abstract SByte GetSByte(SQLiteStatement stmt, int index); internal abstract Byte GetByte(SQLiteStatement stmt, int index); internal abstract Int16 GetInt16(SQLiteStatement stmt, int index); internal abstract UInt16 GetUInt16(SQLiteStatement stmt, int index); internal abstract Int32 GetInt32(SQLiteStatement stmt, int index); internal abstract UInt32 GetUInt32(SQLiteStatement stmt, int index); internal abstract Int64 GetInt64(SQLiteStatement stmt, int index); internal abstract UInt64 GetUInt64(SQLiteStatement stmt, int index); internal abstract string GetText(SQLiteStatement stmt, int index); internal abstract long GetBytes(SQLiteStatement stmt, int index, int nDataoffset, byte[] bDest, int nStart, int nLength); internal abstract char GetChar(SQLiteStatement stmt, int index); internal abstract long GetChars(SQLiteStatement stmt, int index, int nDataoffset, char[] bDest, int nStart, int nLength); internal abstract DateTime GetDateTime(SQLiteStatement stmt, int index); internal abstract bool IsNull(SQLiteStatement stmt, int index); internal abstract SQLiteErrorCode CreateCollation(string strCollation, SQLiteCollation func, SQLiteCollation func16, bool @throw); internal abstract SQLiteErrorCode CreateFunction(string strFunction, int nArgs, bool needCollSeq, SQLiteCallback func, SQLiteCallback funcstep, SQLiteFinalCallback funcfinal, bool @throw); internal abstract CollationSequence GetCollationSequence(SQLiteFunction func, IntPtr context); internal abstract int ContextCollateCompare(CollationEncodingEnum enc, IntPtr context, string s1, string s2); internal abstract int ContextCollateCompare(CollationEncodingEnum enc, IntPtr context, char[] c1, char[] c2); internal abstract int AggregateCount(IntPtr context); internal abstract IntPtr AggregateContext(IntPtr context); internal abstract long GetParamValueBytes(IntPtr ptr, int nDataOffset, byte[] bDest, int nStart, int nLength); internal abstract double GetParamValueDouble(IntPtr ptr); internal abstract int GetParamValueInt32(IntPtr ptr); internal abstract Int64 GetParamValueInt64(IntPtr ptr); internal abstract string GetParamValueText(IntPtr ptr); internal abstract TypeAffinity GetParamValueType(IntPtr ptr); internal abstract void ReturnBlob(IntPtr context, byte[] value); internal abstract void ReturnDouble(IntPtr context, double value); internal abstract void ReturnError(IntPtr context, string value); internal abstract void ReturnInt32(IntPtr context, Int32 value); internal abstract void ReturnInt64(IntPtr context, Int64 value); internal abstract void ReturnNull(IntPtr context); internal abstract void ReturnText(IntPtr context, string value); #if INTEROP_VIRTUAL_TABLE /// /// Calls the native SQLite core library in order to create a disposable /// module containing the implementation of a virtual table. /// /// /// The module object to be used when creating the native disposable module. /// /// /// The flags for the associated object instance. /// internal abstract void CreateModule(SQLiteModule module, SQLiteConnectionFlags flags); /// /// Calls the native SQLite core library in order to cleanup the resources /// associated with a module containing the implementation of a virtual table. /// /// /// The module object previously passed to the /// method. /// /// /// The flags for the associated object instance. /// internal abstract void DisposeModule(SQLiteModule module, SQLiteConnectionFlags flags); /// /// Calls the native SQLite core library in order to declare a virtual table /// in response to a call into the /// or virtual table methods. /// /// /// The virtual table module that is to be responsible for the virtual table /// being declared. /// /// /// The string containing the SQL statement describing the virtual table to /// be declared. /// /// /// Upon success, the contents of this parameter are undefined. Upon failure, /// it should contain an appropriate error message. /// /// /// A standard SQLite return code. /// internal abstract SQLiteErrorCode DeclareVirtualTable(SQLiteModule module, string strSql, ref string error); /// /// Calls the native SQLite core library in order to declare a virtual table /// function in response to a call into the /// or virtual table methods. /// /// /// The virtual table module that is to be responsible for the virtual table /// function being declared. /// /// /// The number of arguments to the function being declared. /// /// /// The name of the function being declared. /// /// /// Upon success, the contents of this parameter are undefined. Upon failure, /// it should contain an appropriate error message. /// /// /// A standard SQLite return code. /// internal abstract SQLiteErrorCode DeclareVirtualFunction(SQLiteModule module, int argumentCount, string name, ref string error); #endif /// /// Returns the current and/or highwater values for the specified database status parameter. /// /// /// The database status parameter to query. /// /// /// Non-zero to reset the highwater value to the current value. /// /// /// If applicable, receives the current value. /// /// /// If applicable, receives the highwater value. /// /// /// A standard SQLite return code. /// internal abstract SQLiteErrorCode GetStatusParameter(SQLiteStatusOpsEnum option, bool reset, ref int current, ref int highwater); /// /// Change a configuration option value for the database. /// /// /// The database configuration option to change. /// /// /// The new value for the specified configuration option. /// /// /// A standard SQLite return code. /// internal abstract SQLiteErrorCode SetConfigurationOption(SQLiteConfigDbOpsEnum option, object value); /// /// Enables or disables extension loading by SQLite. /// /// /// True to enable loading of extensions, false to disable. /// internal abstract void SetLoadExtension(bool bOnOff); /// /// Loads a SQLite extension library from the named file. /// /// /// The name of the dynamic link library file containing the extension. /// /// /// The name of the exported function used to initialize the extension. /// If null, the default "sqlite3_extension_init" will be used. /// internal abstract void LoadExtension(string fileName, string procName); /// /// Enables or disabled extened result codes returned by SQLite /// /// true to enable extended result codes, false to disable. /// internal abstract void SetExtendedResultCodes(bool bOnOff); /// /// Returns the numeric result code for the most recent failed SQLite API call /// associated with the database connection. /// /// Result code internal abstract SQLiteErrorCode ResultCode(); /// /// Returns the extended numeric result code for the most recent failed SQLite API call /// associated with the database connection. /// /// Extended result code internal abstract SQLiteErrorCode ExtendedResultCode(); /// /// Add a log message via the SQLite sqlite3_log interface. /// /// Error code to be logged with the message. /// String to be logged. Unlike the SQLite sqlite3_log() /// interface, this should be pre-formatted. Consider using the /// String.Format() function. /// internal abstract void LogMessage(SQLiteErrorCode iErrCode, string zMessage); #if INTEROP_CODEC || INTEROP_INCLUDE_SEE internal abstract void SetPassword(byte[] passwordBytes); internal abstract void ChangePassword(byte[] newPasswordBytes); #endif internal abstract void SetProgressHook(int nOps, SQLiteProgressCallback func); internal abstract void SetAuthorizerHook(SQLiteAuthorizerCallback func); internal abstract void SetUpdateHook(SQLiteUpdateCallback func); internal abstract void SetCommitHook(SQLiteCommitCallback func); internal abstract void SetTraceCallback(SQLiteTraceCallback func); internal abstract void SetTraceCallback2(SQLiteTraceFlags mask, SQLiteTraceCallback2 func); internal abstract void SetRollbackHook(SQLiteRollbackCallback func); internal abstract SQLiteErrorCode SetLogCallback(SQLiteLogCallback func); /// /// Checks if the SQLite core library has been initialized in the current process. /// /// /// Non-zero if the SQLite core library has been initialized in the current process, /// zero otherwise. /// internal abstract bool IsInitialized(); internal abstract int GetCursorForTable(SQLiteStatement stmt, int database, int rootPage); internal abstract long GetRowIdForCursor(SQLiteStatement stmt, int cursor); internal abstract object GetValue(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, SQLiteType typ); /// /// Returns non-zero if the given database connection is in autocommit mode. /// Autocommit mode is on by default. Autocommit mode is disabled by a BEGIN /// statement. Autocommit mode is re-enabled by a COMMIT or ROLLBACK. /// internal abstract bool AutoCommit { get; } internal abstract SQLiteErrorCode FileControl(string zDbName, int op, IntPtr pArg); /// /// Creates a new SQLite backup object based on the provided destination /// database connection. The source database connection is the one /// associated with this object. The source and destination database /// connections cannot be the same. /// /// The destination database connection. /// The destination database name. /// The source database name. /// The newly created backup object. internal abstract SQLiteBackup InitializeBackup( SQLiteConnection destCnn, string destName, string sourceName); /// /// Copies up to N pages from the source database to the destination /// database associated with the specified backup object. /// /// The backup object to use. /// /// The number of pages to copy or negative to copy all remaining pages. /// /// /// Set to true if the operation needs to be retried due to database /// locking issues. /// /// /// True if there are more pages to be copied, false otherwise. /// internal abstract bool StepBackup(SQLiteBackup backup, int nPage, ref bool retry); /// /// Returns the number of pages remaining to be copied from the source /// database to the destination database associated with the specified /// backup object. /// /// The backup object to check. /// The number of pages remaining to be copied. internal abstract int RemainingBackup(SQLiteBackup backup); /// /// Returns the total number of pages in the source database associated /// with the specified backup object. /// /// The backup object to check. /// The total number of pages in the source database. internal abstract int PageCountBackup(SQLiteBackup backup); /// /// Destroys the backup object, rolling back any backup that may be in /// progess. /// /// The backup object to destroy. internal abstract void FinishBackup(SQLiteBackup backup); /////////////////////////////////////////////////////////////////////////////////////////////// #region IDisposable Members public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } #endregion /////////////////////////////////////////////////////////////////////////////////////////////// #region IDisposable "Pattern" Members private bool disposed; private void CheckDisposed() /* throw */ { #if THROW_ON_DISPOSED if (disposed) throw new ObjectDisposedException(typeof(SQLiteBase).Name); #endif } /////////////////////////////////////////////////////////////////////////////////////////////// protected virtual void Dispose(bool disposing) { if (!disposed) { //if (disposing) //{ // //////////////////////////////////// // // dispose managed resources here... // //////////////////////////////////// //} ////////////////////////////////////// // release unmanaged resources here... ////////////////////////////////////// disposed = true; } } #endregion /////////////////////////////////////////////////////////////////////////////////////////////// #region Destructor ~SQLiteBase() { Dispose(false); } #endregion /////////////////////////////////////////////////////////////////////////////////////////////// // These statics are here for lack of a better place to put them. // They exist here because they are called during the finalization of // a SQLiteStatementHandle, SQLiteConnectionHandle, and SQLiteFunctionCookieHandle. // Therefore these functions have to be static, and have to be low-level. /////////////////////////////////////////////////////////////////////////////////////////////// private static string[] _errorMessages = { /* SQLITE_OK */ "not an error", /* SQLITE_ERROR */ "SQL logic error", /* SQLITE_INTERNAL */ "internal logic error", /* SQLITE_PERM */ "access permission denied", /* SQLITE_ABORT */ "query aborted", /* SQLITE_BUSY */ "database is locked", /* SQLITE_LOCKED */ "database table is locked", /* SQLITE_NOMEM */ "out of memory", /* SQLITE_READONLY */ "attempt to write a readonly database", /* SQLITE_INTERRUPT */ "interrupted", /* SQLITE_IOERR */ "disk I/O error", /* SQLITE_CORRUPT */ "database disk image is malformed", /* SQLITE_NOTFOUND */ "unknown operation", /* SQLITE_FULL */ "database or disk is full", /* SQLITE_CANTOPEN */ "unable to open database file", /* SQLITE_PROTOCOL */ "locking protocol", /* SQLITE_EMPTY */ "table contains no data", /* SQLITE_SCHEMA */ "database schema has changed", /* SQLITE_TOOBIG */ "string or blob too big", /* SQLITE_CONSTRAINT */ "constraint failed", /* SQLITE_MISMATCH */ "datatype mismatch", /* SQLITE_MISUSE */ "bad parameter or other API misuse", /* SQLITE_NOLFS */ "large file support is disabled", /* SQLITE_AUTH */ "authorization denied", /* SQLITE_FORMAT */ "auxiliary database format error", /* SQLITE_RANGE */ "column index out of range", /* SQLITE_NOTADB */ "file is not a database", /* SQLITE_NOTICE */ "notification message", /* SQLITE_WARNING */ "warning message" }; /////////////////////////////////////////////////////////////////////////////////////////////// /// /// Returns the error message for the specified SQLite return code using /// the internal static lookup table. /// /// The SQLite return code. /// The error message or null if it cannot be found. protected static string FallbackGetErrorString(SQLiteErrorCode rc) { switch (rc) { case SQLiteErrorCode.Abort_Rollback: return "abort due to ROLLBACK"; case SQLiteErrorCode.Row: return "another row available"; case SQLiteErrorCode.Done: return "no more rows available"; } if (_errorMessages == null) return null; int index = (int)(rc & SQLiteErrorCode.NonExtendedMask); if ((index < 0) || (index >= _errorMessages.Length)) index = (int)SQLiteErrorCode.Error; /* Make into generic error. */ return _errorMessages[index]; } 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 = 0; result = UTF8ToString(UnsafeNativeMethods.sqlite3_errmsg_interop(db, ref len), len); #else result = UTF8ToString(UnsafeNativeMethods.sqlite3_errmsg(db), -1); #endif } else { result = "closed or invalid connection handle"; } } } GC.KeepAlive(hdl); return result; } internal static void FinishBackup(SQLiteConnectionHandle hdl, IntPtr backup) { if ((hdl == null) || (backup == 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_backup_finish_interop(backup); #else SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_backup_finish(backup); #endif if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, null); } } } internal static void CloseBlob(SQLiteConnectionHandle hdl, IntPtr blob) { if ((hdl == null) || (blob == 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_blob_close_interop(blob); #else SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_blob_close(blob); #endif if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, null); } } } 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 void CloseConnection(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(db); #endif if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, GetLastError(hdl, db)); } } } #if !INTEROP_LEGACY_CLOSE 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)); } } } #endif 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, ref stmt); if (n == SQLiteErrorCode.Ok) { result = true; } else if (canThrow) { throw new SQLiteException(n, GetLastError(hdl, db)); } } } } } GC.KeepAlive(hdl); return result; } 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; } } /// /// /// public interface ISQLiteSchemaExtensions { /// /// Creates temporary tables on the connection so schema information can be queried. /// /// /// The connection upon which to build the schema tables. /// void BuildTempSchema(SQLiteConnection connection); } [Flags] internal enum SQLiteOpenFlagsEnum { None = 0, ReadOnly = 0x1, ReadWrite = 0x2, Create = 0x4, Uri = 0x40, Memory = 0x80, Default = ReadWrite | Create, } /// /// The extra behavioral flags that can be applied to a connection. /// [Flags()] public enum SQLiteConnectionFlags : long { /// /// No extra flags. /// None = 0x0, /// /// Enable logging of all SQL statements to be prepared. /// LogPrepare = 0x1, /// /// Enable logging of all bound parameter types and raw values. /// LogPreBind = 0x2, /// /// Enable logging of all bound parameter strongly typed values. /// LogBind = 0x4, /// /// Enable logging of all exceptions caught from user-provided /// managed code called from native code via delegates. /// LogCallbackException = 0x8, /// /// Enable logging of backup API errors. /// LogBackup = 0x10, /// /// Skip adding the extension functions provided by the native /// interop assembly. /// NoExtensionFunctions = 0x20, /// /// When binding parameter values with the /// type, use the interop method that accepts an /// value. /// BindUInt32AsInt64 = 0x40, /// /// When binding parameter values, always bind them as though they were /// plain text (i.e. no numeric, date/time, or other conversions should /// be attempted). /// BindAllAsText = 0x80, /// /// When returning column values, always return them as though they were /// plain text (i.e. no numeric, date/time, or other conversions should /// be attempted). /// GetAllAsText = 0x100, /// /// Prevent this object instance from /// loading extensions. /// NoLoadExtension = 0x200, #if INTEROP_VIRTUAL_TABLE /// /// Prevent this object instance from /// creating virtual table modules. /// NoCreateModule = 0x400, #endif /// /// Skip binding any functions provided by other managed assemblies when /// opening the connection. /// NoBindFunctions = 0x800, #if INTEROP_VIRTUAL_TABLE /// /// Skip setting the logging related properties of the /// object instance that was passed to /// the method. /// NoLogModule = 0x1000, /// /// Enable logging of all virtual table module errors seen by the /// method. /// LogModuleError = 0x2000, /// /// Enable logging of certain virtual table module exceptions that cannot /// be easily discovered via other means. /// LogModuleException = 0x4000, #endif /// /// Enable tracing of potentially important [non-fatal] error conditions /// that cannot be easily reported through other means. /// TraceWarning = 0x8000, /// /// When binding parameter values, always use the invariant culture when /// converting their values from strings. /// ConvertInvariantText = 0x10000, /// /// When binding parameter values, always use the invariant culture when /// converting their values to strings. /// BindInvariantText = 0x20000, /// /// Disable using the connection pool by default. If the "Pooling" /// connection string property is specified, its value will override /// this flag. The precise outcome of combining this flag with the /// flag is unspecified; however, /// one of the flags will be in effect. /// NoConnectionPool = 0x40000, /// /// Enable using the connection pool by default. If the "Pooling" /// connection string property is specified, its value will override /// this flag. The precise outcome of combining this flag with the /// flag is unspecified; however, /// one of the flags will be in effect. /// UseConnectionPool = 0x80000, /// /// Enable using per-connection mappings between type names and /// values. Also see the /// , /// , and /// methods. These /// per-connection mappings, when present, override the corresponding /// global mappings. /// UseConnectionTypes = 0x100000, /// /// Disable using global mappings between type names and /// values. This may be useful in some very narrow /// cases; however, if there are no per-connection type mappings, the /// fallback defaults will be used for both type names and their /// associated values. Therefore, use of this flag /// is not recommended. /// NoGlobalTypes = 0x200000, /// /// When the property is used, it /// should return non-zero if there were ever any rows in the associated /// result sets. /// StickyHasRows = 0x400000, /// /// Enable "strict" transaction enlistment semantics. Setting this flag /// will cause an exception to be thrown if an attempt is made to enlist /// in a transaction with an unavailable or unsupported isolation level. /// In the future, more extensive checks may be enabled by this flag as /// well. /// StrictEnlistment = 0x800000, /// /// Enable mapping of unsupported transaction isolation levels to the /// closest supported transaction isolation level. /// MapIsolationLevels = 0x1000000, /// /// When returning column values, attempt to detect the affinity of /// textual values by checking if they fully conform to those of the /// , /// , /// , /// or types. /// DetectTextAffinity = 0x2000000, /// /// When returning column values, attempt to detect the type of /// string values by checking if they fully conform to those of /// the , /// , /// , /// or types. /// DetectStringType = 0x4000000, /// /// Skip querying runtime configuration settings for use by the /// class, including the default /// value and default database type name. /// NOTE: If the /// and/or /// properties are not set explicitly nor set via their connection /// string properties and repeated calls to determine these runtime /// configuration settings are seen to be a problem, this flag /// should be set. /// NoConvertSettings = 0x8000000, /// /// When binding parameter values with the /// type, take their into account as /// well as that of the associated . /// BindDateTimeWithKind = 0x10000000, /// /// If an exception is caught when raising the /// event, the transaction /// should be rolled back. If this is not specified, the transaction /// will continue the commit process instead. /// RollbackOnException = 0x20000000, /// /// If an exception is caught when raising the /// event, the action should /// should be denied. If this is not specified, the action will be /// allowed instead. /// DenyOnException = 0x40000000, /// /// If an exception is caught when raising the /// event, the operation /// should be interrupted. If this is not specified, the operation /// will simply continue. /// InterruptOnException = 0x80000000, /// /// Attempt to unbind all functions provided by other managed assemblies /// when closing the connection. /// UnbindFunctionsOnClose = 0x100000000, /// /// When returning column values as a , skip /// verifying their affinity. /// NoVerifyTextAffinity = 0x200000000, /// /// Enable using per-connection mappings between type names and /// values. Also see the /// , /// , and /// methods. /// UseConnectionBindValueCallbacks = 0x400000000, /// /// Enable using per-connection mappings between type names and /// values. Also see the /// , /// , and /// methods. /// UseConnectionReadValueCallbacks = 0x800000000, /// /// If the database type name has not been explicitly set for the /// parameter specified, fallback to using the parameter name. /// UseParameterNameForTypeName = 0x1000000000, /// /// If the database type name has not been explicitly set for the /// parameter specified, fallback to using the database type name /// associated with the value. /// UseParameterDbTypeForTypeName = 0x2000000000, /// /// When returning column values, skip verifying their affinity. /// NoVerifyTypeAffinity = 0x4000000000, /// /// Allow transactions to be nested. The outermost transaction still /// controls whether or not any changes are ultimately committed or /// rolled back. All non-outermost transactions are implemented using /// the SAVEPOINT construct. /// AllowNestedTransactions = 0x8000000000, /// /// When binding parameter values, always bind /// values as though they were plain text (i.e. not , /// which is the legacy behavior). /// BindDecimalAsText = 0x10000000000, /// /// When returning column values, always return /// values as though they were plain text (i.e. not , /// which is the legacy behavior). /// GetDecimalAsText = 0x20000000000, /// /// When binding parameter values, always use /// the invariant culture when converting their values to strings. /// BindInvariantDecimal = 0x40000000000, /// /// When returning column values, always use /// the invariant culture when converting their values from strings. /// GetInvariantDecimal = 0x80000000000, /// /// EXPERIMENTAL -- /// Enable waiting for the enlistment to be reset prior to attempting /// to create a new enlistment. This may be necessary due to the /// semantics used by distributed transactions, which complete /// asynchronously. /// WaitForEnlistmentReset = 0x100000000000, /// /// When binding parameter values or returning column values, always /// treat them as though they were plain text (i.e. no numeric, /// date/time, or other conversions should be attempted). /// BindAndGetAllAsText = BindAllAsText | GetAllAsText, /// /// When binding parameter values, always use the invariant culture when /// converting their values to strings or from strings. /// ConvertAndBindInvariantText = ConvertInvariantText | BindInvariantText, /// /// When binding parameter values or returning column values, always /// treat them as though they were plain text (i.e. no numeric, /// date/time, or other conversions should be attempted) and always /// use the invariant culture when converting their values to strings. /// BindAndGetAllAsInvariantText = BindAndGetAllAsText | BindInvariantText, /// /// When binding parameter values or returning column values, always /// treat them as though they were plain text (i.e. no numeric, /// date/time, or other conversions should be attempted) and always /// use the invariant culture when converting their values to strings /// or from strings. /// ConvertAndBindAndGetAllAsInvariantText = BindAndGetAllAsText | ConvertAndBindInvariantText, /// /// Enables use of all per-connection value handling callbacks. /// UseConnectionAllValueCallbacks = UseConnectionBindValueCallbacks | UseConnectionReadValueCallbacks, /// /// Enables use of all applicable /// properties as fallbacks for the database type name. /// UseParameterAnythingForTypeName = UseParameterNameForTypeName | UseParameterDbTypeForTypeName, /// /// Enable all logging. /// #if INTEROP_VIRTUAL_TABLE LogAll = LogPrepare | LogPreBind | LogBind | LogCallbackException | LogBackup | LogModuleError | LogModuleException, #else LogAll = LogPrepare | LogPreBind | LogBind | LogCallbackException | LogBackup, #endif /// /// The default logging related flags for new connections. /// #if INTEROP_VIRTUAL_TABLE LogDefault = LogCallbackException | LogModuleException, #else LogDefault = LogCallbackException, #endif /// /// The default extra flags for new connections. /// Default = LogDefault | BindInvariantDecimal | GetInvariantDecimal, /// /// The default extra flags for new connections with all logging enabled. /// DefaultAndLogAll = Default | LogAll } /// /// These are the supported status parameters for use with the native /// SQLite library. /// internal enum SQLiteStatusOpsEnum { /// /// This parameter returns the number of lookaside memory slots /// currently checked out. /// SQLITE_DBSTATUS_LOOKASIDE_USED = 0, /// /// This parameter returns the approximate number of bytes of /// heap memory used by all pager caches associated with the /// database connection. The highwater mark associated with /// SQLITE_DBSTATUS_CACHE_USED is always 0. /// SQLITE_DBSTATUS_CACHE_USED = 1, /// /// This parameter returns the approximate number of bytes of /// heap memory used to store the schema for all databases /// associated with the connection - main, temp, and any ATTACH-ed /// databases. The full amount of memory used by the schemas is /// reported, even if the schema memory is shared with other /// database connections due to shared cache mode being enabled. /// The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED /// is always 0. /// SQLITE_DBSTATUS_SCHEMA_USED = 2, /// /// This parameter returns the number malloc attempts that might /// have been satisfied using lookaside memory but failed due to /// all lookaside memory already being in use. Only the high-water /// value is meaningful; the current value is always zero. /// SQLITE_DBSTATUS_STMT_USED = 3, /// /// This parameter returns the number malloc attempts that were /// satisfied using lookaside memory. Only the high-water value /// is meaningful; the current value is always zero. /// SQLITE_DBSTATUS_LOOKASIDE_HIT = 4, /// /// This parameter returns the number malloc attempts that might /// have been satisfied using lookaside memory but failed due to /// the amount of memory requested being larger than the lookaside /// slot size. Only the high-water value is meaningful; the current /// value is always zero. /// SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE = 5, /// /// This parameter returns the number malloc attempts that might /// have been satisfied using lookaside memory but failed due to /// the amount of memory requested being larger than the lookaside /// slot size. Only the high-water value is meaningful; the current /// value is always zero. /// SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL = 6, /// /// This parameter returns the number of pager cache hits that /// have occurred. The highwater mark associated with /// SQLITE_DBSTATUS_CACHE_HIT is always 0. /// SQLITE_DBSTATUS_CACHE_HIT = 7, /// /// This parameter returns the number of pager cache misses that /// have occurred. The highwater mark associated with /// SQLITE_DBSTATUS_CACHE_MISS is always 0. /// SQLITE_DBSTATUS_CACHE_MISS = 8, /// /// This parameter returns the number of dirty cache entries that /// have been written to disk. Specifically, the number of pages /// written to the wal file in wal mode databases, or the number /// of pages written to the database file in rollback mode /// databases. Any pages written as part of transaction rollback /// or database recovery operations are not included. If an IO or /// other error occurs while writing a page to disk, the effect /// on subsequent SQLITE_DBSTATUS_CACHE_WRITE requests is /// undefined. The highwater mark associated with /// SQLITE_DBSTATUS_CACHE_WRITE is always 0. /// SQLITE_DBSTATUS_CACHE_WRITE = 9, /// /// This parameter returns zero for the current value if and only /// if all foreign key constraints (deferred or immediate) have /// been resolved. The highwater mark is always 0. /// SQLITE_DBSTATUS_DEFERRED_FKS = 10, /// /// This parameter is similar to DBSTATUS_CACHE_USED, except that /// if a pager cache is shared between two or more connections the /// bytes of heap memory used by that pager cache is divided evenly /// between the attached connections. In other words, if none of /// the pager caches associated with the database connection are /// shared, this request returns the same value as DBSTATUS_CACHE_USED. /// Or, if one or more or the pager caches are shared, the value /// returned by this call will be smaller than that returned by /// DBSTATUS_CACHE_USED. The highwater mark associated with /// SQLITE_DBSTATUS_CACHE_USED_SHARED is always 0. /// SQLITE_DBSTATUS_CACHE_USED_SHARED = 11 } /// /// These are the supported configuration verbs for use with the native /// SQLite library. They are used with the /// method. /// public enum SQLiteConfigDbOpsEnum { /// /// This value represents an unknown (or invalid) option, do not use it. /// SQLITE_DBCONFIG_NONE = 0, // nil /// /// This option is used to change the name of the "main" database /// schema. The sole argument is a pointer to a constant UTF8 string /// which will become the new schema name in place of "main". /// SQLITE_DBCONFIG_MAINDBNAME = 1000, // char* /// /// This option is used to configure the lookaside memory allocator. /// The value must be an array with three elements. The second element /// must be an containing the size of each buffer /// slot. The third element must be an containing /// the number of slots. The first element must be an /// that points to a native memory buffer of bytes equal to or greater /// than the product of the second and third element values. /// SQLITE_DBCONFIG_LOOKASIDE = 1001, // void* int int /// /// This option is used to enable or disable the enforcement of /// foreign key constraints. /// SQLITE_DBCONFIG_ENABLE_FKEY = 1002, // int int* /// /// This option is used to enable or disable triggers. /// SQLITE_DBCONFIG_ENABLE_TRIGGER = 1003, // int int* /// /// This option is used to enable or disable the two-argument version /// of the fts3_tokenizer() function which is part of the FTS3 full-text /// search engine extension. /// SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER = 1004, // int int* /// /// This option is used to enable or disable the loading of extensions. /// SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION = 1005, // int int* /// /// This option is used to enable or disable the automatic checkpointing /// when a WAL database is closed. /// SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE = 1006, // int int* /// /// This option is used to enable or disable the query planner stability /// guarantee (QPSG). /// SQLITE_DBCONFIG_ENABLE_QPSG = 1007, // int int* /// /// This option is used to enable or disable the extra EXPLAIN QUERY PLAN /// output for trigger programs. /// SQLITE_DBCONFIG_TRIGGER_EQP = 1008 // int int* } // These are the options to the internal sqlite3_config call. internal enum SQLiteConfigOpsEnum { SQLITE_CONFIG_NONE = 0, // nil SQLITE_CONFIG_SINGLETHREAD = 1, // nil SQLITE_CONFIG_MULTITHREAD = 2, // nil SQLITE_CONFIG_SERIALIZED = 3, // nil SQLITE_CONFIG_MALLOC = 4, // sqlite3_mem_methods* SQLITE_CONFIG_GETMALLOC = 5, // sqlite3_mem_methods* SQLITE_CONFIG_SCRATCH = 6, // void*, int sz, int N SQLITE_CONFIG_PAGECACHE = 7, // void*, int sz, int N SQLITE_CONFIG_HEAP = 8, // void*, int nByte, int min SQLITE_CONFIG_MEMSTATUS = 9, // boolean SQLITE_CONFIG_MUTEX = 10, // sqlite3_mutex_methods* SQLITE_CONFIG_GETMUTEX = 11, // sqlite3_mutex_methods* // previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused SQLITE_CONFIG_LOOKASIDE = 13, // int int SQLITE_CONFIG_PCACHE = 14, // sqlite3_pcache_methods* SQLITE_CONFIG_GETPCACHE = 15, // sqlite3_pcache_methods* SQLITE_CONFIG_LOG = 16, // xFunc, void* SQLITE_CONFIG_URI = 17, // int SQLITE_CONFIG_PCACHE2 = 18, // sqlite3_pcache_methods2* SQLITE_CONFIG_GETPCACHE2 = 19, // sqlite3_pcache_methods2* SQLITE_CONFIG_COVERING_INDEX_SCAN = 20, // int SQLITE_CONFIG_SQLLOG = 21, // xSqllog, void* SQLITE_CONFIG_MMAP_SIZE = 22, // sqlite3_int64, sqlite3_int64 SQLITE_CONFIG_WIN32_HEAPSIZE = 23, // int nByte SQLITE_CONFIG_PCACHE_HDRSZ = 24, // int *psz SQLITE_CONFIG_PMASZ = 25 // unsigned int szPma } /// /// These constants are used with the sqlite3_trace_v2() API and the /// callbacks registered by it. /// [Flags()] internal enum SQLiteTraceFlags { SQLITE_TRACE_NONE = 0x0, // nil SQLITE_TRACE_STMT = 0x1, // pStmt, zSql SQLITE_TRACE_PROFILE = 0x2, // pStmt, piNsec64 SQLITE_TRACE_ROW = 0x4, // pStmt SQLITE_TRACE_CLOSE = 0x8 // pDb } }