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 int n = UnsafeNativeMethods.sqlite3_open_v2(ToUTF8(strFilename), out db, (int)flags, IntPtr.Zero);
\r
117 if (n > 0) throw new SQLiteException(n, null);
\r
121 // Bind functions to this connection. If any previous functions of the same name
\r
122 // were already bound, then the new bindings replace the old.
\r
123 _functionsArray = SQLiteFunction.BindFunctions(this);
\r
127 internal override void ClearPool()
\r
129 SQLiteConnectionPool.ClearPool(_fileName);
\r
132 internal override void SetTimeout(int nTimeoutMS)
\r
134 int n = UnsafeNativeMethods.sqlite3_busy_timeout(_sql, nTimeoutMS);
\r
135 if (n > 0) throw new SQLiteException(n, SQLiteLastError());
\r
138 internal override bool Step(SQLiteStatement stmt)
\r
142 uint starttick = (uint)Environment.TickCount;
\r
143 uint timeout = (uint)(stmt._command._commandTimeout * 1000);
\r
147 n = UnsafeNativeMethods.sqlite3_step(stmt._sqlite_stmt);
\r
149 if (n == 100) return true;
\r
150 if (n == 101) return false;
\r
156 // An error occurred, attempt to reset the statement. If the reset worked because the
\r
157 // schema has changed, re-try the step again. If it errored our because the database
\r
158 // is locked, then keep retrying until the command timeout occurs.
\r
162 throw new SQLiteException(n, SQLiteLastError());
\r
164 else if ((r == 6 || r == 5) && stmt._command != null) // SQLITE_LOCKED || SQLITE_BUSY
\r
167 if (rnd == null) // First time we've encountered the lock
\r
168 rnd = new Random();
\r
170 // If we've exceeded the command's timeout, give up and throw an error
\r
171 if ((uint)Environment.TickCount - starttick > timeout)
\r
173 throw new SQLiteException(r, SQLiteLastError());
\r
177 // Otherwise sleep for a random amount of time up to 150ms
\r
178 System.Threading.Thread.CurrentThread.Join(rnd.Next(1, 150));
\r
185 internal override int Reset(SQLiteStatement stmt)
\r
189 #if !SQLITE_STANDARD
\r
190 n = UnsafeNativeMethods.sqlite3_reset_interop(stmt._sqlite_stmt);
\r
192 n = UnsafeNativeMethods.sqlite3_reset(stmt._sqlite_stmt);
\r
195 // If the schema changed, try and re-prepare it
\r
196 if (n == 17) // SQLITE_SCHEMA
\r
198 // Recreate a dummy statement
\r
200 using (SQLiteStatement tmp = Prepare(null, stmt._sqlStatement, null, (uint)(stmt._command._commandTimeout * 1000), out str))
\r
202 // Finalize the existing statement
\r
203 stmt._sqlite_stmt.Dispose();
\r
204 // Reassign a new statement pointer to the old statement and clear the temporary one
\r
205 stmt._sqlite_stmt = tmp._sqlite_stmt;
\r
206 tmp._sqlite_stmt = null;
\r
208 // Reapply parameters
\r
209 stmt.BindParameters();
\r
211 return -1; // Reset was OK, with schema change
\r
213 else if (n == 6 || n == 5) // SQLITE_LOCKED || SQLITE_BUSY
\r
217 throw new SQLiteException(n, SQLiteLastError());
\r
219 return 0; // We reset OK, no schema changes
\r
222 internal override string SQLiteLastError()
\r
224 return SQLiteBase.SQLiteLastError(_sql);
\r
227 internal override SQLiteStatement Prepare(SQLiteConnection cnn, string strSql, SQLiteStatement previous, uint timeoutMS, out string strRemain)
\r
229 IntPtr stmt = IntPtr.Zero;
\r
230 IntPtr ptr = IntPtr.Zero;
\r
234 byte[] b = ToUTF8(strSql);
\r
235 string typedefs = null;
\r
236 SQLiteStatement cmd = null;
\r
238 uint starttick = (uint)Environment.TickCount;
\r
240 GCHandle handle = GCHandle.Alloc(b, GCHandleType.Pinned);
\r
241 IntPtr psql = handle.AddrOfPinnedObject();
\r
244 while ((n == 17 || n == 6 || n == 5) && retries < 3)
\r
246 #if !SQLITE_STANDARD
\r
247 n = UnsafeNativeMethods.sqlite3_prepare_interop(_sql, psql, b.Length - 1, out stmt, out ptr, out len);
\r
249 n = UnsafeNativeMethods.sqlite3_prepare(_sql, psql, b.Length - 1, out stmt, out ptr);
\r
257 if (String.Compare(SQLiteLastError(), "near \"TYPES\": syntax error", StringComparison.OrdinalIgnoreCase) == 0)
\r
259 int pos = strSql.IndexOf(';');
\r
260 if (pos == -1) pos = strSql.Length - 1;
\r
262 typedefs = strSql.Substring(0, pos + 1);
\r
263 strSql = strSql.Substring(pos + 1);
\r
267 while (cmd == null && strSql.Length > 0)
\r
269 cmd = Prepare(cnn, strSql, previous, timeoutMS, out strRemain);
\r
270 strSql = strRemain;
\r
274 cmd.SetTypes(typedefs);
\r
278 #if !PLATFORM_COMPACTFRAMEWORK
\r
279 else if (_buildingSchema == false && String.Compare(SQLiteLastError(), 0, "no such table: TEMP.SCHEMA", 0, 26, StringComparison.OrdinalIgnoreCase) == 0)
\r
282 _buildingSchema = true;
\r
285 ISQLiteSchemaExtensions ext = ((IServiceProvider)SQLiteFactory.Instance).GetService(typeof(ISQLiteSchemaExtensions)) as ISQLiteSchemaExtensions;
\r
288 ext.BuildTempSchema(cnn);
\r
290 while (cmd == null && strSql.Length > 0)
\r
292 cmd = Prepare(cnn, strSql, previous, timeoutMS, out strRemain);
\r
293 strSql = strRemain;
\r
300 _buildingSchema = false;
\r
305 else if (n == 6 || n == 5) // Locked -- delay a small amount before retrying
\r
308 if (rnd == null) // First time we've encountered the lock
\r
309 rnd = new Random();
\r
311 // If we've exceeded the command's timeout, give up and throw an error
\r
312 if ((uint)Environment.TickCount - starttick > timeoutMS)
\r
314 throw new SQLiteException(n, SQLiteLastError());
\r
318 // Otherwise sleep for a random amount of time up to 150ms
\r
319 System.Threading.Thread.CurrentThread.Join(rnd.Next(1, 150));
\r
324 if (n > 0) throw new SQLiteException(n, SQLiteLastError());
\r
326 strRemain = UTF8ToString(ptr, len);
\r
328 if (stmt != IntPtr.Zero) cmd = new SQLiteStatement(this, stmt, strSql.Substring(0, strSql.Length - strRemain.Length), previous);
\r
338 internal override void Bind_Double(SQLiteStatement stmt, int index, double value)
\r
340 #if !PLATFORM_COMPACTFRAMEWORK
\r
341 int n = UnsafeNativeMethods.sqlite3_bind_double(stmt._sqlite_stmt, index, value);
\r
343 int n = UnsafeNativeMethods.sqlite3_bind_double_interop(stmt._sqlite_stmt, index, ref value);
\r
345 if (n > 0) throw new SQLiteException(n, SQLiteLastError());
\r
348 internal override void Bind_Int32(SQLiteStatement stmt, int index, int value)
\r
350 int n = UnsafeNativeMethods.sqlite3_bind_int(stmt._sqlite_stmt, index, value);
\r
351 if (n > 0) throw new SQLiteException(n, SQLiteLastError());
\r
354 internal override void Bind_Int64(SQLiteStatement stmt, int index, long value)
\r
356 #if !PLATFORM_COMPACTFRAMEWORK
\r
357 int n = UnsafeNativeMethods.sqlite3_bind_int64(stmt._sqlite_stmt, index, value);
\r
359 int n = UnsafeNativeMethods.sqlite3_bind_int64_interop(stmt._sqlite_stmt, index, ref value);
\r
361 if (n > 0) throw new SQLiteException(n, SQLiteLastError());
\r
364 internal override void Bind_Text(SQLiteStatement stmt, int index, string value)
\r
366 byte[] b = ToUTF8(value);
\r
367 int n = UnsafeNativeMethods.sqlite3_bind_text(stmt._sqlite_stmt, index, b, b.Length - 1, (IntPtr)(-1));
\r
368 if (n > 0) throw new SQLiteException(n, SQLiteLastError());
\r
371 internal override void Bind_DateTime(SQLiteStatement stmt, int index, DateTime dt)
\r
373 byte[] b = ToUTF8(dt);
\r
374 int n = UnsafeNativeMethods.sqlite3_bind_text(stmt._sqlite_stmt, index, b, b.Length - 1, (IntPtr)(-1));
\r
375 if (n > 0) throw new SQLiteException(n, SQLiteLastError());
\r
378 internal override void Bind_Blob(SQLiteStatement stmt, int index, byte[] blobData)
\r
380 int n = UnsafeNativeMethods.sqlite3_bind_blob(stmt._sqlite_stmt, index, blobData, blobData.Length, (IntPtr)(-1));
\r
381 if (n > 0) throw new SQLiteException(n, SQLiteLastError());
\r
384 internal override void Bind_Null(SQLiteStatement stmt, int index)
\r
386 int n = UnsafeNativeMethods.sqlite3_bind_null(stmt._sqlite_stmt, index);
\r
387 if (n > 0) throw new SQLiteException(n, SQLiteLastError());
\r
390 internal override int Bind_ParamCount(SQLiteStatement stmt)
\r
392 return UnsafeNativeMethods.sqlite3_bind_parameter_count(stmt._sqlite_stmt);
\r
395 internal override string Bind_ParamName(SQLiteStatement stmt, int index)
\r
397 #if !SQLITE_STANDARD
\r
399 return UTF8ToString(UnsafeNativeMethods.sqlite3_bind_parameter_name_interop(stmt._sqlite_stmt, index, out len), len);
\r
401 return UTF8ToString(UnsafeNativeMethods.sqlite3_bind_parameter_name(stmt._sqlite_stmt, index), -1);
\r
405 internal override int Bind_ParamIndex(SQLiteStatement stmt, string paramName)
\r
407 return UnsafeNativeMethods.sqlite3_bind_parameter_index(stmt._sqlite_stmt, ToUTF8(paramName));
\r
410 internal override int ColumnCount(SQLiteStatement stmt)
\r
412 return UnsafeNativeMethods.sqlite3_column_count(stmt._sqlite_stmt);
\r
415 internal override string ColumnName(SQLiteStatement stmt, int index)
\r
417 #if !SQLITE_STANDARD
\r
419 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_name_interop(stmt._sqlite_stmt, index, out len), len);
\r
421 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_name(stmt._sqlite_stmt, index), -1);
\r
425 internal override TypeAffinity ColumnAffinity(SQLiteStatement stmt, int index)
\r
427 return UnsafeNativeMethods.sqlite3_column_type(stmt._sqlite_stmt, index);
\r
430 internal override string ColumnType(SQLiteStatement stmt, int index, out TypeAffinity nAffinity)
\r
433 #if !SQLITE_STANDARD
\r
434 IntPtr p = UnsafeNativeMethods.sqlite3_column_decltype_interop(stmt._sqlite_stmt, index, out len);
\r
437 IntPtr p = UnsafeNativeMethods.sqlite3_column_decltype(stmt._sqlite_stmt, index);
\r
439 nAffinity = ColumnAffinity(stmt, index);
\r
441 if (p != IntPtr.Zero) return UTF8ToString(p, len);
\r
444 string[] ar = stmt.TypeDefinitions;
\r
447 if (index < ar.Length && ar[index] != null)
\r
450 return String.Empty;
\r
452 //switch (nAffinity)
\r
454 // case TypeAffinity.Int64:
\r
455 // return "BIGINT";
\r
456 // case TypeAffinity.Double:
\r
457 // return "DOUBLE";
\r
458 // case TypeAffinity.Blob:
\r
466 internal override int ColumnIndex(SQLiteStatement stmt, string columnName)
\r
468 int x = ColumnCount(stmt);
\r
470 for (int n = 0; n < x; n++)
\r
472 if (String.Compare(columnName, ColumnName(stmt, n), true, CultureInfo.InvariantCulture) == 0)
\r
478 internal override string ColumnOriginalName(SQLiteStatement stmt, int index)
\r
480 #if !SQLITE_STANDARD
\r
482 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_origin_name_interop(stmt._sqlite_stmt, index, out len), len);
\r
484 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_origin_name(stmt._sqlite_stmt, index), -1);
\r
488 internal override string ColumnDatabaseName(SQLiteStatement stmt, int index)
\r
490 #if !SQLITE_STANDARD
\r
492 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_database_name_interop(stmt._sqlite_stmt, index, out len), len);
\r
494 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_database_name(stmt._sqlite_stmt, index), -1);
\r
498 internal override string ColumnTableName(SQLiteStatement stmt, int index)
\r
500 #if !SQLITE_STANDARD
\r
502 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_table_name_interop(stmt._sqlite_stmt, index, out len), len);
\r
504 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_table_name(stmt._sqlite_stmt, index), -1);
\r
508 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
510 IntPtr dataTypePtr;
\r
519 #if !SQLITE_STANDARD
\r
520 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
524 n = UnsafeNativeMethods.sqlite3_table_column_metadata(_sql, ToUTF8(dataBase), ToUTF8(table), ToUTF8(column), out dataTypePtr, out collSeqPtr, out nnotNull, out nprimaryKey, out nautoInc);
\r
526 if (n > 0) throw new SQLiteException(n, SQLiteLastError());
\r
528 dataType = UTF8ToString(dataTypePtr, dtLen);
\r
529 collateSequence = UTF8ToString(collSeqPtr, csLen);
\r
531 notNull = (nnotNull == 1);
\r
532 primaryKey = (nprimaryKey == 1);
\r
533 autoIncrement = (nautoInc == 1);
\r
536 internal override double GetDouble(SQLiteStatement stmt, int index)
\r
539 #if !PLATFORM_COMPACTFRAMEWORK
\r
540 value = UnsafeNativeMethods.sqlite3_column_double(stmt._sqlite_stmt, index);
\r
542 UnsafeNativeMethods.sqlite3_column_double_interop(stmt._sqlite_stmt, index, out value);
\r
547 internal override int GetInt32(SQLiteStatement stmt, int index)
\r
549 return UnsafeNativeMethods.sqlite3_column_int(stmt._sqlite_stmt, index);
\r
552 internal override long GetInt64(SQLiteStatement stmt, int index)
\r
555 #if !PLATFORM_COMPACTFRAMEWORK
\r
556 value = UnsafeNativeMethods.sqlite3_column_int64(stmt._sqlite_stmt, index);
\r
558 UnsafeNativeMethods.sqlite3_column_int64_interop(stmt._sqlite_stmt, index, out value);
\r
563 internal override string GetText(SQLiteStatement stmt, int index)
\r
565 #if !SQLITE_STANDARD
\r
567 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_text_interop(stmt._sqlite_stmt, index, out len), len);
\r
569 return UTF8ToString(UnsafeNativeMethods.sqlite3_column_text(stmt._sqlite_stmt, index), -1);
\r
573 internal override DateTime GetDateTime(SQLiteStatement stmt, int index)
\r
575 #if !SQLITE_STANDARD
\r
577 return ToDateTime(UnsafeNativeMethods.sqlite3_column_text_interop(stmt._sqlite_stmt, index, out len), len);
\r
579 return ToDateTime(UnsafeNativeMethods.sqlite3_column_text(stmt._sqlite_stmt, index), -1);
\r
583 internal override long GetBytes(SQLiteStatement stmt, int index, int nDataOffset, byte[] bDest, int nStart, int nLength)
\r
587 int nCopied = nLength;
\r
589 nlen = UnsafeNativeMethods.sqlite3_column_bytes(stmt._sqlite_stmt, index);
\r
590 ptr = UnsafeNativeMethods.sqlite3_column_blob(stmt._sqlite_stmt, index);
\r
592 if (bDest == null) return nlen;
\r
594 if (nCopied + nStart > bDest.Length) nCopied = bDest.Length - nStart;
\r
595 if (nCopied + nDataOffset > nlen) nCopied = nlen - nDataOffset;
\r
598 Marshal.Copy((IntPtr)(ptr.ToInt32() + nDataOffset), bDest, nStart, nCopied);
\r
604 internal override long GetChars(SQLiteStatement stmt, int index, int nDataOffset, char[] bDest, int nStart, int nLength)
\r
607 int nCopied = nLength;
\r
609 string str = GetText(stmt, index);
\r
612 if (bDest == null) return nlen;
\r
614 if (nCopied + nStart > bDest.Length) nCopied = bDest.Length - nStart;
\r
615 if (nCopied + nDataOffset > nlen) nCopied = nlen - nDataOffset;
\r
618 str.CopyTo(nDataOffset, bDest, nStart, nCopied);
\r
624 internal override bool IsNull(SQLiteStatement stmt, int index)
\r
626 return (ColumnAffinity(stmt, index) == TypeAffinity.Null);
\r
629 internal override int AggregateCount(IntPtr context)
\r
631 return UnsafeNativeMethods.sqlite3_aggregate_count(context);
\r
634 internal override void CreateFunction(string strFunction, int nArgs, bool needCollSeq, SQLiteCallback func, SQLiteCallback funcstep, SQLiteFinalCallback funcfinal)
\r
638 #if !SQLITE_STANDARD
\r
639 n = UnsafeNativeMethods.sqlite3_create_function_interop(_sql, ToUTF8(strFunction), nArgs, 4, IntPtr.Zero, func, funcstep, funcfinal, (needCollSeq == true) ? 1 : 0);
\r
640 if (n == 0) n = UnsafeNativeMethods.sqlite3_create_function_interop(_sql, ToUTF8(strFunction), nArgs, 1, IntPtr.Zero, func, funcstep, funcfinal, (needCollSeq == true) ? 1 : 0);
\r
642 n = UnsafeNativeMethods.sqlite3_create_function(_sql, ToUTF8(strFunction), nArgs, 4, IntPtr.Zero, func, funcstep, funcfinal);
\r
643 if (n == 0) n = UnsafeNativeMethods.sqlite3_create_function(_sql, ToUTF8(strFunction), nArgs, 1, IntPtr.Zero, func, funcstep, funcfinal);
\r
645 if (n > 0) throw new SQLiteException(n, SQLiteLastError());
\r
648 internal override void CreateCollation(string strCollation, SQLiteCollation func, SQLiteCollation func16)
\r
650 int n = UnsafeNativeMethods.sqlite3_create_collation(_sql, ToUTF8(strCollation), 2, IntPtr.Zero, func16);
\r
651 if (n == 0) UnsafeNativeMethods.sqlite3_create_collation(_sql, ToUTF8(strCollation), 1, IntPtr.Zero, func);
\r
652 if (n > 0) throw new SQLiteException(n, SQLiteLastError());
\r
655 internal override int ContextCollateCompare(CollationEncodingEnum enc, IntPtr context, string s1, string s2)
\r
657 #if !SQLITE_STANDARD
\r
660 System.Text.Encoding converter = null;
\r
664 case CollationEncodingEnum.UTF8:
\r
665 converter = System.Text.Encoding.UTF8;
\r
667 case CollationEncodingEnum.UTF16LE:
\r
668 converter = System.Text.Encoding.Unicode;
\r
670 case CollationEncodingEnum.UTF16BE:
\r
671 converter = System.Text.Encoding.BigEndianUnicode;
\r
675 b1 = converter.GetBytes(s1);
\r
676 b2 = converter.GetBytes(s2);
\r
678 return UnsafeNativeMethods.sqlite3_context_collcompare(context, b1, b1.Length, b2, b2.Length);
\r
680 throw new NotImplementedException();
\r
684 internal override int ContextCollateCompare(CollationEncodingEnum enc, IntPtr context, char[] c1, char[] c2)
\r
686 #if !SQLITE_STANDARD
\r
689 System.Text.Encoding converter = null;
\r
693 case CollationEncodingEnum.UTF8:
\r
694 converter = System.Text.Encoding.UTF8;
\r
696 case CollationEncodingEnum.UTF16LE:
\r
697 converter = System.Text.Encoding.Unicode;
\r
699 case CollationEncodingEnum.UTF16BE:
\r
700 converter = System.Text.Encoding.BigEndianUnicode;
\r
704 b1 = converter.GetBytes(c1);
\r
705 b2 = converter.GetBytes(c2);
\r
707 return UnsafeNativeMethods.sqlite3_context_collcompare(context, b1, b1.Length, b2, b2.Length);
\r
709 throw new NotImplementedException();
\r
713 internal override CollationSequence GetCollationSequence(SQLiteFunction func, IntPtr context)
\r
715 #if !SQLITE_STANDARD
\r
716 CollationSequence seq = new CollationSequence();
\r
720 IntPtr p = UnsafeNativeMethods.sqlite3_context_collseq(context, out type, out enc, out len);
\r
722 if (p != null) seq.Name = UTF8ToString(p, len);
\r
723 seq.Type = (CollationTypeEnum)type;
\r
725 seq.Encoding = (CollationEncodingEnum)enc;
\r
729 throw new NotImplementedException();
\r
733 internal override long GetParamValueBytes(IntPtr p, int nDataOffset, byte[] bDest, int nStart, int nLength)
\r
737 int nCopied = nLength;
\r
739 nlen = UnsafeNativeMethods.sqlite3_value_bytes(p);
\r
740 ptr = UnsafeNativeMethods.sqlite3_value_blob(p);
\r
742 if (bDest == null) return nlen;
\r
744 if (nCopied + nStart > bDest.Length) nCopied = bDest.Length - nStart;
\r
745 if (nCopied + nDataOffset > nlen) nCopied = nlen - nDataOffset;
\r
748 Marshal.Copy((IntPtr)(ptr.ToInt32() + nDataOffset), bDest, nStart, nCopied);
\r
754 internal override double GetParamValueDouble(IntPtr ptr)
\r
757 #if !PLATFORM_COMPACTFRAMEWORK
\r
758 value = UnsafeNativeMethods.sqlite3_value_double(ptr);
\r
760 UnsafeNativeMethods.sqlite3_value_double_interop(ptr, out value);
\r
765 internal override int GetParamValueInt32(IntPtr ptr)
\r
767 return UnsafeNativeMethods.sqlite3_value_int(ptr);
\r
770 internal override long GetParamValueInt64(IntPtr ptr)
\r
773 #if !PLATFORM_COMPACTFRAMEWORK
\r
774 value = UnsafeNativeMethods.sqlite3_value_int64(ptr);
\r
776 UnsafeNativeMethods.sqlite3_value_int64_interop(ptr, out value);
\r
781 internal override string GetParamValueText(IntPtr ptr)
\r
783 #if !SQLITE_STANDARD
\r
785 return UTF8ToString(UnsafeNativeMethods.sqlite3_value_text_interop(ptr, out len), len);
\r
787 return UTF8ToString(UnsafeNativeMethods.sqlite3_value_text(ptr), -1);
\r
791 internal override TypeAffinity GetParamValueType(IntPtr ptr)
\r
793 return UnsafeNativeMethods.sqlite3_value_type(ptr);
\r
796 internal override void ReturnBlob(IntPtr context, byte[] value)
\r
798 UnsafeNativeMethods.sqlite3_result_blob(context, value, value.Length, (IntPtr)(-1));
\r
801 internal override void ReturnDouble(IntPtr context, double value)
\r
803 #if !PLATFORM_COMPACTFRAMEWORK
\r
804 UnsafeNativeMethods.sqlite3_result_double(context, value);
\r
806 UnsafeNativeMethods.sqlite3_result_double_interop(context, ref value);
\r
810 internal override void ReturnError(IntPtr context, string value)
\r
812 UnsafeNativeMethods.sqlite3_result_error(context, ToUTF8(value), value.Length);
\r
815 internal override void ReturnInt32(IntPtr context, int value)
\r
817 UnsafeNativeMethods.sqlite3_result_int(context, value);
\r
820 internal override void ReturnInt64(IntPtr context, long value)
\r
822 #if !PLATFORM_COMPACTFRAMEWORK
\r
823 UnsafeNativeMethods.sqlite3_result_int64(context, value);
\r
825 UnsafeNativeMethods.sqlite3_result_int64_interop(context, ref value);
\r
829 internal override void ReturnNull(IntPtr context)
\r
831 UnsafeNativeMethods.sqlite3_result_null(context);
\r
834 internal override void ReturnText(IntPtr context, string value)
\r
836 byte[] b = ToUTF8(value);
\r
837 UnsafeNativeMethods.sqlite3_result_text(context, ToUTF8(value), b.Length - 1, (IntPtr)(-1));
\r
840 internal override IntPtr AggregateContext(IntPtr context)
\r
842 return UnsafeNativeMethods.sqlite3_aggregate_context(context, 1);
\r
845 internal override void SetPassword(byte[] passwordBytes)
\r
847 int n = UnsafeNativeMethods.sqlite3_key(_sql, passwordBytes, passwordBytes.Length);
\r
848 if (n > 0) throw new SQLiteException(n, SQLiteLastError());
\r
851 internal override void ChangePassword(byte[] newPasswordBytes)
\r
853 int n = UnsafeNativeMethods.sqlite3_rekey(_sql, newPasswordBytes, (newPasswordBytes == null) ? 0 : newPasswordBytes.Length);
\r
854 if (n > 0) throw new SQLiteException(n, SQLiteLastError());
\r
857 internal override void SetUpdateHook(SQLiteUpdateCallback func)
\r
859 UnsafeNativeMethods.sqlite3_update_hook(_sql, func, IntPtr.Zero);
\r
862 internal override void SetCommitHook(SQLiteCommitCallback func)
\r
864 UnsafeNativeMethods.sqlite3_commit_hook(_sql, func, IntPtr.Zero);
\r
867 internal override void SetRollbackHook(SQLiteRollbackCallback func)
\r
869 UnsafeNativeMethods.sqlite3_rollback_hook(_sql, func, IntPtr.Zero);
\r
873 /// Helper function to retrieve a column of data from an active statement.
\r
875 /// <param name="stmt">The statement being step()'d through</param>
\r
876 /// <param name="index">The column index to retrieve</param>
\r
877 /// <param name="typ">The type of data contained in the column. If Uninitialized, this function will retrieve the datatype information.</param>
\r
878 /// <returns>Returns the data in the column</returns>
\r
879 internal override object GetValue(SQLiteStatement stmt, int index, SQLiteType typ)
\r
881 if (IsNull(stmt, index)) return DBNull.Value;
\r
882 TypeAffinity aff = typ.Affinity;
\r
885 if (typ.Type != DbType.Object)
\r
887 t = SQLiteConvert.SQLiteTypeToType(typ);
\r
888 aff = TypeToAffinity(t);
\r
893 case TypeAffinity.Blob:
\r
894 if (typ.Type == DbType.Guid && typ.Affinity == TypeAffinity.Text)
\r
895 return new Guid(GetText(stmt, index));
\r
897 int n = (int)GetBytes(stmt, index, 0, null, 0, 0);
\r
898 byte[] b = new byte[n];
\r
899 GetBytes(stmt, index, 0, b, 0, n);
\r
901 if (typ.Type == DbType.Guid && n == 16)
\r
902 return new Guid(b);
\r
905 case TypeAffinity.DateTime:
\r
906 return GetDateTime(stmt, index);
\r
907 case TypeAffinity.Double:
\r
908 if (t == null) return GetDouble(stmt, index);
\r
910 return Convert.ChangeType(GetDouble(stmt, index), t, null);
\r
911 case TypeAffinity.Int64:
\r
912 if (t == null) return GetInt64(stmt, index);
\r
914 return Convert.ChangeType(GetInt64(stmt, index), t, null);
\r
916 return GetText(stmt, index);
\r
920 internal override int GetCursorForTable(SQLiteStatement stmt, int db, int rootPage)
\r
922 #if !SQLITE_STANDARD
\r
923 return UnsafeNativeMethods.sqlite3_table_cursor(stmt._sqlite_stmt, db, rootPage);
\r
929 internal override long GetRowIdForCursor(SQLiteStatement stmt, int cursor)
\r
931 #if !SQLITE_STANDARD
\r
933 int rc = UnsafeNativeMethods.sqlite3_cursor_rowid(stmt._sqlite_stmt, cursor, out rowid);
\r
934 if (rc == 0) return rowid;
\r
942 internal override void GetIndexColumnExtendedInfo(string database, string index, string column, out int sortMode, out int onError, out string collationSequence)
\r
944 #if !SQLITE_STANDARD
\r
949 rc = UnsafeNativeMethods.sqlite3_index_column_info_interop(_sql, ToUTF8(database), ToUTF8(index), ToUTF8(column), out sortMode, out onError, out coll, out colllen);
\r
950 if (rc != 0) throw new SQLiteException(rc, "");
\r
952 collationSequence = UTF8ToString(coll, colllen);
\r
956 collationSequence = "BINARY";
\r