Merge pull request #901 from Blewzman/FixAggregateExceptionGetBaseException
[mono.git] / mcs / class / Mono.Data.Sqlite / Mono.Data.Sqlite_2.0 / SQLiteBase.cs
1 /********************************************************\r
2  * ADO.NET 2.0 Data Provider for SQLite Version 3.X\r
3  * Written by Robert Simpson (robert@blackcastlesoft.com)\r
4  * \r
5  * Released to the public domain, use at your own risk!\r
6  ********************************************************/\r
7 \r
8 namespace Mono.Data.Sqlite\r
9 {\r
10   using System;\r
11   using System.Data;\r
12   using System.Runtime.InteropServices;\r
13   using System.Collections.Generic;\r
14 \r
15   /// <summary>\r
16   /// This internal class provides the foundation of SQLite support.  It defines all the abstract members needed to implement\r
17   /// a SQLite data provider, and inherits from SqliteConvert which allows for simple translations of string to and from SQLite.\r
18   /// </summary>\r
19   internal abstract class SQLiteBase : SqliteConvert, IDisposable\r
20   {\r
21     internal SQLiteBase(SQLiteDateFormats fmt)\r
22       : base(fmt) { }\r
23 \r
24     static internal object _lock = new object();\r
25 \r
26     /// <summary>\r
27     /// Returns a string representing the active version of SQLite\r
28     /// </summary>\r
29     internal abstract string Version { get; }\r
30     /// <summary>\r
31     /// Returns the number of changes the last executing insert/update caused.\r
32     /// </summary>\r
33     internal abstract int Changes { get; }\r
34     /// <summary>\r
35     /// Opens a database.\r
36     /// </summary>\r
37     /// <remarks>\r
38     /// Implementers should call SqliteFunction.BindFunctions() and save the array after opening a connection\r
39     /// to bind all attributed user-defined functions and collating sequences to the new connection.\r
40     /// </remarks>\r
41     /// <param name="strFilename">The filename of the database to open.  SQLite automatically creates it if it doesn't exist.</param>\r
42     /// <param name="flags">The open flags to use when creating the connection</param>\r
43     /// <param name="maxPoolSize">The maximum size of the pool for the given filename</param>\r
44     /// <param name="usePool">If true, the connection can be pulled from the connection pool</param>\r
45     internal abstract void Open(string strFilename, SQLiteOpenFlagsEnum flags, int maxPoolSize, bool usePool);\r
46     /// <summary>\r
47     /// Closes the currently-open database.\r
48     /// </summary>\r
49     /// <remarks>\r
50     /// After the database has been closed implemeters should call SqliteFunction.UnbindFunctions() to deallocate all interop allocated\r
51     /// memory associated with the user-defined functions and collating sequences tied to the closed connection.\r
52     /// </remarks>\r
53     internal abstract void Close();\r
54     /// <summary>\r
55     /// Sets the busy timeout on the connection.  SqliteCommand will call this before executing any command.\r
56     /// </summary>\r
57     /// <param name="nTimeoutMS">The number of milliseconds to wait before returning SQLITE_BUSY</param>\r
58     internal abstract void SetTimeout(int nTimeoutMS);\r
59     /// <summary>\r
60     /// Returns the text of the last error issued by SQLite\r
61     /// </summary>\r
62     /// <returns></returns>\r
63     internal abstract string SQLiteLastError();\r
64 \r
65     /// <summary>\r
66     /// When pooling is enabled, force this connection to be disposed rather than returned to the pool\r
67     /// </summary>\r
68     internal abstract void ClearPool();\r
69 \r
70     /// <summary>\r
71     /// Prepares a SQL statement for execution.\r
72     /// </summary>\r
73     /// <param name="cnn">The source connection preparing the command.  Can be null for any caller except LINQ</param>\r
74     /// <param name="strSql">The SQL command text to prepare</param>\r
75     /// <param name="previous">The previous statement in a multi-statement command, or null if no previous statement exists</param>\r
76     /// <param name="timeoutMS">The timeout to wait before aborting the prepare</param>\r
77     /// <param name="strRemain">The remainder of the statement that was not processed.  Each call to prepare parses the\r
78     /// SQL up to to either the end of the text or to the first semi-colon delimiter.  The remaining text is returned\r
79     /// here for a subsequent call to Prepare() until all the text has been processed.</param>\r
80     /// <returns>Returns an initialized SqliteStatement.</returns>\r
81     internal abstract SqliteStatement Prepare(SqliteConnection cnn, string strSql, SqliteStatement previous, uint timeoutMS, out string strRemain);\r
82     /// <summary>\r
83     /// Steps through a prepared statement.\r
84     /// </summary>\r
85     /// <param name="stmt">The SqliteStatement to step through</param>\r
86     /// <returns>True if a row was returned, False if not.</returns>\r
87     internal abstract bool Step(SqliteStatement stmt);\r
88     /// <summary>\r
89     /// Resets a prepared statement so it can be executed again.  If the error returned is SQLITE_SCHEMA, \r
90     /// transparently attempt to rebuild the SQL statement and throw an error if that was not possible.\r
91     /// </summary>\r
92     /// <param name="stmt">The statement to reset</param>\r
93     /// <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>\r
94     internal abstract int Reset(SqliteStatement stmt);\r
95     internal abstract void Cancel();\r
96 \r
97     internal abstract void Bind_Double(SqliteStatement stmt, int index, double value);\r
98     internal abstract void Bind_Int32(SqliteStatement stmt, int index, Int32 value);\r
99     internal abstract void Bind_Int64(SqliteStatement stmt, int index, Int64 value);\r
100     internal abstract void Bind_Text(SqliteStatement stmt, int index, string value);\r
101     internal abstract void Bind_Blob(SqliteStatement stmt, int index, byte[] blobData);\r
102     internal abstract void Bind_DateTime(SqliteStatement stmt, int index, DateTime dt);\r
103     internal abstract void Bind_Null(SqliteStatement stmt, int index);\r
104 \r
105     internal abstract int Bind_ParamCount(SqliteStatement stmt);\r
106     internal abstract string Bind_ParamName(SqliteStatement stmt, int index);\r
107     internal abstract int Bind_ParamIndex(SqliteStatement stmt, string paramName);\r
108 \r
109     internal abstract int ColumnCount(SqliteStatement stmt);\r
110     internal abstract string ColumnName(SqliteStatement stmt, int index);\r
111     internal abstract TypeAffinity ColumnAffinity(SqliteStatement stmt, int index);\r
112     internal abstract string ColumnType(SqliteStatement stmt, int index, out TypeAffinity nAffinity);\r
113     internal abstract int ColumnIndex(SqliteStatement stmt, string columnName);\r
114     internal abstract string ColumnOriginalName(SqliteStatement stmt, int index);\r
115     internal abstract string ColumnDatabaseName(SqliteStatement stmt, int index);\r
116     internal abstract string ColumnTableName(SqliteStatement stmt, int index);\r
117     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);\r
118     internal abstract void GetIndexColumnExtendedInfo(string database, string index, string column, out int sortMode, out int onError, out string collationSequence);\r
119 \r
120     internal abstract double GetDouble(SqliteStatement stmt, int index);\r
121     internal abstract Int32 GetInt32(SqliteStatement stmt, int index);\r
122     internal abstract Int64 GetInt64(SqliteStatement stmt, int index);\r
123     internal abstract string GetText(SqliteStatement stmt, int index);\r
124     internal abstract long GetBytes(SqliteStatement stmt, int index, int nDataoffset, byte[] bDest, int nStart, int nLength);\r
125     internal abstract long GetChars(SqliteStatement stmt, int index, int nDataoffset, char[] bDest, int nStart, int nLength);\r
126     internal abstract DateTime GetDateTime(SqliteStatement stmt, int index);\r
127     internal abstract bool IsNull(SqliteStatement stmt, int index);\r
128 \r
129     internal abstract void CreateCollation(string strCollation, SQLiteCollation func, SQLiteCollation func16, IntPtr user_data);\r
130     internal abstract void CreateFunction(string strFunction, int nArgs, bool needCollSeq, SQLiteCallback func, SQLiteCallback funcstep, SQLiteFinalCallback funcfinal);\r
131     internal abstract CollationSequence GetCollationSequence(SqliteFunction func, IntPtr context);\r
132     internal abstract int ContextCollateCompare(CollationEncodingEnum enc, IntPtr context, string s1, string s2);\r
133     internal abstract int ContextCollateCompare(CollationEncodingEnum enc, IntPtr context, char[] c1, char[] c2);\r
134 \r
135     internal abstract int AggregateCount(IntPtr context);\r
136     internal abstract IntPtr AggregateContext(IntPtr context);\r
137 \r
138     internal abstract long GetParamValueBytes(IntPtr ptr, int nDataOffset, byte[] bDest, int nStart, int nLength);\r
139     internal abstract double GetParamValueDouble(IntPtr ptr);\r
140     internal abstract int GetParamValueInt32(IntPtr ptr);\r
141     internal abstract Int64 GetParamValueInt64(IntPtr ptr);\r
142     internal abstract string GetParamValueText(IntPtr ptr);\r
143     internal abstract TypeAffinity GetParamValueType(IntPtr ptr);\r
144 \r
145     internal abstract void ReturnBlob(IntPtr context, byte[] value);\r
146     internal abstract void ReturnDouble(IntPtr context, double value);\r
147     internal abstract void ReturnError(IntPtr context, string value);\r
148     internal abstract void ReturnInt32(IntPtr context, Int32 value);\r
149     internal abstract void ReturnInt64(IntPtr context, Int64 value);\r
150     internal abstract void ReturnNull(IntPtr context);\r
151     internal abstract void ReturnText(IntPtr context, string value);\r
152 \r
153     internal abstract void SetPassword(byte[] passwordBytes);\r
154     internal abstract void ChangePassword(byte[] newPasswordBytes);\r
155 \r
156     internal abstract void SetUpdateHook(SQLiteUpdateCallback func);\r
157     internal abstract void SetCommitHook(SQLiteCommitCallback func);\r
158     internal abstract void SetRollbackHook(SQLiteRollbackCallback func);\r
159 \r
160     internal abstract int GetCursorForTable(SqliteStatement stmt, int database, int rootPage);\r
161     internal abstract long GetRowIdForCursor(SqliteStatement stmt, int cursor);\r
162 \r
163     internal abstract object GetValue(SqliteStatement stmt, int index, SQLiteType typ);\r
164 \r
165     protected virtual void Dispose(bool bDisposing)\r
166     {\r
167     }\r
168 \r
169     public void Dispose()\r
170     {\r
171       Dispose(true);\r
172     }\r
173 \r
174     // These statics are here for lack of a better place to put them.\r
175     // They exist here because they are called during the finalization of\r
176     // a SqliteStatementHandle, SqliteConnectionHandle, and SqliteFunctionCookieHandle.\r
177     // Therefore these functions have to be static, and have to be low-level.\r
178 \r
179     internal static string SQLiteLastError(SqliteConnectionHandle db)\r
180     {\r
181 #if !SQLITE_STANDARD\r
182       int len;\r
183       return UTF8ToString(UnsafeNativeMethods.sqlite3_errmsg_interop(db, out len), len);\r
184 #else\r
185       return UTF8ToString(UnsafeNativeMethods.sqlite3_errmsg(db), -1);\r
186 #endif\r
187     }\r
188 \r
189     internal static void FinalizeStatement(SqliteStatementHandle stmt)\r
190     {\r
191       lock (_lock)\r
192       {\r
193 #if !SQLITE_STANDARD\r
194         int n = UnsafeNativeMethods.sqlite3_finalize_interop(stmt);\r
195 #else\r
196       int n = UnsafeNativeMethods.sqlite3_finalize(stmt);\r
197 #endif\r
198         if (n > 0) throw new SqliteException(n, null);\r
199       }\r
200     }\r
201 \r
202     internal static void CloseConnection(SqliteConnectionHandle db)\r
203     {\r
204       lock (_lock)\r
205       {\r
206 #if !SQLITE_STANDARD\r
207         int n = UnsafeNativeMethods.sqlite3_close_interop(db);\r
208 #else\r
209       ResetConnection(db);\r
210       int n = UnsafeNativeMethods.sqlite3_close(db);\r
211 #endif\r
212         if (n > 0) throw new SqliteException(n, SQLiteLastError(db));\r
213       }\r
214     }\r
215 \r
216     internal static void ResetConnection(SqliteConnectionHandle db)\r
217     {\r
218       lock (_lock)\r
219       {\r
220         IntPtr stmt = IntPtr.Zero;\r
221 \r
222         do\r
223         {\r
224           stmt = UnsafeNativeMethods.sqlite3_next_stmt(db, stmt);\r
225           if (stmt != IntPtr.Zero)\r
226           {\r
227 #if !SQLITE_STANDARD\r
228             UnsafeNativeMethods.sqlite3_reset_interop(stmt);\r
229 #else\r
230           UnsafeNativeMethods.sqlite3_reset(stmt);\r
231 #endif\r
232           }\r
233         } while (stmt != IntPtr.Zero);\r
234 \r
235         // Not overly concerned with the return value from a rollback.\r
236         UnsafeNativeMethods.sqlite3_exec(db, ToUTF8("ROLLBACK"), IntPtr.Zero, IntPtr.Zero, out stmt);\r
237         // but free the error message if any!\r
238         if (stmt != IntPtr.Zero)\r
239           UnsafeNativeMethods.sqlite3_free (stmt);\r
240       }\r
241     }\r
242   }\r
243 \r
244   internal interface ISQLiteSchemaExtensions\r
245   {\r
246     void BuildTempSchema(SqliteConnection cnn);\r
247   }\r
248 \r
249   [Flags]\r
250   internal enum SQLiteOpenFlagsEnum\r
251   {\r
252     None = 0,\r
253     ReadOnly = 0x01,\r
254     ReadWrite = 0x02,\r
255     Create = 0x04,\r
256     //SharedCache = 0x01000000,\r
257     Default = 0x06,\r
258 \r
259     // iOS Specific\r
260     FileProtectionComplete = 0x00100000,\r
261     FileProtectionCompleteUnlessOpen = 0x00200000,\r
262     FileProtectionCompleteUntilFirstUserAuthentication = 0x00300000,\r
263     FileProtectionNone = 0x00400000\r
264   }\r
265 \r
266   // subset of the options available in http://www.sqlite.org/c3ref/c_config_getmalloc.html\r
267   public enum SQLiteConfig {\r
268     SingleThread = 1,\r
269     MultiThread = 2,\r
270     Serialized = 3,\r
271   }\r
272 }\r