1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
|
/********************************************************
* 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 Mono.Data.Sqlite
{
using System;
using System.Data;
using System.Runtime.InteropServices;
using System.Collections.Generic;
/// <summary>
/// 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.
/// </summary>
internal abstract class SQLiteBase : SqliteConvert, IDisposable
{
internal SQLiteBase(SQLiteDateFormats fmt)
: base(fmt) { }
static internal object _lock = new object();
/// <summary>
/// Returns a string representing the active version of SQLite
/// </summary>
internal abstract string Version { get; }
/// <summary>
/// Returns the number of changes the last executing insert/update caused.
/// </summary>
internal abstract int Changes { get; }
/// <summary>
/// Opens a database.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
/// <param name="strFilename">The filename of the database to open. SQLite automatically creates it if it doesn't exist.</param>
/// <param name="flags">The open flags to use when creating the connection</param>
/// <param name="maxPoolSize">The maximum size of the pool for the given filename</param>
/// <param name="usePool">If true, the connection can be pulled from the connection pool</param>
internal abstract void Open(string strFilename, SQLiteOpenFlagsEnum flags, int maxPoolSize, bool usePool);
/// <summary>
/// Closes the currently-open database.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
internal abstract void Close();
/// <summary>
/// Sets the busy timeout on the connection. SqliteCommand will call this before executing any command.
/// </summary>
/// <param name="nTimeoutMS">The number of milliseconds to wait before returning SQLITE_BUSY</param>
internal abstract void SetTimeout(int nTimeoutMS);
/// <summary>
/// Returns the text of the last error issued by SQLite
/// </summary>
/// <returns></returns>
internal abstract string SQLiteLastError();
/// <summary>
/// When pooling is enabled, force this connection to be disposed rather than returned to the pool
/// </summary>
internal abstract void ClearPool();
/// <summary>
/// Prepares a SQL statement for execution.
/// </summary>
/// <param name="cnn">The source connection preparing the command. Can be null for any caller except LINQ</param>
/// <param name="strSql">The SQL command text to prepare</param>
/// <param name="previous">The previous statement in a multi-statement command, or null if no previous statement exists</param>
/// <param name="timeoutMS">The timeout to wait before aborting the prepare</param>
/// <param name="strRemain">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.</param>
/// <returns>Returns an initialized SqliteStatement.</returns>
internal abstract SqliteStatement Prepare(SqliteConnection cnn, string strSql, SqliteStatement previous, uint timeoutMS, out string strRemain);
/// <summary>
/// Steps through a prepared statement.
/// </summary>
/// <param name="stmt">The SqliteStatement to step through</param>
/// <returns>True if a row was returned, False if not.</returns>
internal abstract bool Step(SqliteStatement stmt);
/// <summary>
/// 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.
/// </summary>
/// <param name="stmt">The statement to reset</param>
/// <returns>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</returns>
internal abstract int Reset(SqliteStatement stmt);
internal abstract void Cancel();
internal abstract void Bind_Double(SqliteStatement stmt, int index, double value);
internal abstract void Bind_Int32(SqliteStatement stmt, int index, Int32 value);
internal abstract void Bind_Int64(SqliteStatement stmt, int index, Int64 value);
internal abstract void Bind_Text(SqliteStatement stmt, int index, string value);
internal abstract void Bind_Blob(SqliteStatement stmt, int index, byte[] blobData);
internal abstract void Bind_DateTime(SqliteStatement stmt, int index, DateTime dt);
internal abstract void Bind_Null(SqliteStatement stmt, int index);
internal abstract int Bind_ParamCount(SqliteStatement stmt);
internal abstract string Bind_ParamName(SqliteStatement stmt, int index);
internal abstract int Bind_ParamIndex(SqliteStatement stmt, 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, out 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 void ColumnMetaData(string dataBase, string table, string column, out string dataType, out string collateSequence, out bool notNull, out bool primaryKey, out bool autoIncrement);
internal abstract void GetIndexColumnExtendedInfo(string database, string index, string column, out int sortMode, out int onError, out string collationSequence);
internal abstract double GetDouble(SqliteStatement stmt, int index);
internal abstract Int32 GetInt32(SqliteStatement stmt, int index);
internal abstract Int64 GetInt64(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 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 void CreateCollation(string strCollation, SQLiteCollation func, SQLiteCollation func16, IntPtr user_data);
internal abstract void CreateFunction(string strFunction, int nArgs, bool needCollSeq, SQLiteCallback func, SQLiteCallback funcstep, SQLiteFinalCallback funcfinal);
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);
internal abstract void SetPassword(byte[] passwordBytes);
internal abstract void ChangePassword(byte[] newPasswordBytes);
internal abstract void SetUpdateHook(SQLiteUpdateCallback func);
internal abstract void SetCommitHook(SQLiteCommitCallback func);
internal abstract void SetRollbackHook(SQLiteRollbackCallback func);
internal abstract int GetCursorForTable(SqliteStatement stmt, int database, int rootPage);
internal abstract long GetRowIdForCursor(SqliteStatement stmt, int cursor);
internal abstract object GetValue(SqliteStatement stmt, int index, SQLiteType typ);
protected virtual void Dispose(bool bDisposing)
{
}
public void Dispose()
{
Dispose(true);
}
// 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.
internal static string SQLiteLastError(SqliteConnectionHandle db)
{
#if !SQLITE_STANDARD
int len;
return UTF8ToString(UnsafeNativeMethods.sqlite3_errmsg_interop(db, out len), len);
#else
return UTF8ToString(UnsafeNativeMethods.sqlite3_errmsg(db), -1);
#endif
}
internal static void FinalizeStatement(SqliteStatementHandle stmt)
{
lock (_lock)
{
#if !SQLITE_STANDARD
int n = UnsafeNativeMethods.sqlite3_finalize_interop(stmt);
#else
int n = UnsafeNativeMethods.sqlite3_finalize(stmt);
#endif
if (n > 0) throw new SqliteException(n, null);
}
}
internal static void CloseConnection(SqliteConnectionHandle db)
{
lock (_lock)
{
#if !SQLITE_STANDARD
int n = UnsafeNativeMethods.sqlite3_close_interop(db);
#else
ResetConnection(db);
int n;
if (UnsafeNativeMethods.use_sqlite3_close_v2) {
n = UnsafeNativeMethods.sqlite3_close_v2(db);
} else {
n = UnsafeNativeMethods.sqlite3_close(db);
}
#endif
if (n > 0) throw new SqliteException(n, SQLiteLastError(db));
}
}
internal static void ResetConnection(SqliteConnectionHandle db)
{
lock (_lock)
{
IntPtr stmt = IntPtr.Zero;
do
{
stmt = UnsafeNativeMethods.sqlite3_next_stmt(db, stmt);
if (stmt != IntPtr.Zero)
{
#if !SQLITE_STANDARD
UnsafeNativeMethods.sqlite3_reset_interop(stmt);
#else
UnsafeNativeMethods.sqlite3_reset(stmt);
#endif
}
} while (stmt != IntPtr.Zero);
// Not overly concerned with the return value from a rollback.
UnsafeNativeMethods.sqlite3_exec(db, ToUTF8("ROLLBACK"), IntPtr.Zero, IntPtr.Zero, out stmt);
// but free the error message if any!
if (stmt != IntPtr.Zero)
UnsafeNativeMethods.sqlite3_free (stmt);
}
}
}
internal interface ISQLiteSchemaExtensions
{
void BuildTempSchema(SqliteConnection cnn);
}
[Flags]
internal enum SQLiteOpenFlagsEnum
{
None = 0,
ReadOnly = 0x01,
ReadWrite = 0x02,
Create = 0x04,
//SharedCache = 0x01000000,
Default = 0x06,
// iOS Specific
FileProtectionComplete = 0x00100000,
FileProtectionCompleteUnlessOpen = 0x00200000,
FileProtectionCompleteUntilFirstUserAuthentication = 0x00300000,
FileProtectionNone = 0x00400000
}
// subset of the options available in http://www.sqlite.org/c3ref/c_config_getmalloc.html
public enum SQLiteConfig {
SingleThread = 1,
MultiThread = 2,
Serialized = 3,
}
}
|