forked from jstedfast/MimeKit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSQLiteBase.cs
277 lines (246 loc) · 12.5 KB
/
SQLiteBase.cs
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 ([email protected])
*
* 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,
}
}