/******************************************************** * 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.Data.Common; using System.Globalization; #if !PLATFORM_COMPACTFRAMEWORK using System.Reflection; using System.Runtime.Serialization; using System.Security.Permissions; #endif /// /// SQLite exception class. /// #if !PLATFORM_COMPACTFRAMEWORK [Serializable()] public sealed class SQLiteException : DbException, ISerializable #else public sealed class SQLiteException : Exception #endif { #region Private Constants /// /// This value was copied from the "WinError.h" file included with the /// Platform SDK for Windows 10. /// private const int FACILITY_SQLITE = 1967; #endregion /////////////////////////////////////////////////////////////////////////// private SQLiteErrorCode _errorCode; /////////////////////////////////////////////////////////////////////////// #if !PLATFORM_COMPACTFRAMEWORK /// /// Private constructor for use with serialization. /// /// /// Holds the serialized object data about the exception being thrown. /// /// /// Contains contextual information about the source or destination. /// private SQLiteException(SerializationInfo info, StreamingContext context) : base(info, context) { _errorCode = (SQLiteErrorCode)info.GetInt32("errorCode"); Initialize(); } #endif /////////////////////////////////////////////////////////////////////////// /// /// Public constructor for generating a SQLite exception given the error /// code and message. /// /// /// The SQLite return code to report. /// /// /// Message text to go along with the return code message text. /// public SQLiteException(SQLiteErrorCode errorCode, string message) : base(GetStockErrorMessage(errorCode, message)) { _errorCode = errorCode; Initialize(); } /////////////////////////////////////////////////////////////////////////// /// /// Public constructor that uses the base class constructor for the error /// message. /// /// Error message text. public SQLiteException(string message) : this(SQLiteErrorCode.Unknown, message) { // do nothing. } /////////////////////////////////////////////////////////////////////////// /// /// Public constructor that uses the default base class constructor. /// public SQLiteException() : base() { Initialize(); } /////////////////////////////////////////////////////////////////////////// /// /// Public constructor that uses the base class constructor for the error /// message and inner exception. /// /// Error message text. /// The original (inner) exception. public SQLiteException(string message, Exception innerException) : base(message, innerException) { Initialize(); } /////////////////////////////////////////////////////////////////////////// #if !PLATFORM_COMPACTFRAMEWORK /// /// Adds extra information to the serialized object data specific to this /// class type. This is only used for serialization. /// /// /// Holds the serialized object data about the exception being thrown. /// /// /// Contains contextual information about the source or destination. /// [SecurityPermission( SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)] public override void GetObjectData( SerializationInfo info, StreamingContext context) { if (info != null) info.AddValue("errorCode", _errorCode); base.GetObjectData(info, context); } #endif /////////////////////////////////////////////////////////////////////////// /// /// Gets the associated SQLite result code for this exception as a /// . This property returns the same /// underlying value as the property. /// public SQLiteErrorCode ResultCode { get { return _errorCode; } } /////////////////////////////////////////////////////////////////////////// /// /// Gets the associated SQLite return code for this exception as an /// . For desktop versions of the .NET Framework, /// this property overrides the property of the same name within the /// /// class. This property returns the same underlying value as the /// property. /// #if !PLATFORM_COMPACTFRAMEWORK public override int ErrorCode #else public int ErrorCode #endif { get { return (int)_errorCode; } } /////////////////////////////////////////////////////////////////////////// /// /// This method performs extra initialization tasks. It may be called by /// any of the constructors of this class. It must not throw exceptions. /// private void Initialize() { if (HResult == unchecked((int)0x80004005)) /* E_FAIL */ { int? localHResult = GetHResultForErrorCode(ResultCode); if (localHResult != null) HResult = (int)localHResult; } } /////////////////////////////////////////////////////////////////////////// /// /// Maps a Win32 error code to an HRESULT. /// /// /// The specified Win32 error code. It must be within the range of zero /// (0) to 0xFFFF (65535). /// /// /// Non-zero if the HRESULT should indicate success; otherwise, zero. /// /// /// The integer value of the HRESULT. /// private static int MakeHResult( int errorCode, bool success ) { return (errorCode & 0xFFFF) | FACILITY_SQLITE | (success ? 0 : unchecked((int)0x80000000)); } /////////////////////////////////////////////////////////////////////////// /// /// Attempts to map the specified onto an /// existing HRESULT -OR- a Win32 error code wrapped in an HRESULT. The /// mappings may not have perfectly matching semantics; however, they do /// have the benefit of being unique within the context of this exception /// type. /// /// /// The to map. /// /// /// The integer HRESULT value -OR- null if there is no known mapping. /// private static int? GetHResultForErrorCode( SQLiteErrorCode errorCode ) { switch (errorCode & SQLiteErrorCode.NonExtendedMask) { case SQLiteErrorCode.Ok: { return 0; /* S_OK */ } case SQLiteErrorCode.Error: { return MakeHResult(0x001F, false); /* ERROR_GEN_FAILURE */ } case SQLiteErrorCode.Internal: { return unchecked((int)0x8000FFFF); /* E_UNEXPECTED */ } case SQLiteErrorCode.Perm: { return MakeHResult(0x0005, false); /* ERROR_ACCESS_DENIED */ } case SQLiteErrorCode.Abort: { return unchecked((int)0x80004004); /* E_ABORT */ } case SQLiteErrorCode.Busy: { return MakeHResult(0x00AA, false); /* ERROR_BUSY */ } case SQLiteErrorCode.Locked: { return MakeHResult(0x00D4, false); /* ERROR_LOCKED */ } case SQLiteErrorCode.NoMem: { return MakeHResult(0x000E, false); /* ERROR_OUTOFMEMORY */ } case SQLiteErrorCode.ReadOnly: { return MakeHResult(0x1779, false); /* ERROR_FILE_READ_ONLY */ } case SQLiteErrorCode.Interrupt: { return MakeHResult(0x04C7, false); /* ERROR_CANCELLED */ } case SQLiteErrorCode.IoErr: { return MakeHResult(0x045D, false); /* ERROR_IO_DEVICE */ } case SQLiteErrorCode.Corrupt: { return MakeHResult(0x054E, false); /* ERROR_INTERNAL_DB_CORRUPTION */ } case SQLiteErrorCode.NotFound: { return MakeHResult(0x0032, false); /* ERROR_NOT_SUPPORTED */ } case SQLiteErrorCode.Full: { return MakeHResult(0x0070, false); /* ERROR_DISK_FULL */ } case SQLiteErrorCode.CantOpen: { return MakeHResult(0x03F3, false); /* ERROR_CANTOPEN */ } case SQLiteErrorCode.Protocol: { return MakeHResult(0x05B4, false); /* ERROR_TIMEOUT */ } case SQLiteErrorCode.Empty: { return MakeHResult(0x10D2, false); /* ERROR_EMPTY */ } case SQLiteErrorCode.Schema: { return MakeHResult(0x078B, false); /* ERROR_CONTEXT_EXPIRED */ } case SQLiteErrorCode.TooBig: { return unchecked((int)0x800288C5); /* TYPE_E_SIZETOOBIG */ } case SQLiteErrorCode.Constraint: { return MakeHResult(0x202F, false); /* ERROR_DS_CONSTRAINT_VIOLATION */ } case SQLiteErrorCode.Mismatch: { return MakeHResult(0x065D, false); /* ERROR_DATATYPE_MISMATCH */ } case SQLiteErrorCode.Misuse: { return MakeHResult(0x0649, false); /* ERROR_INVALID_HANDLE_STATE */ } case SQLiteErrorCode.NoLfs: { return MakeHResult(0x0646, false); /* ERROR_UNKNOWN_FEATURE */ } case SQLiteErrorCode.Auth: { return MakeHResult(0x078F, false); /* ERROR_AUTHENTICATION_FIREWALL_FAILED */ } case SQLiteErrorCode.Format: { return MakeHResult(0x000B, false); /* ERROR_BAD_FORMAT */ } case SQLiteErrorCode.Range: { return unchecked((int)0x80028CA1); /* TYPE_E_OUTOFBOUNDS */ } case SQLiteErrorCode.NotADb: { return MakeHResult(0x0570, false); /* ERROR_FILE_CORRUPT */ } case SQLiteErrorCode.Notice: case SQLiteErrorCode.Warning: case SQLiteErrorCode.Row: case SQLiteErrorCode.Done: { // // NOTE: These result codes are not errors, per se; // therefore, mask off all HRESULT bits that // are not part of the "code" portion (e.g. // the severity, facility, etc). This will // have the effect of creating an HRESULT // that indicates success, while (hopefully) // preserving the specified result code. At // the time this method was written (2018-02), // no SQLite result codes were outside of the // supported range for HRESULT codes (e.g. // 0x0000 to 0xFFFF, inclusive), which made // the following masking operation a harmless // NOOP. // return MakeHResult((int)errorCode, true); } } return null; } /////////////////////////////////////////////////////////////////////////// /// /// Returns the error message for the specified SQLite return code. /// /// The SQLite return code. /// The error message or null if it cannot be found. 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(SQLite3).InvokeMember("GetErrorString", flags, null, null, new object[] { errorCode }) as string; #else return SQLite3.GetErrorString(errorCode); #endif } /////////////////////////////////////////////////////////////////////////// /// /// Returns the composite error message based on the SQLite return code /// and the optional detailed error message. /// /// The SQLite return code. /// Optional detailed error message. /// Error message text for the return code. private static string GetStockErrorMessage( SQLiteErrorCode errorCode, string message ) { return HelperMethods.StringFormat( CultureInfo.CurrentCulture, "{0}{1}{2}", GetErrorString(errorCode), #if !NET_COMPACT_20 Environment.NewLine, message).Trim(); #else "\r\n", message).Trim(); #endif } /////////////////////////////////////////////////////////////////////////// #region System.Object Overrides public override string ToString() { return HelperMethods.StringFormat( CultureInfo.CurrentCulture, "code = {0} ({1}), message = {2}", _errorCode, (int)_errorCode, base.ToString()); } #endregion } /// /// SQLite error codes. Actually, this enumeration represents a return code, /// which may also indicate success in one of several ways (e.g. SQLITE_OK, /// SQLITE_ROW, and SQLITE_DONE). Therefore, the name of this enumeration is /// something of a misnomer. /// public enum SQLiteErrorCode { /// /// The error code is unknown. This error code /// is only used by the managed wrapper itself. /// Unknown = -1, /// /// Successful result /// Ok /* 0 */, /// /// SQL error or missing database /// Error /* 1 */, /// /// Internal logic error in SQLite /// Internal /* 2 */, /// /// Access permission denied /// Perm /* 3 */, /// /// Callback routine requested an abort /// Abort /* 4 */, /// /// The database file is locked /// Busy /* 5 */, /// /// A table in the database is locked /// Locked /* 6 */, /// /// A malloc() failed /// NoMem /* 7 */, /// /// Attempt to write a readonly database /// ReadOnly /* 8 */, /// /// Operation terminated by sqlite3_interrupt() /// Interrupt /* 9 */, /// /// Some kind of disk I/O error occurred /// IoErr /* 10 */, /// /// The database disk image is malformed /// Corrupt /* 11 */, /// /// Unknown opcode in sqlite3_file_control() /// NotFound /* 12 */, /// /// Insertion failed because database is full /// Full /* 13 */, /// /// Unable to open the database file /// CantOpen /* 14 */, /// /// Database lock protocol error /// Protocol /* 15 */, /// /// Database is empty /// Empty /* 16 */, /// /// The database schema changed /// Schema /* 17 */, /// /// String or BLOB exceeds size limit /// TooBig /* 18 */, /// /// Abort due to constraint violation /// Constraint /* 19 */, /// /// Data type mismatch /// Mismatch /* 20 */, /// /// Library used incorrectly /// Misuse /* 21 */, /// /// Uses OS features not supported on host /// NoLfs /* 22 */, /// /// Authorization denied /// Auth /* 23 */, /// /// Auxiliary database format error /// Format /* 24 */, /// /// 2nd parameter to sqlite3_bind out of range /// Range /* 25 */, /// /// File opened that is not a database file /// NotADb /* 26 */, /// /// Notifications from sqlite3_log() /// Notice /* 27 */, /// /// Warnings from sqlite3_log() /// Warning /* 28 */, /// /// sqlite3_step() has another row ready /// Row = 100, /// /// sqlite3_step() has finished executing /// Done, /* 101 */ /// /// Used to mask off extended result codes /// NonExtendedMask = 0xFF, ///////////////////////////////////////////////////////////////////////// // BEGIN EXTENDED RESULT CODES ///////////////////////////////////////////////////////////////////////// /// /// A collation sequence was referenced by a schema and it cannot be /// found. /// Error_Missing_CollSeq = (Error | (1 << 8)), /// /// An internal operation failed and it may succeed if retried. /// Error_Retry = (Error | (2 << 8)), /// /// A file read operation failed. /// IoErr_Read = (IoErr | (1 << 8)), /// /// A file read operation returned less data than requested. /// IoErr_Short_Read = (IoErr | (2 << 8)), /// /// A file write operation failed. /// IoErr_Write = (IoErr | (3 << 8)), /// /// A file synchronization operation failed. /// IoErr_Fsync = (IoErr | (4 << 8)), /// /// A directory synchronization operation failed. /// IoErr_Dir_Fsync = (IoErr | (5 << 8)), /// /// A file truncate operation failed. /// IoErr_Truncate = (IoErr | (6 << 8)), /// /// A file metadata operation failed. /// IoErr_Fstat = (IoErr | (7 << 8)), /// /// A file unlock operation failed. /// IoErr_Unlock = (IoErr | (8 << 8)), /// /// A file lock operation failed. /// IoErr_RdLock = (IoErr | (9 << 8)), /// /// A file delete operation failed. /// IoErr_Delete = (IoErr | (10 << 8)), /// /// Not currently used. /// IoErr_Blocked = (IoErr | (11 << 8)), /// /// Out-of-memory during a file operation. /// IoErr_NoMem = (IoErr | (12 << 8)), /// /// A file existence/status operation failed. /// IoErr_Access = (IoErr | (13 << 8)), /// /// A check for a reserved lock failed. /// IoErr_CheckReservedLock = (IoErr | (14 << 8)), /// /// A file lock operation failed. /// IoErr_Lock = (IoErr | (15 << 8)), /// /// A file close operation failed. /// IoErr_Close = (IoErr | (16 << 8)), /// /// A directory close operation failed. /// IoErr_Dir_Close = (IoErr | (17 << 8)), /// /// A shared memory open operation failed. /// IoErr_ShmOpen = (IoErr | (18 << 8)), /// /// A shared memory size operation failed. /// IoErr_ShmSize = (IoErr | (19 << 8)), /// /// A shared memory lock operation failed. /// IoErr_ShmLock = (IoErr | (20 << 8)), /// /// A shared memory map operation failed. /// IoErr_ShmMap = (IoErr | (21 << 8)), /// /// A file seek operation failed. /// IoErr_Seek = (IoErr | (22 << 8)), /// /// A file delete operation failed because it does not exist. /// IoErr_Delete_NoEnt = (IoErr | (23 << 8)), /// /// A file memory mapping operation failed. /// IoErr_Mmap = (IoErr | (24 << 8)), /// /// The temporary directory path could not be obtained. /// IoErr_GetTempPath = (IoErr | (25 << 8)), /// /// A path string conversion operation failed. /// IoErr_ConvPath = (IoErr | (26 << 8)), /// /// Reserved. /// IoErr_VNode = (IoErr | (27 << 8)), /// /// An attempt to authenticate failed. /// IoErr_Auth = (IoErr | (28 << 8)), /// /// An attempt to begin a file system transaction failed. /// IoErr_Begin_Atomic = (IoErr | (29 << 8)), /// /// An attempt to commit a file system transaction failed. /// IoErr_Commit_Atomic = (IoErr | (30 << 8)), /// /// An attempt to rollback a file system transaction failed. /// IoErr_Rollback_Atomic = (IoErr | (31 << 8)), /// /// A database table is locked in shared-cache mode. /// Locked_SharedCache = (Locked | (1 << 8)), /// /// A virtual table in the database is locked. /// Locked_Vtab = (Locked | (2 << 8)), /// /// A database file is locked due to a recovery operation. /// Busy_Recovery = (Busy | (1 << 8)), /// /// A database file is locked due to snapshot semantics. /// Busy_Snapshot = (Busy | (2 << 8)), /// /// A database file cannot be opened because no temporary directory is available. /// CantOpen_NoTempDir = (CantOpen | (1 << 8)), /// /// A database file cannot be opened because its path represents a directory. /// CantOpen_IsDir = (CantOpen | (2 << 8)), /// /// A database file cannot be opened because its full path could not be obtained. /// CantOpen_FullPath = (CantOpen | (3 << 8)), /// /// A database file cannot be opened because a path string conversion operation failed. /// CantOpen_ConvPath = (CantOpen | (4 << 8)), /// /// A virtual table is malformed. /// Corrupt_Vtab = (Corrupt | (1 << 8)), /// /// A required sequence table is missing or corrupt. /// Corrupt_Sequence = (Corrupt | (2 << 8)), /// /// A database file is read-only due to a recovery operation. /// ReadOnly_Recovery = (ReadOnly | (1 << 8)), /// /// A database file is read-only because a lock could not be obtained. /// ReadOnly_CantLock = (ReadOnly | (2 << 8)), /// /// A database file is read-only because it needs rollback processing. /// ReadOnly_Rollback = (ReadOnly | (3 << 8)), /// /// A database file is read-only because it was moved while open. /// ReadOnly_DbMoved = (ReadOnly | (4 << 8)), /// /// The shared-memory file is read-only and it should be read-write. /// ReadOnly_CantInit = (ReadOnly | (5 << 8)), /// /// Unable to create journal file because the directory is read-only. /// ReadOnly_Directory = (ReadOnly | (6 << 8)), /// /// An operation is being aborted due to rollback processing. /// Abort_Rollback = (Abort | (2 << 8)), /// /// A CHECK constraint failed. /// Constraint_Check = (Constraint | (1 << 8)), /// /// A commit hook produced a unsuccessful return code. /// Constraint_CommitHook = (Constraint | (2 << 8)), /// /// A FOREIGN KEY constraint failed. /// Constraint_ForeignKey = (Constraint | (3 << 8)), /// /// Not currently used. /// Constraint_Function = (Constraint | (4 << 8)), /// /// A NOT NULL constraint failed. /// Constraint_NotNull = (Constraint | (5 << 8)), /// /// A PRIMARY KEY constraint failed. /// Constraint_PrimaryKey = (Constraint | (6 << 8)), /// /// The RAISE function was used by a trigger-program. /// Constraint_Trigger = (Constraint | (7 << 8)), /// /// A UNIQUE constraint failed. /// Constraint_Unique = (Constraint | (8 << 8)), /// /// Not currently used. /// Constraint_Vtab = (Constraint | (9 << 8)), /// /// A ROWID constraint failed. /// Constraint_RowId = (Constraint | (10 << 8)), /// /// Frames were recovered from the WAL log file. /// Notice_Recover_Wal = (Notice | (1 << 8)), /// /// Pages were recovered from the journal file. /// Notice_Recover_Rollback = (Notice | (2 << 8)), /// /// An automatic index was created to process a query. /// Warning_AutoIndex = (Warning | (1 << 8)), /// /// User authentication failed. /// Auth_User = (Auth | (1 << 8)), /// /// Success. Prevents the extension from unloading until the process /// terminates. /// Ok_Load_Permanently = (Ok | (1 << 8)) } }