Merge pull request #349 from JamesB7/229b363ef861ab9456f8bdc428c550e2241688e9
[mono.git] / mcs / class / Mono.Data.Sqlite / Mono.Data.Sqlite_2.0 / SQLiteConvert.cs
index 2488166c17fc0bd17a42328f048cc9f04637dd00..fe751b822af63971e2f2abfd420f975681f72822 100644 (file)
-//
-// Mono.Data.Sqlite.SQLiteConvert.cs
-//
-// Author(s):
-//   Robert Simpson (robert@blackcastlesoft.com)
-//
-// Adapted and modified for the Mono Project by
-//   Marek Habersack (grendello@gmail.com)
-//
-//
-// Copyright (C) 2006 Novell, Inc (http://www.novell.com)
-// Copyright (C) 2007 Marek Habersack
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-// 
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-// 
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-/********************************************************
- * ADO.NET 2.0 Data Provider for Sqlite Version 3.X
- * Written by Robert Simpson (robert@blackcastlesoft.com)
- * 
- * Released to the public domain, use at your own risk!
- ********************************************************/
-#if NET_2_0
-namespace Mono.Data.Sqlite
-{
-  using System;
-  using System.Data;
-  using System.Runtime.InteropServices;
-  using System.Collections.Generic;
-  using System.ComponentModel;
-  using System.Globalization;
-  using System.Text;
-
-#if !PLATFORM_COMPACTFRAMEWORK 
-  using System.ComponentModel.Design;
-#endif
-
-  /// <summary>
-  /// Sqlite has very limited types, and is inherently text-based.  The first 5 types below represent the sum of all types Sqlite
-  /// understands.  The DateTime extension to the spec is for internal use only.
-  /// </summary>
-  public enum TypeAffinity
-  {
-    /// <summary>
-    /// Not used
-    /// </summary>
-    Uninitialized = 0,
-    /// <summary>
-    /// All integers in Sqlite default to Int64
-    /// </summary>
-    Int64 = 1,
-    /// <summary>
-    /// All floating point numbers in Sqlite default to double
-    /// </summary>
-    Double = 2,
-    /// <summary>
-    /// The default data type of Sqlite is text
-    /// </summary>
-    Text = 3,
-    /// <summary>
-    /// Typically blob types are only seen when returned from a function
-    /// </summary>
-    Blob = 4,
-    /// <summary>
-    /// Null types can be returned from functions
-    /// </summary>
-    Null = 5,
-    /// <summary>
-    /// Used internally by this provider
-    /// </summary>
-    DateTime = 10,
-    /// <summary>
-    /// Used internally
-    /// </summary>
-    None = 11,
-  }
-
-  /// <summary>
-  /// This implementation of Sqlite for ADO.NET can process date/time fields in databases in only one of two formats.  Ticks and ISO8601.
-  /// Ticks is inherently more accurate, but less compatible with 3rd party tools that query the database, and renders the DateTime field
-  /// unreadable without post-processing.
-  /// ISO8601 is more compatible, readable, fully-processable, but less accurate as it doesn't provide time down to fractions of a second.
-  /// </summary>
-  public enum SqliteDateFormats
-  {
-    /// <summary>
-    /// Using ticks is more accurate but less compatible with other viewers and utilities that access your database.
-    /// </summary>
-    Ticks = 0,
-    /// <summary>
-    /// The default format for this provider.
-    /// </summary>
-    ISO8601 = 1,
-  }
-
-  /// <summary>
-  /// Struct used internally to determine the datatype of a column in a resultset
-  /// </summary>
-  internal struct SqliteType
-  {
-    /// <summary>
-    /// The DbType of the column, or DbType.Object if it cannot be determined
-    /// </summary>
-    internal DbType Type;
-    /// <summary>
-    /// The affinity of a column, used for expressions or when Type is DbType.Object
-    /// </summary>
-    internal TypeAffinity Affinity;
-  }
-
-  internal struct SqliteTypeNames
-  {
-    internal SqliteTypeNames(string newtypeName, DbType newdataType)
-    {
-      typeName = newtypeName;
-      dataType = newdataType;
-    }
-
-    internal string typeName;
-    internal DbType dataType;
-  }
-
-  /// <summary>
-  /// This base class provides datatype conversion services for the Sqlite provider.
-  /// </summary>
-  public abstract class SqliteConvert
-  {
-    /// <summary>
-    /// An array of ISO8601 datetime formats we support conversion from
-    /// </summary>
-    private static string[] _datetimeFormats = new string[] {
-      "yyyy-MM-dd HH:mm:ss.fffffff",
-      "yyyy-MM-dd HH:mm:ss",
-      "yyyy-MM-dd HH:mm",                               
-      "yyyyMMddHHmmss",
-      "yyyyMMddHHmm",
-      "yyyyMMddTHHmmssfffffff",
-      "yyyy-MM-dd",
-      "yy-MM-dd",
-      "yyyyMMdd",
-      "HH:mm:ss",
-      "HH:mm",
-      "THHmmss",
-      "THHmm",
-      "yyyy-MM-dd HH:mm:ss.fff",
-      "yyyy-MM-ddTHH:mm",
-      "yyyy-MM-ddTHH:mm:ss",
-      "yyyy-MM-ddTHH:mm:ss.fff",
-      "yyyy-MM-ddTHH:mm:ss.ffffff",
-      "HH:mm:ss.fff"
-    };
-
-    /// <summary>
-    /// An UTF-8 Encoding instance, so we can convert strings to and from UTF-8
-    /// </summary>
-    private Encoding _utf8 = new UTF8Encoding();
-    /// <summary>
-    /// The default DateTime format for this instance
-    /// </summary>
-    internal SqliteDateFormats _datetimeFormat;
-    /// <summary>
-    /// Initializes the conversion class
-    /// </summary>
-    /// <param name="fmt">The default date/time format to use for this instance</param>
-    internal SqliteConvert(SqliteDateFormats fmt)
-    {
-      _datetimeFormat = fmt;
-    }
-
-    #region UTF-8 Conversion Functions
-    /// <summary>
-    /// Converts a string to a UTF-8 encoded byte array sized to include a null-terminating character.
-    /// </summary>
-    /// <param name="sourceText">The string to convert to UTF-8</param>
-    /// <returns>A byte array containing the converted string plus an extra 0 terminating byte at the end of the array.</returns>
-    public byte[] ToUTF8(string sourceText)
-    {
-      Byte[] byteArray;
-      int nlen = _utf8.GetByteCount(sourceText) + 1;
-
-      byteArray = new byte[nlen];
-      nlen = _utf8.GetBytes(sourceText, 0, sourceText.Length, byteArray, 0);
-      byteArray[nlen] = 0;
-
-      return byteArray;
-    }
-
-    /// <summary>
-    /// Convert a DateTime to a UTF-8 encoded, zero-terminated byte array.
-    /// </summary>
-    /// <remarks>
-    /// This function is a convenience function, which first calls ToString() on the DateTime, and then calls ToUTF8() with the
-    /// string result.
-    /// </remarks>
-    /// <param name="dateTimeValue">The DateTime to convert.</param>
-    /// <returns>The UTF-8 encoded string, including a 0 terminating byte at the end of the array.</returns>
-    public byte[] ToUTF8(DateTime dateTimeValue)
-    {
-      return ToUTF8(ToString(dateTimeValue));
-    }
-
-    /// <summary>
-    /// Converts a UTF-8 encoded IntPtr of the specified length into a .NET string
-    /// </summary>
-    /// <param name="nativestring">The pointer to the memory where the UTF-8 string is encoded</param>
-    /// <param name="nativestringlen">The number of bytes to decode</param>
-    /// <returns>A string containing the translated character(s)</returns>
-    public virtual string ToString(IntPtr nativestring)
-    {
-      return UTF8ToString(nativestring);
-    }
-
-    /// <summary>
-    /// Converts a UTF-8 encoded IntPtr of the specified length into a .NET string
-    /// </summary>
-    /// <param name="nativestring">The pointer to the memory where the UTF-8 string is encoded</param>
-    /// <param name="nativestringlen">The number of bytes to decode</param>
-    /// <returns>A string containing the translated character(s)</returns>
-    public virtual string UTF8ToString(IntPtr nativestring)
-    {
-           return Marshal.PtrToStringAuto (nativestring);
-    }
-
-
-    #endregion
-
-    #region DateTime Conversion Functions
-    /// <summary>
-    /// Converts a string into a DateTime, using the current DateTimeFormat specified for the connection when it was opened.
-    /// </summary>
-    /// <remarks>
-    /// Acceptable ISO8601 DateTime formats are:
-    ///   yyyy-MM-dd HH:mm:ss
-    ///   yyyyMMddHHmmss
-    ///   yyyyMMddTHHmmssfffffff
-    ///   yyyy-MM-dd
-    ///   yy-MM-dd
-    ///   yyyyMMdd
-    ///   HH:mm:ss
-    ///   THHmmss
-    /// </remarks>
-    /// <param name="dateText">The string containing either a Tick value or an ISO8601-format string</param>
-    /// <returns>A DateTime value</returns>
-    public DateTime ToDateTime(string dateText)
-    {
-      switch (_datetimeFormat)
-      {
-        case SqliteDateFormats.Ticks:
-          return new DateTime(Convert.ToInt64(dateText, CultureInfo.InvariantCulture));
-        default:
-          return DateTime.ParseExact(dateText, _datetimeFormats, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.None);
-      }
-    }
-
-    /// <summary>
-    /// Converts a DateTime to a string value, using the current DateTimeFormat specified for the connection when it was opened.
-    /// </summary>
-    /// <param name="dateValue">The DateTime value to convert</param>
-    /// <returns>Either a string consisting of the tick count for DateTimeFormat.Ticks, or a date/time in ISO8601 format.</returns>
-    public string ToString(DateTime dateValue)
-    {
-      switch (_datetimeFormat)
-      {
-        case SqliteDateFormats.Ticks:
-          return dateValue.Ticks.ToString(CultureInfo.InvariantCulture);
-        default:
-          return dateValue.ToString(_datetimeFormats[0], CultureInfo.InvariantCulture);
-      }
-    }
-
-    /// <summary>
-    /// Internal function to convert a UTF-8 encoded IntPtr of the specified length to a DateTime.
-    /// </summary>
-    /// <remarks>
-    /// This is a convenience function, which first calls ToString() on the IntPtr to convert it to a string, then calls
-    /// ToDateTime() on the string to return a DateTime.
-    /// </remarks>
-    /// <param name="ptr">A pointer to the UTF-8 encoded string</param>
-    /// <param name="len">The length in bytes of the string</param>
-    /// <returns>The parsed DateTime value</returns>
-    internal DateTime ToDateTime(IntPtr ptr)
-    {
-      return ToDateTime(ToString(ptr));
-    }
-    #endregion
-
-    /// <summary>
-    /// Smart method of splitting a string.  Skips quoted elements, removes the quotes.
-    /// </summary>
-    /// <remarks>
-    /// This split function works somewhat like the String.Split() function in that it breaks apart a string into
-    /// pieces and returns the pieces as an array.  The primary differences are:
-    /// <list type="bullet">
-    /// <item><description>Only one character can be provided as a separator character</description></item>
-    /// <item><description>Quoted text inside the string is skipped over when searching for the separator, and the quotes are removed.</description></item>
-    /// </list>
-    /// Thus, if splitting the following string looking for a comma:<br/>
-    /// One,Two, "Three, Four", Five<br/>
-    /// <br/>
-    /// The resulting array would contain<br/>
-    /// [0] One<br/>
-    /// [1] Two<br/>
-    /// [2] Three, Four<br/>
-    /// [3] Five<br/>
-    /// <br/>
-    /// Note that the leading and trailing spaces were removed from each item during the split.
-    /// </remarks>
-    /// <param name="source">Source string to split apart</param>
-    /// <param name="separator">Separator character</param>
-    /// <returns>A string array of the split up elements</returns>
-    public static string[] Split(string source, char separator)
-    {
-      char[] toks = new char[2] { '\"', separator };
-      char[] quot = new char[1] { '\"' };
-      int n = 0;
-      List<string> ls = new List<string>();
-      string s;
-
-      while (source.Length > 0)
-      {
-        n = source.IndexOfAny(toks, n);
-        if (n == -1) break;
-        if (source[n] == toks[0])
-        {
-          source = source.Remove(n, 1);
-          n = source.IndexOfAny(quot, n);
-          if (n == -1)
-          {
-            source = "\"" + source;
-            break;
-          }
-          source = source.Remove(n, 1);
-        }
-        else
-        {
-          s = source.Substring(0, n).Trim();
-          source = source.Substring(n + 1).Trim();
-          if (s.Length > 0) ls.Add(s);
-          n = 0;
-        }
-      }
-      if (source.Length > 0) ls.Add(source);
-
-      string[] ar = new string[ls.Count];
-      ls.CopyTo(ar, 0);
-
-      return ar;
-    }
-
-    #region Type Conversions
-    /// <summary>
-    /// Determines the data type of a column in a statement
-    /// </summary>
-    /// <param name="stmt">The statement to retrieve information for</param>
-    /// <param name="i">The column to retrieve type information on</param>
-    /// <returns>Returns a SqliteType struct</returns>
-    internal static SqliteType ColumnToType(SqliteStatement stmt, int i)
-    {
-      SqliteType typ;
-
-      typ.Type = TypeNameToDbType(stmt._sql.ColumnType(stmt, i, out typ.Affinity));
-
-      return typ;
-    }
-
-    /// <summary>
-    /// Converts a SqliteType to a .NET Type object
-    /// </summary>
-    /// <param name="t">The SqliteType to convert</param>
-    /// <returns>Returns a .NET Type object</returns>
-    internal static Type SqliteTypeToType(SqliteType t)
-    {
-      if (t.Type != DbType.Object)
-        return SqliteConvert.DbTypeToType(t.Type);
-
-      return _typeaffinities[(int)t.Affinity];
-    }
-
-    static Type[] _typeaffinities = {
-      null,
-      typeof(Int64),
-      typeof(Double),
-      typeof(string),
-      typeof(byte[]),
-      typeof(DBNull),
-      null,
-      null,
-      null,
-      null,
-      typeof(DateTime),
-      null,
-    };
-
-    /// <summary>
-    /// For a given intrinsic type, return a DbType
-    /// </summary>
-    /// <param name="typ">The native type to convert</param>
-    /// <returns>The corresponding (closest match) DbType</returns>
-    internal static DbType TypeToDbType(Type typ)
-    {
-      TypeCode tc = Type.GetTypeCode(typ);
-      if (tc == TypeCode.Object)
-      {
-        if (typ == typeof(byte[])) return DbType.Binary;
-        if (typ == typeof(Guid)) return DbType.Guid;
-        return DbType.String;
-      }
-      return _typetodbtype[(int)tc];
-    }
-
-    private static DbType[] _typetodbtype = {
-      DbType.Object,
-      DbType.Binary,
-      DbType.Object,
-      DbType.Boolean,
-      DbType.SByte,
-      DbType.SByte,
-      DbType.Byte,
-      DbType.Int16, // 7
-      DbType.UInt16,
-      DbType.Int32,
-      DbType.UInt32,
-      DbType.Int64, // 11
-      DbType.UInt64,
-      DbType.Single,
-      DbType.Double,
-      DbType.Decimal,
-      DbType.DateTime,
-      DbType.Object,
-      DbType.String,
-    };
-
-    /// <summary>
-    /// Returns the ColumnSize for the given DbType
-    /// </summary>
-    /// <param name="typ">The DbType to get the size of</param>
-    /// <returns></returns>
-    internal static int DbTypeToColumnSize(DbType typ)
-    {
-      return _dbtypetocolumnsize[(int)typ];
-    }
-
-    private static int[] _dbtypetocolumnsize = {
-      2147483647,   // 0
-      2147483647,   // 1
-      1,     // 2
-      1,     // 3
-      8,  // 4
-      8, // 5
-      8, // 6
-      8,  // 7
-      8,   // 8
-      16,     // 9
-      2,
-      4,
-      8,
-      2147483647,
-      1,
-      4,
-      2147483647,
-      8,
-      2,
-      4,
-      8,
-      8,
-      2147483647,
-      2147483647,
-      2147483647,
-      2147483647,   // 25 (Xml)
-    };
-
-    /// <summary>
-    /// Convert a DbType to a Type
-    /// </summary>
-    /// <param name="typ">The DbType to convert from</param>
-    /// <returns>The closest-match .NET type</returns>
-    internal static Type DbTypeToType(DbType typ)
-    {
-      return _dbtypeToType[(int)typ];
-    }
-
-    private static Type[] _dbtypeToType = {
-      typeof(string),   // 0
-      typeof(byte[]),   // 1
-      typeof(byte),     // 2
-      typeof(bool),     // 3
-      typeof(decimal),  // 4
-      typeof(DateTime), // 5
-      typeof(DateTime), // 6
-      typeof(decimal),  // 7
-      typeof(double),   // 8
-      typeof(Guid),     // 9
-      typeof(Int16),
-      typeof(Int32),
-      typeof(Int64),
-      typeof(object),
-      typeof(sbyte),
-      typeof(float),
-      typeof(string),
-      typeof(DateTime),
-      typeof(UInt16),
-      typeof(UInt32),
-      typeof(UInt64),
-      typeof(double),
-      typeof(string),
-      typeof(string),
-      typeof(string),
-      typeof(string),   // 25 (Xml)
-    };
-
-    /// <summary>
-    /// For a given type, return the closest-match Sqlite TypeAffinity, which only understands a very limited subset of types.
-    /// </summary>
-    /// <param name="typ">The type to evaluate</param>
-    /// <returns>The Sqlite type affinity for that type.</returns>
-    internal static TypeAffinity TypeToAffinity(Type typ)
-    {
-      TypeCode tc = Type.GetTypeCode(typ);
-      if (tc == TypeCode.Object)
-      {
-        if (typ == typeof(byte[]) || typ == typeof(Guid))
-          return TypeAffinity.Blob;
-        else
-          return TypeAffinity.Text;
-      }
-      return _typecodeAffinities[(int)tc];
-    }
-
-    private static TypeAffinity[] _typecodeAffinities = {
-      TypeAffinity.Null,
-      TypeAffinity.Blob,
-      TypeAffinity.Null,
-      TypeAffinity.Int64,
-      TypeAffinity.Int64,
-      TypeAffinity.Int64,
-      TypeAffinity.Int64,
-      TypeAffinity.Int64, // 7
-      TypeAffinity.Int64,
-      TypeAffinity.Int64,
-      TypeAffinity.Int64,
-      TypeAffinity.Int64, // 11
-      TypeAffinity.Int64,
-      TypeAffinity.Double,
-      TypeAffinity.Double,
-      TypeAffinity.Double,
-      TypeAffinity.DateTime,
-      TypeAffinity.Null,
-      TypeAffinity.Text,
-    };
-
-    /// <summary>
-    /// For a given type name, return a closest-match .NET type
-    /// </summary>
-    /// <param name="Name">The name of the type to match</param>
-    /// <returns>The .NET DBType the text evaluates to.</returns>
-    internal static DbType TypeNameToDbType(string Name)
-    {
-      if (String.IsNullOrEmpty(Name)) return DbType.Object;
-
-      int x = _typeNames.Length;
-      for (int n = 0; n < x; n++)
-      {
-        if (String.Compare(Name, 0, _typeNames[n].typeName, 0, _typeNames[n].typeName.Length, true, CultureInfo.InvariantCulture) == 0)
-          return _typeNames[n].dataType; 
-      }
-      return DbType.Object;
-    }
-    #endregion
-
-    private static SqliteTypeNames[] _typeNames = {
-      new SqliteTypeNames("COUNTER", DbType.Int64),
-      new SqliteTypeNames("AUTOINCREMENT", DbType.Int64),
-      new SqliteTypeNames("IDENTITY", DbType.Int64),
-      new SqliteTypeNames("LONGTEXT", DbType.String),
-      new SqliteTypeNames("LONGCHAR", DbType.String),
-      new SqliteTypeNames("LONGVARCHAR", DbType.String),
-      new SqliteTypeNames("LONG", DbType.Int64),
-      new SqliteTypeNames("TINYINT", DbType.Byte),
-      new SqliteTypeNames("INTEGER", DbType.Int64),
-      new SqliteTypeNames("INT", DbType.Int32),
-      new SqliteTypeNames("VARCHAR", DbType.String),
-      new SqliteTypeNames("NVARCHAR", DbType.String),
-      new SqliteTypeNames("CHAR", DbType.String),
-      new SqliteTypeNames("NCHAR", DbType.String),
-      new SqliteTypeNames("TEXT", DbType.String),
-      new SqliteTypeNames("NTEXT", DbType.String),
-      new SqliteTypeNames("STRING", DbType.String),
-      new SqliteTypeNames("DOUBLE", DbType.Double),
-      new SqliteTypeNames("FLOAT", DbType.Double),
-      new SqliteTypeNames("REAL", DbType.Single),          
-      new SqliteTypeNames("BIT", DbType.Boolean),
-      new SqliteTypeNames("YESNO", DbType.Boolean),
-      new SqliteTypeNames("LOGICAL", DbType.Boolean),
-      new SqliteTypeNames("BOOL", DbType.Boolean),
-      new SqliteTypeNames("NUMERIC", DbType.Decimal),
-      new SqliteTypeNames("DECIMAL", DbType.Decimal),
-      new SqliteTypeNames("MONEY", DbType.Decimal),
-      new SqliteTypeNames("CURRENCY", DbType.Decimal),
-      new SqliteTypeNames("TIME", DbType.DateTime),
-      new SqliteTypeNames("DATE", DbType.DateTime),
-      new SqliteTypeNames("SMALLDATE", DbType.DateTime),
-      new SqliteTypeNames("BLOB", DbType.Binary),
-      new SqliteTypeNames("BINARY", DbType.Binary),
-      new SqliteTypeNames("VARBINARY", DbType.Binary),
-      new SqliteTypeNames("IMAGE", DbType.Binary),
-      new SqliteTypeNames("GENERAL", DbType.Binary),
-      new SqliteTypeNames("OLEOBJECT", DbType.Binary),
-      new SqliteTypeNames("GUID", DbType.Guid),
-      new SqliteTypeNames("UNIQUEIDENTIFIER", DbType.Guid),
-      new SqliteTypeNames("MEMO", DbType.String),
-      new SqliteTypeNames("NOTE", DbType.String),
-      new SqliteTypeNames("SMALLINT", DbType.Int16),
-      new SqliteTypeNames("BIGINT", DbType.Int64),
-    };
-  }
-}
-#endif
+/********************************************************\r
+ * ADO.NET 2.0 Data Provider for SQLite Version 3.X\r
+ * Written by Robert Simpson (robert@blackcastlesoft.com)\r
+ * \r
+ * Released to the public domain, use at your own risk!\r
+ ********************************************************/\r
+\r
+namespace Mono.Data.Sqlite\r
+{\r
+  using System;\r
+  using System.Data;\r
+  using System.Runtime.InteropServices;\r
+  using System.Collections.Generic;\r
+  using System.ComponentModel;\r
+  using System.Globalization;\r
+  using System.Text;\r
+\r
+#if !PLATFORM_COMPACTFRAMEWORK \r
+  using System.ComponentModel.Design;\r
+#endif\r
+\r
+  /// <summary>\r
+  /// This base class provides datatype conversion services for the SQLite provider.\r
+  /// </summary>\r
+  public abstract class SqliteConvert\r
+  {\r
+    /// <summary>\r
+    /// The value for the Unix epoch (e.g. January 1, 1970 at midnight, in UTC).\r
+    /// </summary>\r
+    protected static readonly DateTime UnixEpoch =\r
+        new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);\r
+    /// <summary>\r
+    /// An array of ISO8601 datetime formats we support conversion from\r
+    /// </summary>\r
+    private static string[] _datetimeFormats = new string[] {\r
+      "THHmmss",\r
+      "THHmm",\r
+      "HH:mm:ss",\r
+      "HH:mm",\r
+      "HH:mm:ss.FFFFFFF",\r
+      "yy-MM-dd",\r
+      "yyyy-MM-dd",\r
+      "yyyy-MM-dd HH:mm:ss.FFFFFFF",\r
+      "yyyy-MM-dd HH:mm:ss",\r
+      "yyyy-MM-dd HH:mm",                               \r
+      "yyyy-MM-ddTHH:mm:ss.FFFFFFF",\r
+      "yyyy-MM-ddTHH:mm",\r
+      "yyyy-MM-ddTHH:mm:ss",\r
+      "yyyyMMddHHmmss",\r
+      "yyyyMMddHHmm",\r
+      "yyyyMMddTHHmmssFFFFFFF",\r
+      "yyyyMMdd"\r
+    };\r
+\r
+    /// <summary>\r
+    /// An UTF-8 Encoding instance, so we can convert strings to and from UTF-8\r
+    /// </summary>\r
+    private static Encoding _utf8 = new UTF8Encoding();\r
+    /// <summary>\r
+    /// The default DateTime format for this instance\r
+    /// </summary>\r
+    internal SQLiteDateFormats _datetimeFormat;\r
+    /// <summary>\r
+    /// Initializes the conversion class\r
+    /// </summary>\r
+    /// <param name="fmt">The default date/time format to use for this instance</param>\r
+    internal SqliteConvert(SQLiteDateFormats fmt)\r
+    {\r
+      _datetimeFormat = fmt;\r
+    }\r
+\r
+    #region UTF-8 Conversion Functions\r
+    /// <summary>\r
+    /// Converts a string to a UTF-8 encoded byte array sized to include a null-terminating character.\r
+    /// </summary>\r
+    /// <param name="sourceText">The string to convert to UTF-8</param>\r
+    /// <returns>A byte array containing the converted string plus an extra 0 terminating byte at the end of the array.</returns>\r
+    public static byte[] ToUTF8(string sourceText)\r
+    {\r
+      Byte[] byteArray;\r
+      int nlen = _utf8.GetByteCount(sourceText) + 1;\r
+\r
+      byteArray = new byte[nlen];\r
+      nlen = _utf8.GetBytes(sourceText, 0, sourceText.Length, byteArray, 0);\r
+      byteArray[nlen] = 0;\r
+\r
+      return byteArray;\r
+    }\r
+\r
+    /// <summary>\r
+    /// Convert a DateTime to a UTF-8 encoded, zero-terminated byte array.\r
+    /// </summary>\r
+    /// <remarks>\r
+    /// This function is a convenience function, which first calls ToString() on the DateTime, and then calls ToUTF8() with the\r
+    /// string result.\r
+    /// </remarks>\r
+    /// <param name="dateTimeValue">The DateTime to convert.</param>\r
+    /// <returns>The UTF-8 encoded string, including a 0 terminating byte at the end of the array.</returns>\r
+    public byte[] ToUTF8(DateTime dateTimeValue)\r
+    {\r
+      return ToUTF8(ToString(dateTimeValue));\r
+    }\r
+\r
+    /// <summary>\r
+    /// Converts a UTF-8 encoded IntPtr of the specified length into a .NET string\r
+    /// </summary>\r
+    /// <param name="nativestring">The pointer to the memory where the UTF-8 string is encoded</param>\r
+    /// <param name="nativestringlen">The number of bytes to decode</param>\r
+    /// <returns>A string containing the translated character(s)</returns>\r
+    public virtual string ToString(IntPtr nativestring, int nativestringlen)\r
+    {\r
+      return UTF8ToString(nativestring, nativestringlen);\r
+    }\r
+\r
+    /// <summary>\r
+    /// Converts a UTF-8 encoded IntPtr of the specified length into a .NET string\r
+    /// </summary>\r
+    /// <param name="nativestring">The pointer to the memory where the UTF-8 string is encoded</param>\r
+    /// <param name="nativestringlen">The number of bytes to decode</param>\r
+    /// <returns>A string containing the translated character(s)</returns>\r
+    public static string UTF8ToString(IntPtr nativestring, int nativestringlen)\r
+    {\r
+      if (nativestringlen == 0 || nativestring == IntPtr.Zero) return "";\r
+      if (nativestringlen == -1)\r
+      {\r
+        do\r
+        {\r
+          nativestringlen++;\r
+        } while (Marshal.ReadByte(nativestring, nativestringlen) != 0);\r
+      }\r
+\r
+      byte[] byteArray = new byte[nativestringlen];\r
+      \r
+      Marshal.Copy(nativestring, byteArray, 0, nativestringlen);\r
+\r
+      return _utf8.GetString(byteArray, 0, nativestringlen);\r
+    }\r
+\r
+\r
+    #endregion\r
+\r
+    #region DateTime Conversion Functions\r
+    /// <summary>\r
+    /// Converts a string into a DateTime, using the current DateTimeFormat specified for the connection when it was opened.\r
+    /// </summary>\r
+    /// <remarks>\r
+    /// Acceptable ISO8601 DateTime formats are:\r
+    ///   yyyy-MM-dd HH:mm:ss\r
+    ///   yyyyMMddHHmmss\r
+    ///   yyyyMMddTHHmmssfffffff\r
+    ///   yyyy-MM-dd\r
+    ///   yy-MM-dd\r
+    ///   yyyyMMdd\r
+    ///   HH:mm:ss\r
+    ///   THHmmss\r
+    /// </remarks>\r
+    /// <param name="dateText">The string containing either a Tick value, a JulianDay double, or an ISO8601-format string</param>\r
+    /// <returns>A DateTime value</returns>\r
+    public DateTime ToDateTime(string dateText)\r
+    {\r
+      switch (_datetimeFormat)\r
+      {\r
+        case SQLiteDateFormats.Ticks:\r
+          return new DateTime(Convert.ToInt64(dateText, CultureInfo.InvariantCulture));\r
+        case SQLiteDateFormats.JulianDay:\r
+          return ToDateTime(Convert.ToDouble(dateText, CultureInfo.InvariantCulture));\r
+        case SQLiteDateFormats.UnixEpoch:\r
+          return UnixEpoch.AddSeconds(Convert.ToInt32(dateText, CultureInfo.InvariantCulture));\r
+        default:\r
+          return DateTime.ParseExact(dateText, _datetimeFormats, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.None);\r
+      }\r
+    }\r
+\r
+    /// <summary>\r
+    /// Converts a julianday value into a DateTime\r
+    /// </summary>\r
+    /// <param name="julianDay">The value to convert</param>\r
+    /// <returns>A .NET DateTime</returns>\r
+    public DateTime ToDateTime(double julianDay)\r
+    {\r
+      return DateTime.FromOADate(julianDay - 2415018.5);\r
+    }\r
+\r
+    /// <summary>\r
+    /// Converts a DateTime struct to a JulianDay double\r
+    /// </summary>\r
+    /// <param name="value">The DateTime to convert</param>\r
+    /// <returns>The JulianDay value the Datetime represents</returns>\r
+    public double ToJulianDay(DateTime value)\r
+    {\r
+      return value.ToOADate() + 2415018.5;\r
+    }\r
+\r
+    /// <summary>\r
+    /// Converts a DateTime to a string value, using the current DateTimeFormat specified for the connection when it was opened.\r
+    /// </summary>\r
+    /// <param name="dateValue">The DateTime value to convert</param>\r
+    /// <returns>Either a string consisting of the tick count for DateTimeFormat.Ticks, a JulianDay double, or a date/time in ISO8601 format.</returns>\r
+    public string ToString(DateTime dateValue)\r
+    {\r
+      switch (_datetimeFormat)\r
+      {\r
+        case SQLiteDateFormats.Ticks:\r
+          return dateValue.Ticks.ToString(CultureInfo.InvariantCulture);\r
+        case SQLiteDateFormats.JulianDay:\r
+          return ToJulianDay(dateValue).ToString(CultureInfo.InvariantCulture);\r
+        case SQLiteDateFormats.UnixEpoch:\r
+          return ((long)(dateValue.Subtract(UnixEpoch).Ticks / TimeSpan.TicksPerSecond)).ToString();\r
+        default:\r
+          return dateValue.ToString(_datetimeFormats[7], CultureInfo.InvariantCulture);\r
+      }\r
+    }\r
+\r
+    /// <summary>\r
+    /// Internal function to convert a UTF-8 encoded IntPtr of the specified length to a DateTime.\r
+    /// </summary>\r
+    /// <remarks>\r
+    /// This is a convenience function, which first calls ToString() on the IntPtr to convert it to a string, then calls\r
+    /// ToDateTime() on the string to return a DateTime.\r
+    /// </remarks>\r
+    /// <param name="ptr">A pointer to the UTF-8 encoded string</param>\r
+    /// <param name="len">The length in bytes of the string</param>\r
+    /// <returns>The parsed DateTime value</returns>\r
+    internal DateTime ToDateTime(IntPtr ptr, int len)\r
+    {\r
+      return ToDateTime(ToString(ptr, len));\r
+    }\r
+\r
+    #endregion\r
+\r
+    /// <summary>\r
+    /// Smart method of splitting a string.  Skips quoted elements, removes the quotes.\r
+    /// </summary>\r
+    /// <remarks>\r
+    /// This split function works somewhat like the String.Split() function in that it breaks apart a string into\r
+    /// pieces and returns the pieces as an array.  The primary differences are:\r
+    /// <list type="bullet">\r
+    /// <item><description>Only one character can be provided as a separator character</description></item>\r
+    /// <item><description>Quoted text inside the string is skipped over when searching for the separator, and the quotes are removed.</description></item>\r
+    /// </list>\r
+    /// Thus, if splitting the following string looking for a comma:<br/>\r
+    /// One,Two, "Three, Four", Five<br/>\r
+    /// <br/>\r
+    /// The resulting array would contain<br/>\r
+    /// [0] One<br/>\r
+    /// [1] Two<br/>\r
+    /// [2] Three, Four<br/>\r
+    /// [3] Five<br/>\r
+    /// <br/>\r
+    /// Note that the leading and trailing spaces were removed from each item during the split.\r
+    /// </remarks>\r
+    /// <param name="source">Source string to split apart</param>\r
+    /// <param name="separator">Separator character</param>\r
+    /// <returns>A string array of the split up elements</returns>\r
+    public static string[] Split(string source, char separator)\r
+    {\r
+      char[] toks = new char[2] { '\"', separator };\r
+      char[] quot = new char[1] { '\"' };\r
+      int n = 0;\r
+      List<string> ls = new List<string>();\r
+      string s;\r
+\r
+      while (source.Length > 0)\r
+      {\r
+        n = source.IndexOfAny(toks, n);\r
+        if (n == -1) break;\r
+        if (source[n] == toks[0])\r
+        {\r
+          //source = source.Remove(n, 1);\r
+          n = source.IndexOfAny(quot, n + 1);\r
+          if (n == -1)\r
+          {\r
+            //source = "\"" + source;\r
+            break;\r
+          }\r
+          n++;\r
+          //source = source.Remove(n, 1);\r
+        }\r
+        else\r
+        {\r
+          s = source.Substring(0, n).Trim();\r
+          if (s.Length > 1 && s[0] == quot[0] && s[s.Length - 1] == s[0])\r
+            s = s.Substring(1, s.Length - 2);\r
+\r
+          source = source.Substring(n + 1).Trim();\r
+          if (s.Length > 0) ls.Add(s);\r
+          n = 0;\r
+        }\r
+      }\r
+      if (source.Length > 0)\r
+      {\r
+        s = source.Trim();\r
+        if (s.Length > 1 && s[0] == quot[0] && s[s.Length - 1] == s[0])\r
+          s = s.Substring(1, s.Length - 2);\r
+        ls.Add(s);\r
+      }\r
+\r
+      string[] ar = new string[ls.Count];\r
+      ls.CopyTo(ar, 0);\r
+\r
+      return ar;\r
+    }\r
+\r
+    /// <summary>\r
+    /// Convert a value to true or false.\r
+    /// </summary>\r
+    /// <param name="source">A string or number representing true or false</param>\r
+    /// <returns></returns>\r
+    public static bool ToBoolean(object source)\r
+    {\r
+      if (source is bool) return (bool)source;\r
+\r
+      return ToBoolean(source.ToString());\r
+    }\r
+\r
+    /// <summary>\r
+    /// Convert a string to true or false.\r
+    /// </summary>\r
+    /// <param name="source">A string representing true or false</param>\r
+    /// <returns></returns>\r
+    /// <remarks>\r
+    /// "yes", "no", "y", "n", "0", "1", "on", "off" as well as Boolean.FalseString and Boolean.TrueString will all be\r
+    /// converted to a proper boolean value.\r
+    /// </remarks>\r
+    public static bool ToBoolean(string source)\r
+    {\r
+      if (String.Compare(source, bool.TrueString, StringComparison.OrdinalIgnoreCase) == 0) return true;\r
+      else if (String.Compare(source, bool.FalseString, StringComparison.OrdinalIgnoreCase) == 0) return false;\r
+\r
+      switch(source.ToLower())\r
+      {\r
+        case "yes":\r
+        case "y":\r
+        case "1":\r
+        case "on":\r
+          return true;\r
+        case "no":\r
+        case "n":\r
+        case "0":\r
+        case "off":\r
+          return false;\r
+        default:\r
+          throw new ArgumentException("source");\r
+      }\r
+    }\r
+\r
+    #region Type Conversions\r
+    /// <summary>\r
+    /// Determines the data type of a column in a statement\r
+    /// </summary>\r
+    /// <param name="stmt">The statement to retrieve information for</param>\r
+    /// <param name="i">The column to retrieve type information on</param>\r
+    /// <param name="typ">The SQLiteType to receive the affinity for the given column</param>\r
+    internal static void ColumnToType(SqliteStatement stmt, int i, SQLiteType typ)\r
+    {\r
+      typ.Type = TypeNameToDbType(stmt._sql.ColumnType(stmt, i, out typ.Affinity));\r
+    }\r
+\r
+    /// <summary>\r
+    /// Converts a SQLiteType to a .NET Type object\r
+    /// </summary>\r
+    /// <param name="t">The SQLiteType to convert</param>\r
+    /// <returns>Returns a .NET Type object</returns>\r
+    internal static Type SQLiteTypeToType(SQLiteType t)\r
+    {\r
+      if (t.Type == DbType.Object)\r
+        return _affinitytotype[(int)t.Affinity];\r
+      else\r
+        return SqliteConvert.DbTypeToType(t.Type);\r
+    }\r
+\r
+    private static Type[] _affinitytotype = {\r
+      typeof(object),\r
+      typeof(Int64),\r
+      typeof(Double),\r
+      typeof(string),\r
+      typeof(byte[]),\r
+      typeof(object),\r
+      typeof(DateTime),\r
+      typeof(object)\r
+    };\r
+\r
+    /// <summary>\r
+    /// For a given intrinsic type, return a DbType\r
+    /// </summary>\r
+    /// <param name="typ">The native type to convert</param>\r
+    /// <returns>The corresponding (closest match) DbType</returns>\r
+    internal static DbType TypeToDbType(Type typ)\r
+    {\r
+      TypeCode tc = Type.GetTypeCode(typ);\r
+      if (tc == TypeCode.Object)\r
+      {\r
+        if (typ == typeof(byte[])) return DbType.Binary;\r
+        if (typ == typeof(Guid)) return DbType.Guid;\r
+        return DbType.String;\r
+      }\r
+      return _typetodbtype[(int)tc];\r
+    }\r
+\r
+    private static DbType[] _typetodbtype = {\r
+      DbType.Object,\r
+      DbType.Binary,\r
+      DbType.Object,\r
+      DbType.Boolean,\r
+      DbType.SByte,\r
+      DbType.SByte,\r
+      DbType.Byte,\r
+      DbType.Int16, // 7\r
+      DbType.UInt16,\r
+      DbType.Int32,\r
+      DbType.UInt32,\r
+      DbType.Int64, // 11\r
+      DbType.UInt64,\r
+      DbType.Single,\r
+      DbType.Double,\r
+      DbType.Decimal,\r
+      DbType.DateTime,\r
+      DbType.Object,\r
+      DbType.String,\r
+    };\r
+\r
+    /// <summary>\r
+    /// Returns the ColumnSize for the given DbType\r
+    /// </summary>\r
+    /// <param name="typ">The DbType to get the size of</param>\r
+    /// <returns></returns>\r
+    internal static int DbTypeToColumnSize(DbType typ)\r
+    {\r
+      return _dbtypetocolumnsize[(int)typ];\r
+    }\r
+\r
+    private static int[] _dbtypetocolumnsize = {\r
+      2147483647,   // 0\r
+      2147483647,   // 1\r
+      1,     // 2\r
+      1,     // 3\r
+      8,  // 4\r
+      8, // 5\r
+      8, // 6\r
+      8,  // 7\r
+      8,   // 8\r
+      16,     // 9\r
+      2,\r
+      4,\r
+      8,\r
+      2147483647,\r
+      1,\r
+      4,\r
+      2147483647,\r
+      8,\r
+      2,\r
+      4,\r
+      8,\r
+      8,\r
+      2147483647,\r
+      2147483647,\r
+      2147483647,\r
+      2147483647,   // 25 (Xml)\r
+    };\r
+\r
+    internal static object DbTypeToNumericPrecision(DbType typ)\r
+    {\r
+      return _dbtypetonumericprecision[(int)typ];\r
+    }\r
+\r
+    private static object[] _dbtypetonumericprecision = {\r
+      DBNull.Value, // 0\r
+      DBNull.Value, // 1\r
+      3,\r
+      DBNull.Value,\r
+      19,\r
+      DBNull.Value, // 5\r
+      DBNull.Value, // 6\r
+      53,\r
+      53,\r
+      DBNull.Value,\r
+      5,\r
+      10,\r
+      19,\r
+      DBNull.Value,\r
+      3,\r
+      24,\r
+      DBNull.Value,\r
+      DBNull.Value,\r
+      5,\r
+      10,\r
+      19,\r
+      53,\r
+      DBNull.Value,\r
+      DBNull.Value,\r
+      DBNull.Value\r
+    };\r
+\r
+    internal static object DbTypeToNumericScale(DbType typ)\r
+    {\r
+      return _dbtypetonumericscale[(int)typ];\r
+    }\r
+\r
+    private static object[] _dbtypetonumericscale = {\r
+      DBNull.Value, // 0\r
+      DBNull.Value, // 1\r
+      0,\r
+      DBNull.Value,\r
+      4,\r
+      DBNull.Value, // 5\r
+      DBNull.Value, // 6\r
+      DBNull.Value,\r
+      DBNull.Value,\r
+      DBNull.Value,\r
+      0,\r
+      0,\r
+      0,\r
+      DBNull.Value,\r
+      0,\r
+      DBNull.Value,\r
+      DBNull.Value,\r
+      DBNull.Value,\r
+      0,\r
+      0,\r
+      0,\r
+      0,\r
+      DBNull.Value,\r
+      DBNull.Value,\r
+      DBNull.Value\r
+    };\r
+\r
+    internal static string DbTypeToTypeName(DbType typ)\r
+    {\r
+      for (int n = 0; n < _dbtypeNames.Length; n++)\r
+      {\r
+        if (_dbtypeNames[n].dataType == typ)\r
+          return _dbtypeNames[n].typeName;\r
+      }\r
+\r
+      return String.Empty;\r
+    }\r
+\r
+    private static SQLiteTypeNames[] _dbtypeNames = {\r
+      new SQLiteTypeNames("INTEGER", DbType.Int64),\r
+      new SQLiteTypeNames("TINYINT", DbType.Byte),\r
+      new SQLiteTypeNames("INT", DbType.Int32),\r
+      new SQLiteTypeNames("VARCHAR", DbType.AnsiString),\r
+      new SQLiteTypeNames("NVARCHAR", DbType.String),\r
+      new SQLiteTypeNames("CHAR", DbType.AnsiStringFixedLength),\r
+      new SQLiteTypeNames("NCHAR", DbType.StringFixedLength),\r
+      new SQLiteTypeNames("FLOAT", DbType.Double),\r
+      new SQLiteTypeNames("REAL", DbType.Single),          \r
+      new SQLiteTypeNames("BIT", DbType.Boolean),\r
+      new SQLiteTypeNames("DECIMAL", DbType.Decimal),\r
+      new SQLiteTypeNames("DATETIME", DbType.DateTime),\r
+      new SQLiteTypeNames("BLOB", DbType.Binary),\r
+      new SQLiteTypeNames("UNIQUEIDENTIFIER", DbType.Guid),\r
+      new SQLiteTypeNames("SMALLINT", DbType.Int16),\r
+    };\r
+    /// <summary>\r
+    /// Convert a DbType to a Type\r
+    /// </summary>\r
+    /// <param name="typ">The DbType to convert from</param>\r
+    /// <returns>The closest-match .NET type</returns>\r
+    internal static Type DbTypeToType(DbType typ)\r
+    {\r
+      return _dbtypeToType[(int)typ];\r
+    }\r
+\r
+    private static Type[] _dbtypeToType = {\r
+      typeof(string),   // 0\r
+      typeof(byte[]),   // 1\r
+      typeof(byte),     // 2\r
+      typeof(bool),     // 3\r
+      typeof(decimal),  // 4\r
+      typeof(DateTime), // 5\r
+      typeof(DateTime), // 6\r
+      typeof(decimal),  // 7\r
+      typeof(double),   // 8\r
+      typeof(Guid),     // 9\r
+      typeof(Int16),\r
+      typeof(Int32),\r
+      typeof(Int64),\r
+      typeof(object),\r
+      typeof(sbyte),\r
+      typeof(float),\r
+      typeof(string),\r
+      typeof(DateTime),\r
+      typeof(UInt16),\r
+      typeof(UInt32),\r
+      typeof(UInt64),\r
+      typeof(double),\r
+      typeof(string),\r
+      typeof(string),\r
+      typeof(string),\r
+      typeof(string),   // 25 (Xml)\r
+    };\r
+\r
+    /// <summary>\r
+    /// For a given type, return the closest-match SQLite TypeAffinity, which only understands a very limited subset of types.\r
+    /// </summary>\r
+    /// <param name="typ">The type to evaluate</param>\r
+    /// <returns>The SQLite type affinity for that type.</returns>\r
+    internal static TypeAffinity TypeToAffinity(Type typ)\r
+    {\r
+      TypeCode tc = Type.GetTypeCode(typ);\r
+      if (tc == TypeCode.Object)\r
+      {\r
+        if (typ == typeof(byte[]) || typ == typeof(Guid))\r
+          return TypeAffinity.Blob;\r
+        else\r
+          return TypeAffinity.Text;\r
+      }\r
+      return _typecodeAffinities[(int)tc];\r
+    }\r
+\r
+    private static TypeAffinity[] _typecodeAffinities = {\r
+      TypeAffinity.Null,\r
+      TypeAffinity.Blob,\r
+      TypeAffinity.Null,\r
+      TypeAffinity.Int64,\r
+      TypeAffinity.Int64,\r
+      TypeAffinity.Int64,\r
+      TypeAffinity.Int64,\r
+      TypeAffinity.Int64, // 7\r
+      TypeAffinity.Int64,\r
+      TypeAffinity.Int64,\r
+      TypeAffinity.Int64,\r
+      TypeAffinity.Int64, // 11\r
+      TypeAffinity.Int64,\r
+      TypeAffinity.Double,\r
+      TypeAffinity.Double,\r
+      TypeAffinity.Double,\r
+      TypeAffinity.DateTime,\r
+      TypeAffinity.Null,\r
+      TypeAffinity.Text,\r
+    };\r
+\r
+    /// <summary>\r
+    /// For a given type name, return a closest-match .NET type\r
+    /// </summary>\r
+    /// <param name="Name">The name of the type to match</param>\r
+    /// <returns>The .NET DBType the text evaluates to.</returns>\r
+    internal static DbType TypeNameToDbType(string Name)\r
+    {\r
+      if (String.IsNullOrEmpty(Name)) return DbType.Object;\r
+\r
+      int x = _typeNames.Length;\r
+      for (int n = 0; n < x; n++)\r
+      {\r
+        if (String.Compare(Name, _typeNames[n].typeName, true, CultureInfo.InvariantCulture) == 0)\r
+          return _typeNames[n].dataType; \r
+      }\r
+      return DbType.Object;\r
+    }\r
+    #endregion\r
+\r
+    private static SQLiteTypeNames[] _typeNames = {\r
+      new SQLiteTypeNames("COUNTER", DbType.Int64),\r
+      new SQLiteTypeNames("AUTOINCREMENT", DbType.Int64),\r
+      new SQLiteTypeNames("IDENTITY", DbType.Int64),\r
+      new SQLiteTypeNames("LONGTEXT", DbType.String),\r
+      new SQLiteTypeNames("LONGCHAR", DbType.String),\r
+      new SQLiteTypeNames("LONGVARCHAR", DbType.String),\r
+      new SQLiteTypeNames("LONG", DbType.Int64),\r
+      new SQLiteTypeNames("TINYINT", DbType.Byte),\r
+      new SQLiteTypeNames("INTEGER", DbType.Int64),\r
+      new SQLiteTypeNames("INT", DbType.Int32),\r
+      new SQLiteTypeNames("VARCHAR", DbType.String),\r
+      new SQLiteTypeNames("NVARCHAR", DbType.String),\r
+      new SQLiteTypeNames("CHAR", DbType.String),\r
+      new SQLiteTypeNames("NCHAR", DbType.String),\r
+      new SQLiteTypeNames("TEXT", DbType.String),\r
+      new SQLiteTypeNames("NTEXT", DbType.String),\r
+      new SQLiteTypeNames("STRING", DbType.String),\r
+      new SQLiteTypeNames("DOUBLE", DbType.Double),\r
+      new SQLiteTypeNames("FLOAT", DbType.Double),\r
+      new SQLiteTypeNames("REAL", DbType.Single),          \r
+      new SQLiteTypeNames("BIT", DbType.Boolean),\r
+      new SQLiteTypeNames("YESNO", DbType.Boolean),\r
+      new SQLiteTypeNames("LOGICAL", DbType.Boolean),\r
+      new SQLiteTypeNames("BOOL", DbType.Boolean),\r
+      new SQLiteTypeNames("BOOLEAN", DbType.Boolean),\r
+      new SQLiteTypeNames("NUMERIC", DbType.Decimal),\r
+      new SQLiteTypeNames("DECIMAL", DbType.Decimal),\r
+      new SQLiteTypeNames("MONEY", DbType.Decimal),\r
+      new SQLiteTypeNames("CURRENCY", DbType.Decimal),\r
+      new SQLiteTypeNames("TIME", DbType.DateTime),\r
+      new SQLiteTypeNames("DATE", DbType.DateTime),\r
+      new SQLiteTypeNames("SMALLDATE", DbType.DateTime),\r
+      new SQLiteTypeNames("BLOB", DbType.Binary),\r
+      new SQLiteTypeNames("BINARY", DbType.Binary),\r
+      new SQLiteTypeNames("VARBINARY", DbType.Binary),\r
+      new SQLiteTypeNames("IMAGE", DbType.Binary),\r
+      new SQLiteTypeNames("GENERAL", DbType.Binary),\r
+      new SQLiteTypeNames("OLEOBJECT", DbType.Binary),\r
+      new SQLiteTypeNames("GUID", DbType.Guid),\r
+      new SQLiteTypeNames("GUIDBLOB", DbType.Guid),\r
+      new SQLiteTypeNames("UNIQUEIDENTIFIER", DbType.Guid),\r
+      new SQLiteTypeNames("MEMO", DbType.String),\r
+      new SQLiteTypeNames("NOTE", DbType.String),\r
+      new SQLiteTypeNames("SMALLINT", DbType.Int16),\r
+      new SQLiteTypeNames("BIGINT", DbType.Int64),\r
+      new SQLiteTypeNames("TIMESTAMP", DbType.DateTime),\r
+      new SQLiteTypeNames("DATETIME", DbType.DateTime),\r
+    };\r
+  }\r
+\r
+  /// <summary>\r
+  /// SQLite has very limited types, and is inherently text-based.  The first 5 types below represent the sum of all types SQLite\r
+  /// understands.  The DateTime extension to the spec is for internal use only.\r
+  /// </summary>\r
+  public enum TypeAffinity\r
+  {\r
+    /// <summary>\r
+    /// Not used\r
+    /// </summary>\r
+    Uninitialized = 0,\r
+    /// <summary>\r
+    /// All integers in SQLite default to Int64\r
+    /// </summary>\r
+    Int64 = 1,\r
+    /// <summary>\r
+    /// All floating point numbers in SQLite default to double\r
+    /// </summary>\r
+    Double = 2,\r
+    /// <summary>\r
+    /// The default data type of SQLite is text\r
+    /// </summary>\r
+    Text = 3,\r
+    /// <summary>\r
+    /// Typically blob types are only seen when returned from a function\r
+    /// </summary>\r
+    Blob = 4,\r
+    /// <summary>\r
+    /// Null types can be returned from functions\r
+    /// </summary>\r
+    Null = 5,\r
+    /// <summary>\r
+    /// Used internally by this provider\r
+    /// </summary>\r
+    DateTime = 10,\r
+    /// <summary>\r
+    /// Used internally\r
+    /// </summary>\r
+    None = 11,\r
+  }\r
+\r
+  /// <summary>\r
+  /// This implementation of SQLite for ADO.NET can process date/time fields in databases in only one of three formats.  Ticks, ISO8601\r
+  /// and JulianDay.\r
+  /// </summary>\r
+  /// <remarks>\r
+  /// ISO8601 is more compatible, readable, fully-processable, but less accurate as it doesn't provide time down to fractions of a second.\r
+  /// JulianDay is the numeric format the SQLite uses internally and is arguably the most compatible with 3rd party tools.  It is\r
+  /// not readable as text without post-processing.\r
+  /// Ticks less compatible with 3rd party tools that query the database, and renders the DateTime field unreadable as text without post-processing.\r
+  /// \r
+  /// The preferred order of choosing a datetime format is JulianDay, ISO8601, and then Ticks.  Ticks is mainly present for legacy \r
+  /// code support.\r
+  /// </remarks>\r
+  public enum SQLiteDateFormats\r
+  {\r
+    /// <summary>\r
+    /// Using ticks is not recommended and is not well supported with LINQ.\r
+    /// </summary>\r
+    Ticks = 0,\r
+    /// <summary>\r
+    /// The default format for this provider.\r
+    /// </summary>\r
+    ISO8601 = 1,\r
+    /// <summary>\r
+    /// JulianDay format, which is what SQLite uses internally\r
+    /// </summary>\r
+    JulianDay = 2,\r
+    /// <summary>\r
+    /// The whole number of seconds since the Unix epoch (January 1, 1970).\r
+    /// </summary>\r
+    UnixEpoch = 3,\r
+  }\r
+\r
+  /// <summary>\r
+  /// This enum determines how SQLite treats its journal file.\r
+  /// </summary>\r
+  /// <remarks>\r
+  /// By default SQLite will create and delete the journal file when needed during a transaction.\r
+  /// However, for some computers running certain filesystem monitoring tools, the rapid\r
+  /// creation and deletion of the journal file can cause those programs to fail, or to interfere with SQLite.\r
+  /// \r
+  /// If a program or virus scanner is interfering with SQLite's journal file, you may receive errors like "unable to open database file"\r
+  /// when starting a transaction.  If this is happening, you may want to change the default journal mode to Persist.\r
+  /// </remarks>\r
+  public enum SQLiteJournalModeEnum\r
+  {\r
+    /// <summary>\r
+    /// The default mode, this causes SQLite to create and destroy the journal file as-needed.\r
+    /// </summary>\r
+    Delete = 0,\r
+    /// <summary>\r
+    /// When this is set, SQLite will keep the journal file even after a transaction has completed.  It's contents will be erased,\r
+    /// and the journal re-used as often as needed.  If it is deleted, it will be recreated the next time it is needed.\r
+    /// </summary>\r
+    Persist = 1,\r
+    /// <summary>\r
+    /// This option disables the rollback journal entirely.  Interrupted transactions or a program crash can cause database\r
+    /// corruption in this mode!\r
+    /// </summary>\r
+    Off = 2\r
+  }\r
+\r
+  /// <summary>\r
+  /// Struct used internally to determine the datatype of a column in a resultset\r
+  /// </summary>\r
+  internal class SQLiteType\r
+  {\r
+    /// <summary>\r
+    /// The DbType of the column, or DbType.Object if it cannot be determined\r
+    /// </summary>\r
+    internal DbType Type;\r
+    /// <summary>\r
+    /// The affinity of a column, used for expressions or when Type is DbType.Object\r
+    /// </summary>\r
+    internal TypeAffinity Affinity;\r
+  }\r
+\r
+  internal struct SQLiteTypeNames\r
+  {\r
+    internal SQLiteTypeNames(string newtypeName, DbType newdataType)\r
+    {\r
+      typeName = newtypeName;\r
+      dataType = newdataType;\r
+    }\r
+\r
+    internal string typeName;\r
+    internal DbType dataType;\r
+  }\r
+}\r