/********************************************************
* 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))
}
}