1 /********************************************************
\r
2 * ADO.NET 2.0 Data Provider for SQLite Version 3.X
\r
3 * Written by Robert Simpson (robert@blackcastlesoft.com)
\r
5 * Released to the public domain, use at your own risk!
\r
6 ********************************************************/
\r
8 namespace Mono.Data.Sqlite
\r
12 using System.Runtime.InteropServices;
\r
13 using System.Collections.Generic;
\r
14 using System.Globalization;
\r
17 /// This class implements SQLiteBase completely, and is the guts of the code that interop's SQLite with .NET
\r
19 internal class SQLite3 : SQLiteBase
\r
22 /// The opaque pointer returned to us by the sqlite provider
\r
24 protected SqliteConnectionHandle _sql;
\r
25 protected string _fileName;
\r
26 protected bool _usePool;
\r
27 protected int _poolVersion = 0;
\r
29 #if !PLATFORM_COMPACTFRAMEWORK
\r
30 private bool _buildingSchema = false;
\r
36 /// The user-defined functions registered on this connection
\r
38 protected SqliteFunction[] _functionsArray;
\r
40 internal SQLite3(SQLiteDateFormats fmt)
\r
44 gch = GCHandle.Alloc (this);
\r
48 protected override void Dispose(bool bDisposing)
\r
54 // It isn't necessary to cleanup any functions we've registered. If the connection
\r
55 // goes to the pool and is resurrected later, re-registered functions will overwrite the
\r
56 // previous functions. The SqliteFunctionCookieHandle will take care of freeing unmanaged
\r
57 // resources belonging to the previously-registered functions.
\r
58 internal override void Close()
\r
64 SQLiteBase.ResetConnection(_sql);
\r
65 SqliteConnectionPool.Add(_fileName, _sql, _poolVersion);
\r
73 if (gch.IsAllocated)
\r
78 internal override void Cancel()
\r
80 UnsafeNativeMethods.sqlite3_interrupt(_sql);
\r
83 internal override string Version
\r
87 return SQLite3.SQLiteVersion;
\r
91 internal static string SQLiteVersion
\r
95 return UTF8ToString(UnsafeNativeMethods.sqlite3_libversion(), -1);
\r
99 internal override int Changes
\r
103 return UnsafeNativeMethods.sqlite3_changes(_sql);
\r
107 internal override void Open(string strFilename, SQLiteOpenFlagsEnum flags, int maxPoolSize, bool usePool)
\r
109 if (_sql != null) return;
\r
111 _usePool = usePool;
\r
114 _fileName = strFilename;
\r
115 _sql = SqliteConnectionPool.Remove(strFilename, maxPoolSize, out _poolVersion);
\r
122 #if !SQLITE_STANDARD
\r
123 int n = UnsafeNativeMethods.sqlite3_open_interop(ToUTF8(strFilename), (int)flags, out db);
\r
125 // Compatibility with versions < 3.5.0
\r
129 n = UnsafeNativeMethods.sqlite3_open_v2(ToUTF8(strFilename), out db, (int)flags, IntPtr.Zero);
\r
130 } catch (EntryPointNotFoundException) {
\r
131 Console.WriteLine ("Your sqlite3 version is old - please upgrade to at least v3.5.0!");
\r
132 n = UnsafeNativeMethods.sqlite3_open (ToUTF8 (strFilename), out db);
\r
136 if (n > 0) throw new SqliteException(n, null);
\r
140 // Bind functions to this connection. If any previous functions of the same name
\r
141 // were already bound, then the new bindings replace the old.
\r
142 _functionsArray = SqliteFunction.BindFunctions(this);
\r
146 internal override void ClearPool()
\r
148 SqliteConnectionPool.ClearPool(_fileName);
\r
151 internal override void SetTimeout(int nTimeoutMS)
\r
153 int n = UnsafeNativeMethods.sqlite3_busy_timeout(_sql, nTimeoutMS);
\r
154 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
157 internal override bool Step(SqliteStatement stmt)
\r
161 uint starttick = (uint)Environment.TickCount;
\r
162 uint timeout = (uint)(stmt._command._commandTimeout * 1000);
\r
166 n = UnsafeNativeMethods.sqlite3_step(stmt._sqlite_stmt);
\r
168 if (n == 100) return true;
\r
169 if (n == 101) return false;
\r
175 // An error occurred, attempt to reset the statement. If the reset worked because the
\r
176 // schema has changed, re-try the step again. If it errored our because the database
\r
177 // is locked, then keep retrying until the command timeout occurs.
\r
181 throw new SqliteException(n, SQLiteLastError());
\r
183 else if ((r == 6 || r == 5) && stmt._command != null) // SQLITE_LOCKED || SQLITE_BUSY
\r
186 if (rnd == null) // First time we've encountered the lock
\r
187 rnd = new Random();
\r
189 // If we've exceeded the command's timeout, give up and throw an error
\r
190 if ((uint)Environment.TickCount - starttick > timeout)
\r
192 throw new SqliteException(r, SQLiteLastError());
\r
196 // Otherwise sleep for a random amount of time up to 150ms
\r
197 System.Threading.Thread.CurrentThread.Join(rnd.Next(1, 150));
\r
204 internal override int Reset(SqliteStatement stmt)
\r
208 #if !SQLITE_STANDARD
\r
209 n = UnsafeNativeMethods.sqlite3_reset_interop(stmt._sqlite_stmt);
\r
211 n = UnsafeNativeMethods.sqlite3_reset(stmt._sqlite_stmt);
\r
214 // If the schema changed, try and re-prepare it
\r
215 if (n == 17) // SQLITE_SCHEMA
\r
217 // Recreate a dummy statement
\r
219 using (SqliteStatement tmp = Prepare(null, stmt._sqlStatement, null, (uint)(stmt._command._commandTimeout * 1000), out str))
\r
221 // Finalize the existing statement
\r
222 stmt._sqlite_stmt.Dispose();
\r
223 // Reassign a new statement pointer to the old statement and clear the temporary one
\r
224 stmt._sqlite_stmt = tmp._sqlite_stmt;
\r
225 tmp._sqlite_stmt = null;
\r
227 // Reapply parameters
\r
228 stmt.BindParameters();
\r
230 return -1; // Reset was OK, with schema change
\r
232 else if (n == 6 || n == 5) // SQLITE_LOCKED || SQLITE_BUSY
\r
236 throw new SqliteException(n, SQLiteLastError());
\r
238 return 0; // We reset OK, no schema changes
\r
241 internal override string SQLiteLastError()
\r
243 return SQLiteBase.SQLiteLastError(_sql);
\r
246 internal override SqliteStatement Prepare(SqliteConnection cnn, string strSql, SqliteStatement previous, uint timeoutMS, out string strRemain)
\r
248 IntPtr stmt = IntPtr.Zero;
\r
249 IntPtr ptr = IntPtr.Zero;
\r
253 byte[] b = ToUTF8(strSql);
\r
254 string typedefs = null;
\r
255 SqliteStatement cmd = null;
\r
257 uint starttick = (uint)Environment.TickCount;
\r
259 GCHandle handle = GCHandle.Alloc(b, GCHandleType.Pinned);
\r
260 IntPtr psql = handle.AddrOfPinnedObject();
\r
263 while ((n == 17 || n == 6 || n == 5) && retries < 3)
\r
265 #if !SQLITE_STANDARD
\r
266 n = UnsafeNativeMethods.sqlite3_prepare_interop(_sql, psql, b.Length - 1, out stmt, out ptr, out len);
\r
268 n = UnsafeNativeMethods.sqlite3_prepare(_sql, psql, b.Length - 1, out stmt, out ptr);
\r
276 if (String.Compare(SQLiteLastError(), "near \"TYPES\": syntax error", StringComparison.OrdinalIgnoreCase) == 0)
\r
278 int pos = strSql.IndexOf(';');
\r
279 if (pos == -1) pos = strSql.Length - 1;
\r
281 typedefs = strSql.Substring(0, pos + 1);
\r
282 strSql = strSql.Substring(pos + 1);
\r
286 while (cmd == null && strSql.Length > 0)
\r
288 cmd = Prepare(cnn, strSql, previous, timeoutMS, out strRemain);
\r
289 strSql = strRemain;
\r
293 cmd.SetTypes(typedefs);
\r
297 #if !PLATFORM_COMPACTFRAMEWORK
\r
298 else if (_buildingSchema == false && String.Compare(SQLiteLastError(), 0, "no such table: TEMP.SCHEMA", 0, 26, StringComparison.OrdinalIgnoreCase) == 0)
\r
301 _buildingSchema = true;
\r
304 ISQLiteSchemaExtensions ext = ((IServiceProvider)SqliteFactory.Instance).GetService(typeof(ISQLiteSchemaExtensions)) as ISQLiteSchemaExtensions;
\r
307 ext.BuildTempSchema(cnn);
\r
309 while (cmd == null && strSql.Length > 0)
\r
311 cmd = Prepare(cnn, strSql, previous, timeoutMS, out strRemain);
\r
312 strSql = strRemain;
\r
319 _buildingSchema = false;
\r
324 else if (n == 6 || n == 5) // Locked -- delay a small amount before retrying
\r
327 if (rnd == null) // First time we've encountered the lock
\r
328 rnd = new Random();
\r
330 // If we've exceeded the command's timeout, give up and throw an error
\r
331 if ((uint)Environment.TickCount - starttick > timeoutMS)
\r
333 throw new SqliteException(n, SQLiteLastError());
\r
337 // Otherwise sleep for a random amount of time up to 150ms
\r
338 System.Threading.Thread.CurrentThread.Join(rnd.Next(1, 150));
\r
343 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
345 strRemain = UTF8ToString(ptr, len);
\r
347 if (stmt != IntPtr.Zero) cmd = new SqliteStatement(this, stmt, strSql.Substring(0, strSql.Length - strRemain.Length), previous);
\r
357 internal override void Bind_Double(SqliteStatement stmt, int index, double value)
\r
359 #if !PLATFORM_COMPACTFRAMEWORK
\r
360 int n = UnsafeNativeMethods.sqlite3_bind_double(stmt._sqlite_stmt, index, value);
\r
362 int n = UnsafeNativeMethods.sqlite3_bind_double_interop(stmt._sqlite_stmt, index, ref value);
\r
364 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
367 internal override void Bind_Int32(SqliteStatement stmt, int index, int value)
\r
369 int n = UnsafeNativeMethods.sqlite3_bind_int(stmt._sqlite_stmt, index, value);
\r
370 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
373 internal override void Bind_Int64(SqliteStatement stmt, int index, long value)
\r
375 #if !PLATFORM_COMPACTFRAMEWORK
\r
376 int n = UnsafeNativeMethods.sqlite3_bind_int64(stmt._sqlite_stmt, index, value);
\r
378 int n = UnsafeNativeMethods.sqlite3_bind_int64_interop(stmt._sqlite_stmt, index, ref value);
\r
380 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
383 internal override void Bind_Text(SqliteStatement stmt, int index, string value)
\r
385 byte[] b = ToUTF8(value);
\r
386 int n = UnsafeNativeMethods.sqlite3_bind_text(stmt._sqlite_stmt, index, b, b.Length - 1, (IntPtr)(-1));
\r
387 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
390 internal override void Bind_DateTime(SqliteStatement stmt, int index, DateTime dt)
\r
392 byte[] b = ToUTF8(dt);
\r
393 int n = UnsafeNativeMethods.sqlite3_bind_text(stmt._sqlite_stmt, index, b, b.Length - 1, (IntPtr)(-1));
\r
394 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
397 internal override void Bind_Blob(SqliteStatement stmt, int index, byte[] blobData)
\r
399 int n = UnsafeNativeMethods.sqlite3_bind_blob(stmt._sqlite_stmt, index, blobData, blobData.Length, (IntPtr)(-1));
\r
400 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
403 internal override void Bind_Null(SqliteStatement stmt, int index)
\r
405 int n = UnsafeNativeMethods.sqlite3_bind_null(stmt._sqlite_stmt, index);
\r
406 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
409 internal override int Bind_ParamCount(SqliteStatement stmt)
\r
411 return UnsafeNativeMethods.sqlite3_bind_parameter_count(stmt._sqlite_stmt);
\r
414 internal override string Bind_ParamName(SqliteStatement stmt, int index)
\r
416 #if !SQLITE_STANDARD
\r
418 return UTF8ToString(UnsafeNativeMethods.sqlite3_bind_parameter_name_interop(stmt._sqlite_stmt, index, out len), len);
\r
420 return UTF8ToString(UnsafeNativeMethods.sqlite3_bind_parameter_name(stmt._sqlite_stmt, index), -1);
\r
424 internal override int Bind_ParamIndex(SqliteStatement stmt, string paramName)
\r
426 return UnsafeNativeMethods.sqlite3_bind_parameter_index(stmt._sqlite_stmt, ToUTF8(paramName));
\r
429 internal override int ColumnCount(SqliteStatement stmt)
\r
431 return UnsafeNativeMethods.sqlite3_column_count(stmt._sqlite_stmt);
\r
434 internal override string ColumnName(SqliteStatement stmt, int index)
\r
436 #if !SQLITE_STANDARD
\r
438 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_name_interop(stmt._sqlite_stmt, index, out len), len);
\r
440 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_name(stmt._sqlite_stmt, index), -1);
\r
444 internal override TypeAffinity ColumnAffinity(SqliteStatement stmt, int index)
\r
446 return UnsafeNativeMethods.sqlite3_column_type(stmt._sqlite_stmt, index);
\r
449 internal override string ColumnType(SqliteStatement stmt, int index, out TypeAffinity nAffinity)
\r
452 #if !SQLITE_STANDARD
\r
453 IntPtr p = UnsafeNativeMethods.sqlite3_column_decltype_interop(stmt._sqlite_stmt, index, out len);
\r
456 IntPtr p = UnsafeNativeMethods.sqlite3_column_decltype(stmt._sqlite_stmt, index);
\r
458 nAffinity = ColumnAffinity(stmt, index);
\r
460 if (p != IntPtr.Zero) return UTF8ToString(p, len);
\r
463 string[] ar = stmt.TypeDefinitions;
\r
466 if (index < ar.Length && ar[index] != null)
\r
469 return String.Empty;
\r
471 //switch (nAffinity)
\r
473 // case TypeAffinity.Int64:
\r
474 // return "BIGINT";
\r
475 // case TypeAffinity.Double:
\r
476 // return "DOUBLE";
\r
477 // case TypeAffinity.Blob:
\r
485 internal override int ColumnIndex(SqliteStatement stmt, string columnName)
\r
487 int x = ColumnCount(stmt);
\r
489 for (int n = 0; n < x; n++)
\r
491 if (String.Compare(columnName, ColumnName(stmt, n), true, CultureInfo.InvariantCulture) == 0)
\r
497 internal override string ColumnOriginalName(SqliteStatement stmt, int index)
\r
499 #if !SQLITE_STANDARD
\r
501 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_origin_name_interop(stmt._sqlite_stmt, index, out len), len);
\r
503 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_origin_name(stmt._sqlite_stmt, index), -1);
\r
507 internal override string ColumnDatabaseName(SqliteStatement stmt, int index)
\r
509 #if !SQLITE_STANDARD
\r
511 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_database_name_interop(stmt._sqlite_stmt, index, out len), len);
\r
513 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_database_name(stmt._sqlite_stmt, index), -1);
\r
517 internal override string ColumnTableName(SqliteStatement stmt, int index)
\r
519 #if !SQLITE_STANDARD
\r
521 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_table_name_interop(stmt._sqlite_stmt, index, out len), len);
\r
523 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_table_name(stmt._sqlite_stmt, index), -1);
\r
527 internal override void ColumnMetaData(string dataBase, string table, string column, out string dataType, out string collateSequence, out bool notNull, out bool primaryKey, out bool autoIncrement)
\r
529 IntPtr dataTypePtr;
\r
538 #if !SQLITE_STANDARD
\r
539 n = UnsafeNativeMethods.sqlite3_table_column_metadata_interop(_sql, ToUTF8(dataBase), ToUTF8(table), ToUTF8(column), out dataTypePtr, out collSeqPtr, out nnotNull, out nprimaryKey, out nautoInc, out dtLen, out csLen);
\r
543 n = UnsafeNativeMethods.sqlite3_table_column_metadata(_sql, ToUTF8(dataBase), ToUTF8(table), ToUTF8(column), out dataTypePtr, out collSeqPtr, out nnotNull, out nprimaryKey, out nautoInc);
\r
545 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
547 dataType = UTF8ToString(dataTypePtr, dtLen);
\r
548 collateSequence = UTF8ToString(collSeqPtr, csLen);
\r
550 notNull = (nnotNull == 1);
\r
551 primaryKey = (nprimaryKey == 1);
\r
552 autoIncrement = (nautoInc == 1);
\r
555 internal override double GetDouble(SqliteStatement stmt, int index)
\r
558 #if !PLATFORM_COMPACTFRAMEWORK
\r
559 value = UnsafeNativeMethods.sqlite3_column_double(stmt._sqlite_stmt, index);
\r
561 UnsafeNativeMethods.sqlite3_column_double_interop(stmt._sqlite_stmt, index, out value);
\r
566 internal override int GetInt32(SqliteStatement stmt, int index)
\r
568 return UnsafeNativeMethods.sqlite3_column_int(stmt._sqlite_stmt, index);
\r
571 internal override long GetInt64(SqliteStatement stmt, int index)
\r
574 #if !PLATFORM_COMPACTFRAMEWORK
\r
575 value = UnsafeNativeMethods.sqlite3_column_int64(stmt._sqlite_stmt, index);
\r
577 UnsafeNativeMethods.sqlite3_column_int64_interop(stmt._sqlite_stmt, index, out value);
\r
582 internal override string GetText(SqliteStatement stmt, int index)
\r
584 #if !SQLITE_STANDARD
\r
586 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_text_interop(stmt._sqlite_stmt, index, out len), len);
\r
588 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_text(stmt._sqlite_stmt, index), -1);
\r
592 internal override DateTime GetDateTime(SqliteStatement stmt, int index)
\r
594 #if !SQLITE_STANDARD
\r
596 return ToDateTime(UnsafeNativeMethods.sqlite3_column_text_interop(stmt._sqlite_stmt, index, out len), len);
\r
598 return ToDateTime(UnsafeNativeMethods.sqlite3_column_text(stmt._sqlite_stmt, index), -1);
\r
602 internal override long GetBytes(SqliteStatement stmt, int index, int nDataOffset, byte[] bDest, int nStart, int nLength)
\r
606 int nCopied = nLength;
\r
608 nlen = UnsafeNativeMethods.sqlite3_column_bytes(stmt._sqlite_stmt, index);
\r
609 ptr = UnsafeNativeMethods.sqlite3_column_blob(stmt._sqlite_stmt, index);
\r
611 if (bDest == null) return nlen;
\r
613 if (nCopied + nStart > bDest.Length) nCopied = bDest.Length - nStart;
\r
614 if (nCopied + nDataOffset > nlen) nCopied = nlen - nDataOffset;
\r
618 Marshal.Copy((IntPtr)((byte*)ptr + nDataOffset), bDest, nStart, nCopied);
\r
625 internal override long GetChars(SqliteStatement stmt, int index, int nDataOffset, char[] bDest, int nStart, int nLength)
\r
628 int nCopied = nLength;
\r
630 string str = GetText(stmt, index);
\r
633 if (bDest == null) return nlen;
\r
635 if (nCopied + nStart > bDest.Length) nCopied = bDest.Length - nStart;
\r
636 if (nCopied + nDataOffset > nlen) nCopied = nlen - nDataOffset;
\r
639 str.CopyTo(nDataOffset, bDest, nStart, nCopied);
\r
645 internal override bool IsNull(SqliteStatement stmt, int index)
\r
647 return (ColumnAffinity(stmt, index) == TypeAffinity.Null);
\r
650 internal override int AggregateCount(IntPtr context)
\r
652 return UnsafeNativeMethods.sqlite3_aggregate_count(context);
\r
656 class FunctionData {
\r
657 public SQLiteCallback Func;
\r
658 public SQLiteCallback FuncStep;
\r
659 public SQLiteFinalCallback FuncFinal;
\r
663 internal override void CreateFunction(string strFunction, int nArgs, bool needCollSeq, SQLiteCallback func, SQLiteCallback funcstep, SQLiteFinalCallback funcfinal)
\r
668 var data = new FunctionData();
\r
670 data.FuncStep = funcstep;
\r
671 data.FuncFinal = funcfinal;
\r
672 SQLiteCallback func_callback = func == null ? null : new SQLiteCallback(scalar_callback);
\r
673 SQLiteCallback funcstep_callback = funcstep == null ? null : new SQLiteCallback(step_callback);
\r
674 SQLiteFinalCallback funcfinal_callback = funcfinal == null ? null : new SQLiteFinalCallback(final_callback);
\r
677 user_data = GCHandle.ToIntPtr(GCHandle.Alloc(data));
\r
678 n = UnsafeNativeMethods.sqlite3_create_function_v2(_sql, ToUTF8(strFunction), nArgs, 4, user_data, func_callback, funcstep_callback, funcfinal_callback, destroy_callback);
\r
681 // sqlite3_create_function_v2 will call 'destroy_callback' if it fails, so we need to recreate the gchandle here.
\r
682 user_data = GCHandle.ToIntPtr(GCHandle.Alloc(data));
\r
683 n = UnsafeNativeMethods.sqlite3_create_function_v2(_sql, ToUTF8(strFunction), nArgs, 1, user_data, func_callback, funcstep_callback, funcfinal_callback, destroy_callback);
\r
685 #elif !SQLITE_STANDARD
\r
686 n = UnsafeNativeMethods.sqlite3_create_function_interop(_sql, ToUTF8(strFunction), nArgs, 4, IntPtr.Zero, func, funcstep, funcfinal, (needCollSeq == true) ? 1 : 0);
\r
687 if (n == 0) n = UnsafeNativeMethods.sqlite3_create_function_interop(_sql, ToUTF8(strFunction), nArgs, 1, IntPtr.Zero, func, funcstep, funcfinal, (needCollSeq == true) ? 1 : 0);
\r
689 n = UnsafeNativeMethods.sqlite3_create_function(_sql, ToUTF8(strFunction), nArgs, 4, IntPtr.Zero, func, funcstep, funcfinal);
\r
690 if (n == 0) n = UnsafeNativeMethods.sqlite3_create_function(_sql, ToUTF8(strFunction), nArgs, 1, IntPtr.Zero, func, funcstep, funcfinal);
\r
692 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
695 internal override void CreateCollation(string strCollation, SQLiteCollation func, SQLiteCollation func16, IntPtr user_data)
\r
697 int n = UnsafeNativeMethods.sqlite3_create_collation(_sql, ToUTF8(strCollation), 2, user_data, func16);
\r
698 if (n == 0) UnsafeNativeMethods.sqlite3_create_collation(_sql, ToUTF8(strCollation), 1, user_data, func);
\r
699 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
703 [MonoTouch.MonoPInvokeCallback(typeof(SQLiteCallback))]
\r
704 internal static void scalar_callback(IntPtr context, int nArgs, IntPtr argsptr)
\r
706 var handle = GCHandle.FromIntPtr (UnsafeNativeMethods.sqlite3_user_data(context));
\r
707 var func = (FunctionData)handle.Target;
\r
708 func.Func(context, nArgs, argsptr);
\r
711 [MonoTouch.MonoPInvokeCallback(typeof(SQLiteCallback))]
\r
712 internal static void step_callback(IntPtr context, int nArgs, IntPtr argsptr)
\r
714 var handle = GCHandle.FromIntPtr(UnsafeNativeMethods.sqlite3_user_data(context));
\r
715 var func = (FunctionData)handle.Target;
\r
716 func.FuncStep(context, nArgs, argsptr);
\r
719 [MonoTouch.MonoPInvokeCallback(typeof(SQLiteFinalCallback))]
\r
720 internal static void final_callback(IntPtr context)
\r
722 var handle = GCHandle.FromIntPtr(UnsafeNativeMethods.sqlite3_user_data(context));
\r
723 var func = (FunctionData)handle.Target;
\r
724 func.FuncFinal(context);
\r
727 [MonoTouch.MonoPInvokeCallback(typeof(SQLiteFinalCallback))]
\r
728 internal static void destroy_callback(IntPtr context)
\r
730 GCHandle.FromIntPtr(context).Free();
\r
734 internal override int ContextCollateCompare(CollationEncodingEnum enc, IntPtr context, string s1, string s2)
\r
736 #if !SQLITE_STANDARD
\r
739 System.Text.Encoding converter = null;
\r
743 case CollationEncodingEnum.UTF8:
\r
744 converter = System.Text.Encoding.UTF8;
\r
746 case CollationEncodingEnum.UTF16LE:
\r
747 converter = System.Text.Encoding.Unicode;
\r
749 case CollationEncodingEnum.UTF16BE:
\r
750 converter = System.Text.Encoding.BigEndianUnicode;
\r
754 b1 = converter.GetBytes(s1);
\r
755 b2 = converter.GetBytes(s2);
\r
757 return UnsafeNativeMethods.sqlite3_context_collcompare(context, b1, b1.Length, b2, b2.Length);
\r
759 throw new NotImplementedException();
\r
763 internal override int ContextCollateCompare(CollationEncodingEnum enc, IntPtr context, char[] c1, char[] c2)
\r
765 #if !SQLITE_STANDARD
\r
768 System.Text.Encoding converter = null;
\r
772 case CollationEncodingEnum.UTF8:
\r
773 converter = System.Text.Encoding.UTF8;
\r
775 case CollationEncodingEnum.UTF16LE:
\r
776 converter = System.Text.Encoding.Unicode;
\r
778 case CollationEncodingEnum.UTF16BE:
\r
779 converter = System.Text.Encoding.BigEndianUnicode;
\r
783 b1 = converter.GetBytes(c1);
\r
784 b2 = converter.GetBytes(c2);
\r
786 return UnsafeNativeMethods.sqlite3_context_collcompare(context, b1, b1.Length, b2, b2.Length);
\r
788 throw new NotImplementedException();
\r
792 internal override CollationSequence GetCollationSequence(SqliteFunction func, IntPtr context)
\r
794 #if !SQLITE_STANDARD
\r
795 CollationSequence seq = new CollationSequence();
\r
799 IntPtr p = UnsafeNativeMethods.sqlite3_context_collseq(context, out type, out enc, out len);
\r
801 if (p != null) seq.Name = UTF8ToString(p, len);
\r
802 seq.Type = (CollationTypeEnum)type;
\r
804 seq.Encoding = (CollationEncodingEnum)enc;
\r
808 throw new NotImplementedException();
\r
812 internal override long GetParamValueBytes(IntPtr p, int nDataOffset, byte[] bDest, int nStart, int nLength)
\r
816 int nCopied = nLength;
\r
818 nlen = UnsafeNativeMethods.sqlite3_value_bytes(p);
\r
819 ptr = UnsafeNativeMethods.sqlite3_value_blob(p);
\r
821 if (bDest == null) return nlen;
\r
823 if (nCopied + nStart > bDest.Length) nCopied = bDest.Length - nStart;
\r
824 if (nCopied + nDataOffset > nlen) nCopied = nlen - nDataOffset;
\r
828 Marshal.Copy((IntPtr)((byte*)ptr + nDataOffset), bDest, nStart, nCopied);
\r
835 internal override double GetParamValueDouble(IntPtr ptr)
\r
838 #if !PLATFORM_COMPACTFRAMEWORK
\r
839 value = UnsafeNativeMethods.sqlite3_value_double(ptr);
\r
841 UnsafeNativeMethods.sqlite3_value_double_interop(ptr, out value);
\r
846 internal override int GetParamValueInt32(IntPtr ptr)
\r
848 return UnsafeNativeMethods.sqlite3_value_int(ptr);
\r
851 internal override long GetParamValueInt64(IntPtr ptr)
\r
854 #if !PLATFORM_COMPACTFRAMEWORK
\r
855 value = UnsafeNativeMethods.sqlite3_value_int64(ptr);
\r
857 UnsafeNativeMethods.sqlite3_value_int64_interop(ptr, out value);
\r
862 internal override string GetParamValueText(IntPtr ptr)
\r
864 #if !SQLITE_STANDARD
\r
866 return UTF8ToString(UnsafeNativeMethods.sqlite3_value_text_interop(ptr, out len), len);
\r
868 return UTF8ToString(UnsafeNativeMethods.sqlite3_value_text(ptr), -1);
\r
872 internal override TypeAffinity GetParamValueType(IntPtr ptr)
\r
874 return UnsafeNativeMethods.sqlite3_value_type(ptr);
\r
877 internal override void ReturnBlob(IntPtr context, byte[] value)
\r
879 UnsafeNativeMethods.sqlite3_result_blob(context, value, value.Length, (IntPtr)(-1));
\r
882 internal override void ReturnDouble(IntPtr context, double value)
\r
884 #if !PLATFORM_COMPACTFRAMEWORK
\r
885 UnsafeNativeMethods.sqlite3_result_double(context, value);
\r
887 UnsafeNativeMethods.sqlite3_result_double_interop(context, ref value);
\r
891 internal override void ReturnError(IntPtr context, string value)
\r
893 UnsafeNativeMethods.sqlite3_result_error(context, ToUTF8(value), value.Length);
\r
896 internal override void ReturnInt32(IntPtr context, int value)
\r
898 UnsafeNativeMethods.sqlite3_result_int(context, value);
\r
901 internal override void ReturnInt64(IntPtr context, long value)
\r
903 #if !PLATFORM_COMPACTFRAMEWORK
\r
904 UnsafeNativeMethods.sqlite3_result_int64(context, value);
\r
906 UnsafeNativeMethods.sqlite3_result_int64_interop(context, ref value);
\r
910 internal override void ReturnNull(IntPtr context)
\r
912 UnsafeNativeMethods.sqlite3_result_null(context);
\r
915 internal override void ReturnText(IntPtr context, string value)
\r
917 byte[] b = ToUTF8(value);
\r
918 UnsafeNativeMethods.sqlite3_result_text(context, ToUTF8(value), b.Length - 1, (IntPtr)(-1));
\r
921 internal override IntPtr AggregateContext(IntPtr context)
\r
923 return UnsafeNativeMethods.sqlite3_aggregate_context(context, 1);
\r
926 internal override void SetPassword(byte[] passwordBytes)
\r
928 int n = UnsafeNativeMethods.sqlite3_key(_sql, passwordBytes, passwordBytes.Length);
\r
929 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
932 internal override void ChangePassword(byte[] newPasswordBytes)
\r
934 int n = UnsafeNativeMethods.sqlite3_rekey(_sql, newPasswordBytes, (newPasswordBytes == null) ? 0 : newPasswordBytes.Length);
\r
935 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
939 SQLiteUpdateCallback update_callback;
\r
940 SQLiteCommitCallback commit_callback;
\r
941 SQLiteRollbackCallback rollback_callback;
\r
943 [MonoTouch.MonoPInvokeCallback (typeof (SQLiteUpdateCallback))]
\r
944 static void update (IntPtr puser, int type, IntPtr database, IntPtr table, Int64 rowid)
\r
946 SQLite3 instance = GCHandle.FromIntPtr (puser).Target as SQLite3;
\r
947 instance.update_callback (puser, type, database, table, rowid);
\r
950 internal override void SetUpdateHook (SQLiteUpdateCallback func)
\r
952 update_callback = func;
\r
954 UnsafeNativeMethods.sqlite3_update_hook (_sql, null, IntPtr.Zero);
\r
956 UnsafeNativeMethods.sqlite3_update_hook (_sql, update, GCHandle.ToIntPtr (gch));
\r
959 [MonoTouch.MonoPInvokeCallback (typeof (SQLiteCommitCallback))]
\r
960 static int commit (IntPtr puser)
\r
962 SQLite3 instance = GCHandle.FromIntPtr (puser).Target as SQLite3;
\r
963 return instance.commit_callback (puser);
\r
966 internal override void SetCommitHook (SQLiteCommitCallback func)
\r
968 commit_callback = func;
\r
970 UnsafeNativeMethods.sqlite3_commit_hook (_sql, null, IntPtr.Zero);
\r
972 UnsafeNativeMethods.sqlite3_commit_hook (_sql, commit, GCHandle.ToIntPtr (gch));
\r
975 [MonoTouch.MonoPInvokeCallback (typeof (SQLiteRollbackCallback))]
\r
976 static void rollback (IntPtr puser)
\r
978 SQLite3 instance = GCHandle.FromIntPtr (puser).Target as SQLite3;
\r
979 instance.rollback_callback (puser);
\r
982 internal override void SetRollbackHook (SQLiteRollbackCallback func)
\r
984 rollback_callback = func;
\r
986 UnsafeNativeMethods.sqlite3_rollback_hook (_sql, null, IntPtr.Zero);
\r
988 UnsafeNativeMethods.sqlite3_rollback_hook (_sql, rollback, GCHandle.ToIntPtr (gch));
\r
991 internal override void SetUpdateHook(SQLiteUpdateCallback func)
\r
993 UnsafeNativeMethods.sqlite3_update_hook(_sql, func, IntPtr.Zero);
\r
996 internal override void SetCommitHook(SQLiteCommitCallback func)
\r
998 UnsafeNativeMethods.sqlite3_commit_hook(_sql, func, IntPtr.Zero);
\r
1001 internal override void SetRollbackHook(SQLiteRollbackCallback func)
\r
1003 UnsafeNativeMethods.sqlite3_rollback_hook(_sql, func, IntPtr.Zero);
\r
1007 /// Helper function to retrieve a column of data from an active statement.
\r
1009 /// <param name="stmt">The statement being step()'d through</param>
\r
1010 /// <param name="index">The column index to retrieve</param>
\r
1011 /// <param name="typ">The type of data contained in the column. If Uninitialized, this function will retrieve the datatype information.</param>
\r
1012 /// <returns>Returns the data in the column</returns>
\r
1013 internal override object GetValue(SqliteStatement stmt, int index, SQLiteType typ)
\r
1015 if (IsNull(stmt, index)) return DBNull.Value;
\r
1016 TypeAffinity aff = typ.Affinity;
\r
1019 if (typ.Type != DbType.Object)
\r
1021 t = SqliteConvert.SQLiteTypeToType(typ);
\r
1022 aff = TypeToAffinity(t);
\r
1027 case TypeAffinity.Blob:
\r
1028 if (typ.Type == DbType.Guid && typ.Affinity == TypeAffinity.Text)
\r
1029 return new Guid(GetText(stmt, index));
\r
1031 int n = (int)GetBytes(stmt, index, 0, null, 0, 0);
\r
1032 byte[] b = new byte[n];
\r
1033 GetBytes(stmt, index, 0, b, 0, n);
\r
1035 if (typ.Type == DbType.Guid && n == 16)
\r
1036 return new Guid(b);
\r
1039 case TypeAffinity.DateTime:
\r
1040 return GetDateTime(stmt, index);
\r
1041 case TypeAffinity.Double:
\r
1042 if (t == null) return GetDouble(stmt, index);
\r
1044 return Convert.ChangeType(GetDouble(stmt, index), t, null);
\r
1045 case TypeAffinity.Int64:
\r
1046 if (t == null) return GetInt64(stmt, index);
\r
1048 return Convert.ChangeType(GetInt64(stmt, index), t, null);
\r
1050 return GetText(stmt, index);
\r
1054 internal override int GetCursorForTable(SqliteStatement stmt, int db, int rootPage)
\r
1056 #if !SQLITE_STANDARD
\r
1057 return UnsafeNativeMethods.sqlite3_table_cursor(stmt._sqlite_stmt, db, rootPage);
\r
1063 internal override long GetRowIdForCursor(SqliteStatement stmt, int cursor)
\r
1065 #if !SQLITE_STANDARD
\r
1067 int rc = UnsafeNativeMethods.sqlite3_cursor_rowid(stmt._sqlite_stmt, cursor, out rowid);
\r
1068 if (rc == 0) return rowid;
\r
1076 internal override void GetIndexColumnExtendedInfo(string database, string index, string column, out int sortMode, out int onError, out string collationSequence)
\r
1078 #if !SQLITE_STANDARD
\r
1083 rc = UnsafeNativeMethods.sqlite3_index_column_info_interop(_sql, ToUTF8(database), ToUTF8(index), ToUTF8(column), out sortMode, out onError, out coll, out colllen);
\r
1084 if (rc != 0) throw new SqliteException(rc, "");
\r
1086 collationSequence = UTF8ToString(coll, colllen);
\r
1090 collationSequence = "BINARY";
\r