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
33 /// The user-defined functions registered on this connection
\r
35 protected SqliteFunction[] _functionsArray;
\r
37 internal SQLite3(SQLiteDateFormats fmt)
\r
42 protected override void Dispose(bool bDisposing)
\r
48 // It isn't necessary to cleanup any functions we've registered. If the connection
\r
49 // goes to the pool and is resurrected later, re-registered functions will overwrite the
\r
50 // previous functions. The SqliteFunctionCookieHandle will take care of freeing unmanaged
\r
51 // resources belonging to the previously-registered functions.
\r
52 internal override void Close()
\r
58 SQLiteBase.ResetConnection(_sql);
\r
59 SqliteConnectionPool.Add(_fileName, _sql, _poolVersion);
\r
68 internal override void Cancel()
\r
70 UnsafeNativeMethods.sqlite3_interrupt(_sql);
\r
73 internal override string Version
\r
77 return SQLite3.SQLiteVersion;
\r
81 internal static string SQLiteVersion
\r
85 return UTF8ToString(UnsafeNativeMethods.sqlite3_libversion(), -1);
\r
89 internal override int Changes
\r
93 return UnsafeNativeMethods.sqlite3_changes(_sql);
\r
97 internal override void Open(string strFilename, SQLiteOpenFlagsEnum flags, int maxPoolSize, bool usePool)
\r
99 if (_sql != null) return;
\r
101 _usePool = usePool;
\r
104 _fileName = strFilename;
\r
105 _sql = SqliteConnectionPool.Remove(strFilename, maxPoolSize, out _poolVersion);
\r
112 #if !SQLITE_STANDARD
\r
113 int n = UnsafeNativeMethods.sqlite3_open_interop(ToUTF8(strFilename), (int)flags, out db);
\r
115 // Compatibility with versions < 3.5.0
\r
119 n = UnsafeNativeMethods.sqlite3_open_v2(ToUTF8(strFilename), out db, (int)flags, IntPtr.Zero);
\r
120 } catch (EntryPointNotFoundException ex) {
\r
121 Console.WriteLine ("Your sqlite3 version is old - please upgrade to at least v3.5.0!");
\r
122 n = UnsafeNativeMethods.sqlite3_open (ToUTF8 (strFilename), out db);
\r
126 if (n > 0) throw new SqliteException(n, null);
\r
130 // Bind functions to this connection. If any previous functions of the same name
\r
131 // were already bound, then the new bindings replace the old.
\r
132 _functionsArray = SqliteFunction.BindFunctions(this);
\r
136 internal override void ClearPool()
\r
138 SqliteConnectionPool.ClearPool(_fileName);
\r
141 internal override void SetTimeout(int nTimeoutMS)
\r
143 int n = UnsafeNativeMethods.sqlite3_busy_timeout(_sql, nTimeoutMS);
\r
144 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
147 internal override bool Step(SqliteStatement stmt)
\r
151 uint starttick = (uint)Environment.TickCount;
\r
152 uint timeout = (uint)(stmt._command._commandTimeout * 1000);
\r
156 n = UnsafeNativeMethods.sqlite3_step(stmt._sqlite_stmt);
\r
158 if (n == 100) return true;
\r
159 if (n == 101) return false;
\r
165 // An error occurred, attempt to reset the statement. If the reset worked because the
\r
166 // schema has changed, re-try the step again. If it errored our because the database
\r
167 // is locked, then keep retrying until the command timeout occurs.
\r
171 throw new SqliteException(n, SQLiteLastError());
\r
173 else if ((r == 6 || r == 5) && stmt._command != null) // SQLITE_LOCKED || SQLITE_BUSY
\r
176 if (rnd == null) // First time we've encountered the lock
\r
177 rnd = new Random();
\r
179 // If we've exceeded the command's timeout, give up and throw an error
\r
180 if ((uint)Environment.TickCount - starttick > timeout)
\r
182 throw new SqliteException(r, SQLiteLastError());
\r
186 // Otherwise sleep for a random amount of time up to 150ms
\r
187 System.Threading.Thread.CurrentThread.Join(rnd.Next(1, 150));
\r
194 internal override int Reset(SqliteStatement stmt)
\r
198 #if !SQLITE_STANDARD
\r
199 n = UnsafeNativeMethods.sqlite3_reset_interop(stmt._sqlite_stmt);
\r
201 n = UnsafeNativeMethods.sqlite3_reset(stmt._sqlite_stmt);
\r
204 // If the schema changed, try and re-prepare it
\r
205 if (n == 17) // SQLITE_SCHEMA
\r
207 // Recreate a dummy statement
\r
209 using (SqliteStatement tmp = Prepare(null, stmt._sqlStatement, null, (uint)(stmt._command._commandTimeout * 1000), out str))
\r
211 // Finalize the existing statement
\r
212 stmt._sqlite_stmt.Dispose();
\r
213 // Reassign a new statement pointer to the old statement and clear the temporary one
\r
214 stmt._sqlite_stmt = tmp._sqlite_stmt;
\r
215 tmp._sqlite_stmt = null;
\r
217 // Reapply parameters
\r
218 stmt.BindParameters();
\r
220 return -1; // Reset was OK, with schema change
\r
222 else if (n == 6 || n == 5) // SQLITE_LOCKED || SQLITE_BUSY
\r
226 throw new SqliteException(n, SQLiteLastError());
\r
228 return 0; // We reset OK, no schema changes
\r
231 internal override string SQLiteLastError()
\r
233 return SQLiteBase.SQLiteLastError(_sql);
\r
236 internal override SqliteStatement Prepare(SqliteConnection cnn, string strSql, SqliteStatement previous, uint timeoutMS, out string strRemain)
\r
238 IntPtr stmt = IntPtr.Zero;
\r
239 IntPtr ptr = IntPtr.Zero;
\r
243 byte[] b = ToUTF8(strSql);
\r
244 string typedefs = null;
\r
245 SqliteStatement cmd = null;
\r
247 uint starttick = (uint)Environment.TickCount;
\r
249 GCHandle handle = GCHandle.Alloc(b, GCHandleType.Pinned);
\r
250 IntPtr psql = handle.AddrOfPinnedObject();
\r
253 while ((n == 17 || n == 6 || n == 5) && retries < 3)
\r
255 #if !SQLITE_STANDARD
\r
256 n = UnsafeNativeMethods.sqlite3_prepare_interop(_sql, psql, b.Length - 1, out stmt, out ptr, out len);
\r
258 n = UnsafeNativeMethods.sqlite3_prepare(_sql, psql, b.Length - 1, out stmt, out ptr);
\r
266 if (String.Compare(SQLiteLastError(), "near \"TYPES\": syntax error", StringComparison.OrdinalIgnoreCase) == 0)
\r
268 int pos = strSql.IndexOf(';');
\r
269 if (pos == -1) pos = strSql.Length - 1;
\r
271 typedefs = strSql.Substring(0, pos + 1);
\r
272 strSql = strSql.Substring(pos + 1);
\r
276 while (cmd == null && strSql.Length > 0)
\r
278 cmd = Prepare(cnn, strSql, previous, timeoutMS, out strRemain);
\r
279 strSql = strRemain;
\r
283 cmd.SetTypes(typedefs);
\r
287 #if !PLATFORM_COMPACTFRAMEWORK
\r
288 else if (_buildingSchema == false && String.Compare(SQLiteLastError(), 0, "no such table: TEMP.SCHEMA", 0, 26, StringComparison.OrdinalIgnoreCase) == 0)
\r
291 _buildingSchema = true;
\r
294 ISQLiteSchemaExtensions ext = ((IServiceProvider)SqliteFactory.Instance).GetService(typeof(ISQLiteSchemaExtensions)) as ISQLiteSchemaExtensions;
\r
297 ext.BuildTempSchema(cnn);
\r
299 while (cmd == null && strSql.Length > 0)
\r
301 cmd = Prepare(cnn, strSql, previous, timeoutMS, out strRemain);
\r
302 strSql = strRemain;
\r
309 _buildingSchema = false;
\r
314 else if (n == 6 || n == 5) // Locked -- delay a small amount before retrying
\r
317 if (rnd == null) // First time we've encountered the lock
\r
318 rnd = new Random();
\r
320 // If we've exceeded the command's timeout, give up and throw an error
\r
321 if ((uint)Environment.TickCount - starttick > timeoutMS)
\r
323 throw new SqliteException(n, SQLiteLastError());
\r
327 // Otherwise sleep for a random amount of time up to 150ms
\r
328 System.Threading.Thread.CurrentThread.Join(rnd.Next(1, 150));
\r
333 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
335 strRemain = UTF8ToString(ptr, len);
\r
337 if (stmt != IntPtr.Zero) cmd = new SqliteStatement(this, stmt, strSql.Substring(0, strSql.Length - strRemain.Length), previous);
\r
347 internal override void Bind_Double(SqliteStatement stmt, int index, double value)
\r
349 #if !PLATFORM_COMPACTFRAMEWORK
\r
350 int n = UnsafeNativeMethods.sqlite3_bind_double(stmt._sqlite_stmt, index, value);
\r
352 int n = UnsafeNativeMethods.sqlite3_bind_double_interop(stmt._sqlite_stmt, index, ref value);
\r
354 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
357 internal override void Bind_Int32(SqliteStatement stmt, int index, int value)
\r
359 int n = UnsafeNativeMethods.sqlite3_bind_int(stmt._sqlite_stmt, index, value);
\r
360 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
363 internal override void Bind_Int64(SqliteStatement stmt, int index, long value)
\r
365 #if !PLATFORM_COMPACTFRAMEWORK
\r
366 int n = UnsafeNativeMethods.sqlite3_bind_int64(stmt._sqlite_stmt, index, value);
\r
368 int n = UnsafeNativeMethods.sqlite3_bind_int64_interop(stmt._sqlite_stmt, index, ref value);
\r
370 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
373 internal override void Bind_Text(SqliteStatement stmt, int index, string value)
\r
375 byte[] b = ToUTF8(value);
\r
376 int n = UnsafeNativeMethods.sqlite3_bind_text(stmt._sqlite_stmt, index, b, b.Length - 1, (IntPtr)(-1));
\r
377 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
380 internal override void Bind_DateTime(SqliteStatement stmt, int index, DateTime dt)
\r
382 byte[] b = ToUTF8(dt);
\r
383 int n = UnsafeNativeMethods.sqlite3_bind_text(stmt._sqlite_stmt, index, b, b.Length - 1, (IntPtr)(-1));
\r
384 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
387 internal override void Bind_Blob(SqliteStatement stmt, int index, byte[] blobData)
\r
389 int n = UnsafeNativeMethods.sqlite3_bind_blob(stmt._sqlite_stmt, index, blobData, blobData.Length, (IntPtr)(-1));
\r
390 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
393 internal override void Bind_Null(SqliteStatement stmt, int index)
\r
395 int n = UnsafeNativeMethods.sqlite3_bind_null(stmt._sqlite_stmt, index);
\r
396 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
399 internal override int Bind_ParamCount(SqliteStatement stmt)
\r
401 return UnsafeNativeMethods.sqlite3_bind_parameter_count(stmt._sqlite_stmt);
\r
404 internal override string Bind_ParamName(SqliteStatement stmt, int index)
\r
406 #if !SQLITE_STANDARD
\r
408 return UTF8ToString(UnsafeNativeMethods.sqlite3_bind_parameter_name_interop(stmt._sqlite_stmt, index, out len), len);
\r
410 return UTF8ToString(UnsafeNativeMethods.sqlite3_bind_parameter_name(stmt._sqlite_stmt, index), -1);
\r
414 internal override int Bind_ParamIndex(SqliteStatement stmt, string paramName)
\r
416 return UnsafeNativeMethods.sqlite3_bind_parameter_index(stmt._sqlite_stmt, ToUTF8(paramName));
\r
419 internal override int ColumnCount(SqliteStatement stmt)
\r
421 return UnsafeNativeMethods.sqlite3_column_count(stmt._sqlite_stmt);
\r
424 internal override string ColumnName(SqliteStatement stmt, int index)
\r
426 #if !SQLITE_STANDARD
\r
428 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_name_interop(stmt._sqlite_stmt, index, out len), len);
\r
430 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_name(stmt._sqlite_stmt, index), -1);
\r
434 internal override TypeAffinity ColumnAffinity(SqliteStatement stmt, int index)
\r
436 return UnsafeNativeMethods.sqlite3_column_type(stmt._sqlite_stmt, index);
\r
439 internal override string ColumnType(SqliteStatement stmt, int index, out TypeAffinity nAffinity)
\r
442 #if !SQLITE_STANDARD
\r
443 IntPtr p = UnsafeNativeMethods.sqlite3_column_decltype_interop(stmt._sqlite_stmt, index, out len);
\r
446 IntPtr p = UnsafeNativeMethods.sqlite3_column_decltype(stmt._sqlite_stmt, index);
\r
448 nAffinity = ColumnAffinity(stmt, index);
\r
450 if (p != IntPtr.Zero) return UTF8ToString(p, len);
\r
453 string[] ar = stmt.TypeDefinitions;
\r
456 if (index < ar.Length && ar[index] != null)
\r
459 return String.Empty;
\r
461 //switch (nAffinity)
\r
463 // case TypeAffinity.Int64:
\r
464 // return "BIGINT";
\r
465 // case TypeAffinity.Double:
\r
466 // return "DOUBLE";
\r
467 // case TypeAffinity.Blob:
\r
475 internal override int ColumnIndex(SqliteStatement stmt, string columnName)
\r
477 int x = ColumnCount(stmt);
\r
479 for (int n = 0; n < x; n++)
\r
481 if (String.Compare(columnName, ColumnName(stmt, n), true, CultureInfo.InvariantCulture) == 0)
\r
487 internal override string ColumnOriginalName(SqliteStatement stmt, int index)
\r
489 #if !SQLITE_STANDARD
\r
491 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_origin_name_interop(stmt._sqlite_stmt, index, out len), len);
\r
493 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_origin_name(stmt._sqlite_stmt, index), -1);
\r
497 internal override string ColumnDatabaseName(SqliteStatement stmt, int index)
\r
499 #if !SQLITE_STANDARD
\r
501 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_database_name_interop(stmt._sqlite_stmt, index, out len), len);
\r
503 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_database_name(stmt._sqlite_stmt, index), -1);
\r
507 internal override string ColumnTableName(SqliteStatement stmt, int index)
\r
509 #if !SQLITE_STANDARD
\r
511 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_table_name_interop(stmt._sqlite_stmt, index, out len), len);
\r
513 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_table_name(stmt._sqlite_stmt, index), -1);
\r
517 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
519 IntPtr dataTypePtr;
\r
528 #if !SQLITE_STANDARD
\r
529 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
533 n = UnsafeNativeMethods.sqlite3_table_column_metadata(_sql, ToUTF8(dataBase), ToUTF8(table), ToUTF8(column), out dataTypePtr, out collSeqPtr, out nnotNull, out nprimaryKey, out nautoInc);
\r
535 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
537 dataType = UTF8ToString(dataTypePtr, dtLen);
\r
538 collateSequence = UTF8ToString(collSeqPtr, csLen);
\r
540 notNull = (nnotNull == 1);
\r
541 primaryKey = (nprimaryKey == 1);
\r
542 autoIncrement = (nautoInc == 1);
\r
545 internal override double GetDouble(SqliteStatement stmt, int index)
\r
548 #if !PLATFORM_COMPACTFRAMEWORK
\r
549 value = UnsafeNativeMethods.sqlite3_column_double(stmt._sqlite_stmt, index);
\r
551 UnsafeNativeMethods.sqlite3_column_double_interop(stmt._sqlite_stmt, index, out value);
\r
556 internal override int GetInt32(SqliteStatement stmt, int index)
\r
558 return UnsafeNativeMethods.sqlite3_column_int(stmt._sqlite_stmt, index);
\r
561 internal override long GetInt64(SqliteStatement stmt, int index)
\r
564 #if !PLATFORM_COMPACTFRAMEWORK
\r
565 value = UnsafeNativeMethods.sqlite3_column_int64(stmt._sqlite_stmt, index);
\r
567 UnsafeNativeMethods.sqlite3_column_int64_interop(stmt._sqlite_stmt, index, out value);
\r
572 internal override string GetText(SqliteStatement stmt, int index)
\r
574 #if !SQLITE_STANDARD
\r
576 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_text_interop(stmt._sqlite_stmt, index, out len), len);
\r
578 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_text(stmt._sqlite_stmt, index), -1);
\r
582 internal override DateTime GetDateTime(SqliteStatement stmt, int index)
\r
584 #if !SQLITE_STANDARD
\r
586 return ToDateTime(UnsafeNativeMethods.sqlite3_column_text_interop(stmt._sqlite_stmt, index, out len), len);
\r
588 return ToDateTime(UnsafeNativeMethods.sqlite3_column_text(stmt._sqlite_stmt, index), -1);
\r
592 internal override long GetBytes(SqliteStatement stmt, int index, int nDataOffset, byte[] bDest, int nStart, int nLength)
\r
596 int nCopied = nLength;
\r
598 nlen = UnsafeNativeMethods.sqlite3_column_bytes(stmt._sqlite_stmt, index);
\r
599 ptr = UnsafeNativeMethods.sqlite3_column_blob(stmt._sqlite_stmt, index);
\r
601 if (bDest == null) return nlen;
\r
603 if (nCopied + nStart > bDest.Length) nCopied = bDest.Length - nStart;
\r
604 if (nCopied + nDataOffset > nlen) nCopied = nlen - nDataOffset;
\r
608 Marshal.Copy((IntPtr)((byte*)ptr + nDataOffset), bDest, nStart, nCopied);
\r
615 internal override long GetChars(SqliteStatement stmt, int index, int nDataOffset, char[] bDest, int nStart, int nLength)
\r
618 int nCopied = nLength;
\r
620 string str = GetText(stmt, index);
\r
623 if (bDest == null) return nlen;
\r
625 if (nCopied + nStart > bDest.Length) nCopied = bDest.Length - nStart;
\r
626 if (nCopied + nDataOffset > nlen) nCopied = nlen - nDataOffset;
\r
629 str.CopyTo(nDataOffset, bDest, nStart, nCopied);
\r
635 internal override bool IsNull(SqliteStatement stmt, int index)
\r
637 return (ColumnAffinity(stmt, index) == TypeAffinity.Null);
\r
640 internal override int AggregateCount(IntPtr context)
\r
642 return UnsafeNativeMethods.sqlite3_aggregate_count(context);
\r
645 internal override void CreateFunction(string strFunction, int nArgs, bool needCollSeq, SQLiteCallback func, SQLiteCallback funcstep, SQLiteFinalCallback funcfinal)
\r
649 #if !SQLITE_STANDARD
\r
650 n = UnsafeNativeMethods.sqlite3_create_function_interop(_sql, ToUTF8(strFunction), nArgs, 4, IntPtr.Zero, func, funcstep, funcfinal, (needCollSeq == true) ? 1 : 0);
\r
651 if (n == 0) n = UnsafeNativeMethods.sqlite3_create_function_interop(_sql, ToUTF8(strFunction), nArgs, 1, IntPtr.Zero, func, funcstep, funcfinal, (needCollSeq == true) ? 1 : 0);
\r
653 n = UnsafeNativeMethods.sqlite3_create_function(_sql, ToUTF8(strFunction), nArgs, 4, IntPtr.Zero, func, funcstep, funcfinal);
\r
654 if (n == 0) n = UnsafeNativeMethods.sqlite3_create_function(_sql, ToUTF8(strFunction), nArgs, 1, IntPtr.Zero, func, funcstep, funcfinal);
\r
656 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
659 internal override void CreateCollation(string strCollation, SQLiteCollation func, SQLiteCollation func16)
\r
661 int n = UnsafeNativeMethods.sqlite3_create_collation(_sql, ToUTF8(strCollation), 2, IntPtr.Zero, func16);
\r
662 if (n == 0) UnsafeNativeMethods.sqlite3_create_collation(_sql, ToUTF8(strCollation), 1, IntPtr.Zero, func);
\r
663 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
666 internal override int ContextCollateCompare(CollationEncodingEnum enc, IntPtr context, string s1, string s2)
\r
668 #if !SQLITE_STANDARD
\r
671 System.Text.Encoding converter = null;
\r
675 case CollationEncodingEnum.UTF8:
\r
676 converter = System.Text.Encoding.UTF8;
\r
678 case CollationEncodingEnum.UTF16LE:
\r
679 converter = System.Text.Encoding.Unicode;
\r
681 case CollationEncodingEnum.UTF16BE:
\r
682 converter = System.Text.Encoding.BigEndianUnicode;
\r
686 b1 = converter.GetBytes(s1);
\r
687 b2 = converter.GetBytes(s2);
\r
689 return UnsafeNativeMethods.sqlite3_context_collcompare(context, b1, b1.Length, b2, b2.Length);
\r
691 throw new NotImplementedException();
\r
695 internal override int ContextCollateCompare(CollationEncodingEnum enc, IntPtr context, char[] c1, char[] c2)
\r
697 #if !SQLITE_STANDARD
\r
700 System.Text.Encoding converter = null;
\r
704 case CollationEncodingEnum.UTF8:
\r
705 converter = System.Text.Encoding.UTF8;
\r
707 case CollationEncodingEnum.UTF16LE:
\r
708 converter = System.Text.Encoding.Unicode;
\r
710 case CollationEncodingEnum.UTF16BE:
\r
711 converter = System.Text.Encoding.BigEndianUnicode;
\r
715 b1 = converter.GetBytes(c1);
\r
716 b2 = converter.GetBytes(c2);
\r
718 return UnsafeNativeMethods.sqlite3_context_collcompare(context, b1, b1.Length, b2, b2.Length);
\r
720 throw new NotImplementedException();
\r
724 internal override CollationSequence GetCollationSequence(SqliteFunction func, IntPtr context)
\r
726 #if !SQLITE_STANDARD
\r
727 CollationSequence seq = new CollationSequence();
\r
731 IntPtr p = UnsafeNativeMethods.sqlite3_context_collseq(context, out type, out enc, out len);
\r
733 if (p != null) seq.Name = UTF8ToString(p, len);
\r
734 seq.Type = (CollationTypeEnum)type;
\r
736 seq.Encoding = (CollationEncodingEnum)enc;
\r
740 throw new NotImplementedException();
\r
744 internal override long GetParamValueBytes(IntPtr p, int nDataOffset, byte[] bDest, int nStart, int nLength)
\r
748 int nCopied = nLength;
\r
750 nlen = UnsafeNativeMethods.sqlite3_value_bytes(p);
\r
751 ptr = UnsafeNativeMethods.sqlite3_value_blob(p);
\r
753 if (bDest == null) return nlen;
\r
755 if (nCopied + nStart > bDest.Length) nCopied = bDest.Length - nStart;
\r
756 if (nCopied + nDataOffset > nlen) nCopied = nlen - nDataOffset;
\r
760 Marshal.Copy((IntPtr)((byte*)ptr + nDataOffset), bDest, nStart, nCopied);
\r
767 internal override double GetParamValueDouble(IntPtr ptr)
\r
770 #if !PLATFORM_COMPACTFRAMEWORK
\r
771 value = UnsafeNativeMethods.sqlite3_value_double(ptr);
\r
773 UnsafeNativeMethods.sqlite3_value_double_interop(ptr, out value);
\r
778 internal override int GetParamValueInt32(IntPtr ptr)
\r
780 return UnsafeNativeMethods.sqlite3_value_int(ptr);
\r
783 internal override long GetParamValueInt64(IntPtr ptr)
\r
786 #if !PLATFORM_COMPACTFRAMEWORK
\r
787 value = UnsafeNativeMethods.sqlite3_value_int64(ptr);
\r
789 UnsafeNativeMethods.sqlite3_value_int64_interop(ptr, out value);
\r
794 internal override string GetParamValueText(IntPtr ptr)
\r
796 #if !SQLITE_STANDARD
\r
798 return UTF8ToString(UnsafeNativeMethods.sqlite3_value_text_interop(ptr, out len), len);
\r
800 return UTF8ToString(UnsafeNativeMethods.sqlite3_value_text(ptr), -1);
\r
804 internal override TypeAffinity GetParamValueType(IntPtr ptr)
\r
806 return UnsafeNativeMethods.sqlite3_value_type(ptr);
\r
809 internal override void ReturnBlob(IntPtr context, byte[] value)
\r
811 UnsafeNativeMethods.sqlite3_result_blob(context, value, value.Length, (IntPtr)(-1));
\r
814 internal override void ReturnDouble(IntPtr context, double value)
\r
816 #if !PLATFORM_COMPACTFRAMEWORK
\r
817 UnsafeNativeMethods.sqlite3_result_double(context, value);
\r
819 UnsafeNativeMethods.sqlite3_result_double_interop(context, ref value);
\r
823 internal override void ReturnError(IntPtr context, string value)
\r
825 UnsafeNativeMethods.sqlite3_result_error(context, ToUTF8(value), value.Length);
\r
828 internal override void ReturnInt32(IntPtr context, int value)
\r
830 UnsafeNativeMethods.sqlite3_result_int(context, value);
\r
833 internal override void ReturnInt64(IntPtr context, long value)
\r
835 #if !PLATFORM_COMPACTFRAMEWORK
\r
836 UnsafeNativeMethods.sqlite3_result_int64(context, value);
\r
838 UnsafeNativeMethods.sqlite3_result_int64_interop(context, ref value);
\r
842 internal override void ReturnNull(IntPtr context)
\r
844 UnsafeNativeMethods.sqlite3_result_null(context);
\r
847 internal override void ReturnText(IntPtr context, string value)
\r
849 byte[] b = ToUTF8(value);
\r
850 UnsafeNativeMethods.sqlite3_result_text(context, ToUTF8(value), b.Length - 1, (IntPtr)(-1));
\r
853 internal override IntPtr AggregateContext(IntPtr context)
\r
855 return UnsafeNativeMethods.sqlite3_aggregate_context(context, 1);
\r
858 internal override void SetPassword(byte[] passwordBytes)
\r
860 int n = UnsafeNativeMethods.sqlite3_key(_sql, passwordBytes, passwordBytes.Length);
\r
861 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
864 internal override void ChangePassword(byte[] newPasswordBytes)
\r
866 int n = UnsafeNativeMethods.sqlite3_rekey(_sql, newPasswordBytes, (newPasswordBytes == null) ? 0 : newPasswordBytes.Length);
\r
867 if (n > 0) throw new SqliteException(n, SQLiteLastError());
\r
870 internal override void SetUpdateHook(SQLiteUpdateCallback func)
\r
872 UnsafeNativeMethods.sqlite3_update_hook(_sql, func, IntPtr.Zero);
\r
875 internal override void SetCommitHook(SQLiteCommitCallback func)
\r
877 UnsafeNativeMethods.sqlite3_commit_hook(_sql, func, IntPtr.Zero);
\r
880 internal override void SetRollbackHook(SQLiteRollbackCallback func)
\r
882 UnsafeNativeMethods.sqlite3_rollback_hook(_sql, func, IntPtr.Zero);
\r
886 /// Helper function to retrieve a column of data from an active statement.
\r
888 /// <param name="stmt">The statement being step()'d through</param>
\r
889 /// <param name="index">The column index to retrieve</param>
\r
890 /// <param name="typ">The type of data contained in the column. If Uninitialized, this function will retrieve the datatype information.</param>
\r
891 /// <returns>Returns the data in the column</returns>
\r
892 internal override object GetValue(SqliteStatement stmt, int index, SQLiteType typ)
\r
894 if (IsNull(stmt, index)) return DBNull.Value;
\r
895 TypeAffinity aff = typ.Affinity;
\r
898 if (typ.Type != DbType.Object)
\r
900 t = SqliteConvert.SQLiteTypeToType(typ);
\r
901 aff = TypeToAffinity(t);
\r
906 case TypeAffinity.Blob:
\r
907 if (typ.Type == DbType.Guid && typ.Affinity == TypeAffinity.Text)
\r
908 return new Guid(GetText(stmt, index));
\r
910 int n = (int)GetBytes(stmt, index, 0, null, 0, 0);
\r
911 byte[] b = new byte[n];
\r
912 GetBytes(stmt, index, 0, b, 0, n);
\r
914 if (typ.Type == DbType.Guid && n == 16)
\r
915 return new Guid(b);
\r
918 case TypeAffinity.DateTime:
\r
919 return GetDateTime(stmt, index);
\r
920 case TypeAffinity.Double:
\r
921 if (t == null) return GetDouble(stmt, index);
\r
923 return Convert.ChangeType(GetDouble(stmt, index), t, null);
\r
924 case TypeAffinity.Int64:
\r
925 if (t == null) return GetInt64(stmt, index);
\r
927 return Convert.ChangeType(GetInt64(stmt, index), t, null);
\r
929 return GetText(stmt, index);
\r
933 internal override int GetCursorForTable(SqliteStatement stmt, int db, int rootPage)
\r
935 #if !SQLITE_STANDARD
\r
936 return UnsafeNativeMethods.sqlite3_table_cursor(stmt._sqlite_stmt, db, rootPage);
\r
942 internal override long GetRowIdForCursor(SqliteStatement stmt, int cursor)
\r
944 #if !SQLITE_STANDARD
\r
946 int rc = UnsafeNativeMethods.sqlite3_cursor_rowid(stmt._sqlite_stmt, cursor, out rowid);
\r
947 if (rc == 0) return rowid;
\r
955 internal override void GetIndexColumnExtendedInfo(string database, string index, string column, out int sortMode, out int onError, out string collationSequence)
\r
957 #if !SQLITE_STANDARD
\r
962 rc = UnsafeNativeMethods.sqlite3_index_column_info_interop(_sql, ToUTF8(database), ToUTF8(index), ToUTF8(column), out sortMode, out onError, out coll, out colllen);
\r
963 if (rc != 0) throw new SqliteException(rc, "");
\r
965 collationSequence = UTF8ToString(coll, colllen);
\r
969 collationSequence = "BINARY";
\r