banshee r5007 - in trunk/banshee: . build build/pkg-config src/Libraries src/Libraries/Hyena/Hyena.Data.Sqlite src/Libraries/Mono.Data.Sqlite src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite



Author: gburt
Date: Wed Feb  4 04:24:49 2009
New Revision: 5007
URL: http://svn.gnome.org/viewvc/banshee?rev=5007&view=rev

Log:
2009-02-03  Gabriel Burt  <gabriel burt gmail com>

	* src/Libraries/Makefile.am:
	* src/Libraries/Mono.Data.Sqlite/Makefile.am:
	* src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/*: Add copy of
	Mono.Data.Sqlite from Mono svn (revision 120995), with a patch from John
	Millikin that fixes its support for custom functions.

	* src/Libraries/Mono.Data.Sqlite/bug-470042_mds-custom-functions_v2.patch:
	John's patch as applied to the M.D.S source.

	* build/build.environment.mk:
	* build/pkg-config/banshee-1-hyena.pc.in:
	* configure.ac:
	* src/Libraries/Hyena/Hyena.Data.Sqlite/HyenaSqliteArrayDataReader.cs:
	Adjust to build/work with the bundled Mono.Data.Sqlite

Added:
   trunk/banshee/src/Libraries/Mono.Data.Sqlite/
   trunk/banshee/src/Libraries/Mono.Data.Sqlite/Makefile.am
   trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/
   trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLite3.cs
   trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLite3_UTF16.cs
   trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteBase.cs
   trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteCommand.cs
   trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteCommandBuilder.cs
   trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteConnection.cs
   trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteConnectionStringBuilder.cs
   trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteConvert.cs
   trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteDataAdapter.cs
   trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteDataReader.cs
   trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteEnlistment.cs
   trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteException.cs
   trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteFactory.cs
   trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteFunction.cs
   trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteFunctionAttribute.cs
   trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteMetaDataCollectionNames.cs
   trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteParameter.cs
   trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteParameterCollection.cs
   trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteStatement.cs
   trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteTransaction.cs
   trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SR.Designer.cs
   trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SqliteDataSourceEnumerator.cs
   trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/UnsafeNativeMethods.cs
   trunk/banshee/src/Libraries/Mono.Data.Sqlite/bug-470042_mds-custom-functions_v2.patch
Modified:
   trunk/banshee/ChangeLog
   trunk/banshee/build/build.environment.mk
   trunk/banshee/build/pkg-config/banshee-1-hyena.pc.in
   trunk/banshee/configure.ac
   trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/HyenaSqliteArrayDataReader.cs
   trunk/banshee/src/Libraries/Makefile.am

Modified: trunk/banshee/build/build.environment.mk
==============================================================================
--- trunk/banshee/build/build.environment.mk	(original)
+++ trunk/banshee/build/build.environment.mk	Wed Feb  4 04:24:49 2009
@@ -10,7 +10,6 @@
 # External libraries to link against, generated from configure
 LINK_SYSTEM = -r:System
 LINK_SYSTEM_WEB = -r:System.Web
-LINK_SQLITE = -r:System.Data -r:Mono.Data.Sqlite
 LINK_CAIRO = -r:Mono.Cairo
 LINK_MONO_POSIX = -r:Mono.Posix
 LINK_ICSHARP_ZIP_LIB = -r:ICSharpCode.SharpZipLib
@@ -33,6 +32,10 @@
 
 DIR_BIN = $(top_builddir)/bin
 
+# Mono.Data
+REF_SQLITE = -r:System -r:System.Data -r:System.Transactions
+LINK_SQLITE = -r:System.Data -r:$(DIR_BIN)/Mono.Data.Sqlite.dll
+
 # Hyena
 REF_HYENA = $(LINK_SYSTEM) $(LINK_SQLITE) $(LINK_MONO_POSIX)
 LINK_HYENA = -r:$(DIR_BIN)/Hyena.dll

Modified: trunk/banshee/build/pkg-config/banshee-1-hyena.pc.in
==============================================================================
--- trunk/banshee/build/pkg-config/banshee-1-hyena.pc.in	(original)
+++ trunk/banshee/build/pkg-config/banshee-1-hyena.pc.in	Wed Feb  4 04:24:49 2009
@@ -6,5 +6,5 @@
 Name: Banshee Hyena
 Description: Hyena libraries for the Banshee Media Framework
 Version: @VERSION@
-Libs: -r:System -r:System.Data -r:Mono.Data.Sqlite -r:Mono.Posix -r:${bansheedir}/Hyena.dll
+Libs: -r:System -r:System.Data -r:${bansheedir}/Mono.Data.Sqlite -r:Mono.Posix -r:${bansheedir}/Hyena.dll
 

Modified: trunk/banshee/configure.ac
==============================================================================
--- trunk/banshee/configure.ac	(original)
+++ trunk/banshee/configure.ac	Wed Feb  4 04:24:49 2009
@@ -41,7 +41,6 @@
 	System.Web
 	System.Web.Services
 	Mono.Cairo
-	Mono.Data.Sqlite
 	Mono.Posix
 	ICSharpCode.SharpZipLib
 ])
@@ -214,6 +213,7 @@
 src/Libraries/Lastfm/Makefile
 src/Libraries/Lastfm.Gui/Makefile
 src/Libraries/Migo/Makefile
+src/Libraries/Mono.Data.Sqlite/Makefile
 src/Libraries/Mono.Media/Makefile
 src/Libraries/Mtp/Makefile
 src/Libraries/Mtp/Mtp.dll.config

Modified: trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/HyenaSqliteArrayDataReader.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/HyenaSqliteArrayDataReader.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/HyenaSqliteArrayDataReader.cs	Wed Feb  4 04:24:49 2009
@@ -320,7 +320,7 @@
             object value = GetValue (i);
             if (!(value is Guid)) {
                 if (value is DBNull)
-                    throw new SqliteExecutionException ("Column value must not be null");
+                    throw new SqliteException ("Column value must not be null");
                 throw new InvalidCastException ("Type is " + value.GetType ().ToString ());
             }
             return ((Guid) value);

Modified: trunk/banshee/src/Libraries/Makefile.am
==============================================================================
--- trunk/banshee/src/Libraries/Makefile.am	(original)
+++ trunk/banshee/src/Libraries/Makefile.am	Wed Feb  4 04:24:49 2009
@@ -1,4 +1,5 @@
 SUBDIRS = \
+   Mono.Data.Sqlite \
    Hyena \
    Hyena.Gui \
    Migo \

Added: trunk/banshee/src/Libraries/Mono.Data.Sqlite/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Mono.Data.Sqlite/Makefile.am	Wed Feb  4 04:24:49 2009
@@ -0,0 +1,32 @@
+ASSEMBLY = Mono.Data.Sqlite
+TARGET = library
+LINK = $(REF_SQLITE)
+ASSEMBLY_BUILD_FLAGS = -unsafe -d:MONO_BACKWARD_COMPAT
+
+SOURCES =  \
+	Mono.Data.Sqlite/SQLite3.cs \
+	Mono.Data.Sqlite/SQLite3_UTF16.cs \
+	Mono.Data.Sqlite/SQLiteBase.cs \
+	Mono.Data.Sqlite/SQLiteCommandBuilder.cs \
+	Mono.Data.Sqlite/SQLiteCommand.cs \
+	Mono.Data.Sqlite/SQLiteConnection.cs \
+	Mono.Data.Sqlite/SQLiteConnectionStringBuilder.cs \
+	Mono.Data.Sqlite/SQLiteConvert.cs \
+	Mono.Data.Sqlite/SQLiteDataAdapter.cs \
+	Mono.Data.Sqlite/SQLiteDataReader.cs \
+	Mono.Data.Sqlite/SqliteDataSourceEnumerator.cs \
+	Mono.Data.Sqlite/SQLiteEnlistment.cs \
+	Mono.Data.Sqlite/SQLiteException.cs \
+	Mono.Data.Sqlite/SQLiteFactory.cs \
+	Mono.Data.Sqlite/SQLiteFunctionAttribute.cs \
+	Mono.Data.Sqlite/SQLiteFunction.cs \
+	Mono.Data.Sqlite/SQLiteMetaDataCollectionNames.cs \
+	Mono.Data.Sqlite/SQLiteParameterCollection.cs \
+	Mono.Data.Sqlite/SQLiteParameter.cs \
+	Mono.Data.Sqlite/SQLiteStatement.cs \
+	Mono.Data.Sqlite/SQLiteTransaction.cs \
+	Mono.Data.Sqlite/SR.Designer.cs \
+	Mono.Data.Sqlite/UnsafeNativeMethods.cs
+
+include $(top_srcdir)/build/build.mk
+

Added: trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLite3.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLite3.cs	Wed Feb  4 04:24:49 2009
@@ -0,0 +1,674 @@
+//
+// Mono.Data.Sqlite.SQLite3.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.Globalization;
+
+  /// <summary>
+  /// This class implements SqliteBase completely, and is the guts of the code that interop's Sqlite with .NET
+  /// </summary>
+  internal class Sqlite3 : SqliteBase
+  {
+    /// <summary>
+    /// The opaque pointer returned to us by the sqlite provider
+    /// </summary>
+    protected IntPtr              _sql;
+    /// <summary>
+    /// The user-defined functions registered on this connection
+    /// </summary>
+    protected SqliteFunction[] _functionsArray;
+
+    internal Sqlite3(SqliteDateFormats fmt)
+      : base(fmt)
+    {
+    }
+
+    protected override void Dispose(bool bDisposing)
+    {
+      Close();
+    }
+
+    internal override void Close()
+    {
+      if (_sql != IntPtr.Zero)
+      {
+        int n = UnsafeNativeMethods.sqlite3_close(_sql);
+        if (n > 0) throw new SqliteException(n, SqliteLastError());
+      }
+      _sql = IntPtr.Zero;
+    }
+
+    internal override void Cancel()
+    {
+      UnsafeNativeMethods.sqlite3_interrupt(_sql);
+    }
+
+    internal override string Version
+    {
+      get
+      {
+	      return ToString (UnsafeNativeMethods.sqlite3_libversion());
+      }
+    }
+
+    internal override int Changes
+    {
+      get
+      {
+        return UnsafeNativeMethods.sqlite3_changes(_sql);
+      }
+    }
+
+    internal override void Open(string strFilename)
+    {
+      if (_sql != IntPtr.Zero) return;
+      int n = UnsafeNativeMethods.sqlite3_open(ToUTF8(strFilename), out _sql);
+      if (n > 0) throw new SqliteException(n, SqliteLastError());
+
+      _functionsArray = SqliteFunction.BindFunctions(this);
+    }
+
+    internal override void SetTimeout(int nTimeoutMS)
+    {
+      int n = UnsafeNativeMethods.sqlite3_busy_timeout(_sql, nTimeoutMS);
+      if (n > 0) throw new SqliteException(n, SqliteLastError());
+    }
+
+    internal override bool Step(SqliteStatement stmt)
+    {
+      int n;
+      long timeout = 0;
+      Random rnd = null;
+
+      while (true)
+      {
+        n = UnsafeNativeMethods.sqlite3_step(stmt._sqlite_stmt);
+
+        if (n == 100) return true;
+        if (n == 101) return false;
+
+        if (n > 0)
+        {
+          int r;
+
+          // An error occurred, attempt to reset the statement.  If the reset worked because the
+          // schema has changed, re-try the step again.  If it errored our because the database
+          // is locked, then keep retrying until the command timeout occurs.
+          r = Reset(stmt);
+
+          if (r == 0)
+            throw new SqliteException(n, SqliteLastError());
+
+          else if (r == 6 && stmt._command != null) // SQLITE_LOCKED
+          {
+            // Keep trying
+            if (timeout == 0) // First time we've encountered the lock
+            {
+              timeout = Environment.TickCount + (stmt._command._commandTimeout * 1000);
+              rnd = new Random();
+            }
+            // If we've exceeded the command's timeout, give up and throw an error
+            if (Environment.TickCount - timeout > 0)
+            {
+              throw new SqliteException(r, SqliteLastError());
+            }
+            else
+            {
+              // Otherwise sleep for a random amount of time up to 250ms
+              UnsafeNativeMethods.sqlite3_sleep((uint)rnd.Next(1, 250));
+            }
+          }
+
+        }
+      }
+    }
+
+    internal override void FinalizeStatement(SqliteStatement stmt)
+    {
+      if (stmt._sqlite_stmt != IntPtr.Zero)
+      {
+        int n = UnsafeNativeMethods.sqlite3_finalize(stmt._sqlite_stmt);
+        if (n > 0) throw new SqliteException(n, SqliteLastError());
+      }
+      stmt._sqlite_stmt = IntPtr.Zero;
+    }
+
+    internal override int Reset(SqliteStatement stmt)
+    {
+      int n;
+
+      n = UnsafeNativeMethods.sqlite3_reset(stmt._sqlite_stmt);
+
+      // If the schema changed, try and re-prepare it
+      if (n == 17) // SQLITE_SCHEMA
+      {
+        // Recreate a dummy statement
+        string str;
+        using (SqliteStatement tmp = Prepare(stmt._sqlStatement, null, out str))
+        {
+          // Finalize the existing statement
+          FinalizeStatement(stmt);
+
+          // Reassign a new statement pointer to the old statement and clear the temporary one
+          stmt._sqlite_stmt = tmp._sqlite_stmt;
+          tmp._sqlite_stmt = IntPtr.Zero;
+
+          // Reapply parameters
+          stmt.BindParameters();
+        }
+        return -1; // Reset was OK, with schema change
+      }
+      else if (n == 6) // SQLITE_LOCKED
+        return n;
+
+      if (n > 0)
+        throw new SqliteException(n, SqliteLastError());
+
+      return 0; // We reset OK, no schema changes
+    }
+
+    internal override string SqliteLastError()
+    {
+      return ToString(UnsafeNativeMethods.sqlite3_errmsg(_sql));
+    }
+
+    internal override SqliteStatement Prepare(string strSql, SqliteStatement previous, out string strRemain)
+    {
+      IntPtr stmt = IntPtr.Zero;
+      IntPtr ptr = IntPtr.Zero;
+      int n = 17;
+      int retries = 0;
+      byte[] b = ToUTF8(strSql);
+      string typedefs = null;
+      SqliteStatement cmd = null;
+      GCHandle handle = GCHandle.Alloc(b, GCHandleType.Pinned);
+      IntPtr psql = handle.AddrOfPinnedObject();
+
+      try
+      {
+        while (n == 17 && retries < 3)
+        {
+		try {
+			n = UnsafeNativeMethods.sqlite3_prepare_v2(_sql, psql, b.Length - 1, out stmt, out ptr);
+		} catch (EntryPointNotFoundException) {
+			n = UnsafeNativeMethods.sqlite3_prepare (_sql, psql, b.Length - 1, out stmt, out ptr);
+		}
+		
+          retries++;
+
+          if (n == 1)
+          {
+            if (String.Compare(SqliteLastError(), "near \"TYPES\": syntax error", StringComparison.OrdinalIgnoreCase) == 0)
+            {
+              int pos = strSql.IndexOf(';');
+              if (pos == -1) pos = strSql.Length - 1;
+
+              typedefs = strSql.Substring(0, pos + 1);
+              strSql = strSql.Substring(pos + 1);
+
+              strRemain = "";
+
+              while (cmd == null && strSql.Length > 0)
+              {
+                cmd = Prepare(strSql, previous, out strRemain);
+                strSql = strRemain;
+              }
+
+              if (cmd != null)
+                cmd.SetTypes(typedefs);
+
+              return cmd;
+            }
+          }
+        }
+
+        if (n > 0) throw new SqliteException(n, SqliteLastError());
+
+        strRemain = UTF8ToString(ptr);
+
+        if (stmt != IntPtr.Zero) cmd = new SqliteStatement(this, stmt, strSql.Substring(0, strSql.Length - strRemain.Length), previous);
+
+        return cmd;
+      }
+      finally
+      {
+        handle.Free();
+      }
+    }
+
+    internal override void Bind_Double(SqliteStatement stmt, int index, double value)
+    {
+      int n = UnsafeNativeMethods.sqlite3_bind_double(stmt._sqlite_stmt, index, value);
+      if (n > 0) throw new SqliteException(n, SqliteLastError());
+    }
+
+    internal override void Bind_Int32(SqliteStatement stmt, int index, int value)
+    {
+      int n = UnsafeNativeMethods.sqlite3_bind_int(stmt._sqlite_stmt, index, value);
+      if (n > 0) throw new SqliteException(n, SqliteLastError());
+    }
+
+    internal override void Bind_Int64(SqliteStatement stmt, int index, long value)
+    {
+      int n = UnsafeNativeMethods.sqlite3_bind_int64(stmt._sqlite_stmt, index, value);
+      if (n > 0) throw new SqliteException(n, SqliteLastError());
+    }
+
+    internal override void Bind_Text(SqliteStatement stmt, int index, string value)
+    {
+      byte[] b = ToUTF8(value);
+      int n = UnsafeNativeMethods.sqlite3_bind_text(stmt._sqlite_stmt, index, b, b.Length - 1, (IntPtr)(-1));
+      if (n > 0) throw new SqliteException(n, SqliteLastError());
+    }
+
+    internal override void Bind_DateTime(SqliteStatement stmt, int index, DateTime dt)
+    {
+      byte[] b = ToUTF8(dt);
+      int n = UnsafeNativeMethods.sqlite3_bind_text(stmt._sqlite_stmt, index, b, b.Length - 1, (IntPtr)(-1));
+      if (n > 0) throw new SqliteException(n, SqliteLastError());
+    }
+
+    internal override void Bind_Blob(SqliteStatement stmt, int index, byte[] blobData)
+    {
+      int n = UnsafeNativeMethods.sqlite3_bind_blob(stmt._sqlite_stmt, index, blobData, blobData.Length, (IntPtr)(-1));
+      if (n > 0) throw new SqliteException(n, SqliteLastError());
+    }
+
+    internal override void Bind_Null(SqliteStatement stmt, int index)
+    {
+      int n = UnsafeNativeMethods.sqlite3_bind_null(stmt._sqlite_stmt, index);
+      if (n > 0) throw new SqliteException(n, SqliteLastError());
+    }
+
+    internal override int Bind_ParamCount(SqliteStatement stmt)
+    {
+      return UnsafeNativeMethods.sqlite3_bind_parameter_count(stmt._sqlite_stmt);
+    }
+
+    internal override string Bind_ParamName(SqliteStatement stmt, int index)
+    {
+      return ToString(UnsafeNativeMethods.sqlite3_bind_parameter_name(stmt._sqlite_stmt, index));
+    }
+
+    internal override int Bind_ParamIndex(SqliteStatement stmt, string paramName)
+    {
+      return UnsafeNativeMethods.sqlite3_bind_parameter_index(stmt._sqlite_stmt, ToUTF8(paramName));
+    }
+
+    internal override int ColumnCount(SqliteStatement stmt)
+    {
+      return UnsafeNativeMethods.sqlite3_column_count(stmt._sqlite_stmt);
+    }
+
+    internal override string ColumnName(SqliteStatement stmt, int index)
+    {
+      return ToString(UnsafeNativeMethods.sqlite3_column_name(stmt._sqlite_stmt, index));
+    }
+
+    internal override TypeAffinity ColumnAffinity(SqliteStatement stmt, int index)
+    {
+      return UnsafeNativeMethods.sqlite3_column_type(stmt._sqlite_stmt, index);
+    }
+
+    internal override string ColumnType(SqliteStatement stmt, int index, out TypeAffinity nAffinity)
+    {
+      IntPtr p = UnsafeNativeMethods.sqlite3_column_decltype(stmt._sqlite_stmt, index);
+      nAffinity = ColumnAffinity(stmt, index);
+
+      if (p != IntPtr.Zero) return base.ToString(p);
+      else
+      {
+        string[] ar = stmt.TypeDefinitions;
+        if (ar != null)
+        {
+          if (index < ar.Length)
+            return ar[index];
+        }
+
+        switch (nAffinity)
+        {
+          case TypeAffinity.Int64:
+            return "BIGINT";
+          case TypeAffinity.Double:
+            return "DOUBLE";
+          case TypeAffinity.Blob:
+            return "BLOB";
+          default:
+            return "TEXT";
+        }
+      }
+    }
+
+    internal override int ColumnIndex(SqliteStatement stmt, string columnName)
+    {
+      int x = ColumnCount(stmt);
+
+      for (int n = 0; n < x; n++)
+      {
+        if (String.Compare(columnName, ColumnName(stmt, n), true, CultureInfo.InvariantCulture) == 0)
+          return n;
+      }
+      return -1;
+    }
+
+    internal override string ColumnOriginalName(SqliteStatement stmt, int index)
+    {
+      return ToString(UnsafeNativeMethods.sqlite3_column_origin_name(stmt._sqlite_stmt, index));
+    }
+
+    internal override string ColumnDatabaseName(SqliteStatement stmt, int index)
+    {
+      return ToString(UnsafeNativeMethods.sqlite3_column_database_name(stmt._sqlite_stmt, index));
+    }
+
+    internal override string ColumnTableName(SqliteStatement stmt, int index)
+    {
+      return ToString(UnsafeNativeMethods.sqlite3_column_table_name(stmt._sqlite_stmt, index));
+    }
+
+    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)
+    {
+      IntPtr dataTypePtr;
+      IntPtr collSeqPtr;
+      int nnotNull;
+      int nprimaryKey;
+      int nautoInc;
+      int n;
+
+      n = UnsafeNativeMethods.sqlite3_table_column_metadata(_sql, ToUTF8(dataBase), ToUTF8(table), ToUTF8(column),
+							    out dataTypePtr, out collSeqPtr, out nnotNull,
+							    out nprimaryKey, out nautoInc);
+      if (n > 0) throw new SqliteException(n, SqliteLastError());
+
+      dataType = base.ToString(dataTypePtr);
+      collateSequence = base.ToString(collSeqPtr);
+
+      notNull = (nnotNull == 1);
+      primaryKey = (nprimaryKey == 1);
+      autoIncrement = (nautoInc == 1);
+    }
+
+    internal override double GetDouble(SqliteStatement stmt, int index)
+    {
+      return UnsafeNativeMethods.sqlite3_column_double(stmt._sqlite_stmt, index);
+    }
+
+    internal override int GetInt32(SqliteStatement stmt, int index)
+    {
+      return UnsafeNativeMethods.sqlite3_column_int(stmt._sqlite_stmt, index);
+    }
+
+    internal override long GetInt64(SqliteStatement stmt, int index)
+    {
+      return UnsafeNativeMethods.sqlite3_column_int64(stmt._sqlite_stmt, index);
+    }
+
+    internal override string GetText(SqliteStatement stmt, int index)
+    {
+	    return ToString (UnsafeNativeMethods.sqlite3_column_text(stmt._sqlite_stmt, index));
+    }
+
+    internal override DateTime GetDateTime(SqliteStatement stmt, int index)
+    {
+	    return ToDateTime(GetText (stmt, index));
+    }
+
+    internal override long GetBytes(SqliteStatement stmt, int index, int nDataOffset, byte[] bDest, int nStart, int nLength)
+    {
+      IntPtr ptr;
+      int nlen;
+      int nCopied = nLength;
+
+      nlen = UnsafeNativeMethods.sqlite3_column_bytes(stmt._sqlite_stmt, index);
+      ptr = UnsafeNativeMethods.sqlite3_column_blob(stmt._sqlite_stmt, index);
+
+      if (bDest == null) return nlen;
+
+      if (nCopied + nStart > bDest.Length) nCopied = bDest.Length - nStart;
+      if (nCopied + nDataOffset > nlen) nCopied = nlen - nDataOffset;
+
+	  unsafe {
+		  if (nCopied > 0)
+			  Marshal.Copy((IntPtr)((byte*)ptr + nDataOffset), bDest, nStart, nCopied);
+		  else nCopied = 0;
+	  }
+
+      return nCopied;
+    }
+
+    internal override long GetChars(SqliteStatement stmt, int index, int nDataOffset, char[] bDest, int nStart, int nLength)
+    {
+      int nlen;
+      int nCopied = nLength;
+
+      string str = GetText(stmt, index);
+      nlen = str.Length;
+
+      if (bDest == null) return nlen;
+
+      if (nCopied + nStart > bDest.Length) nCopied = bDest.Length - nStart;
+      if (nCopied + nDataOffset > nlen) nCopied = nlen - nDataOffset;
+
+      if (nCopied > 0)
+        str.CopyTo(nDataOffset, bDest, nStart, nCopied);
+      else nCopied = 0;
+
+      return nCopied;
+    }
+
+    internal override bool IsNull(SqliteStatement stmt, int index)
+    {
+      return (ColumnAffinity(stmt, index) == TypeAffinity.Null);
+    }
+
+    internal override int AggregateCount(IntPtr context)
+    {
+      return UnsafeNativeMethods.sqlite3_aggregate_count(context);
+    }
+
+    internal override void CreateFunction(string strFunction, int nArgs, SqliteCallback func, SqliteCallback funcstep, SqliteFinalCallback funcfinal)
+    {
+      int n = UnsafeNativeMethods.sqlite3_create_function(_sql, ToUTF8(strFunction), nArgs, 1, IntPtr.Zero, func, funcstep, funcfinal);
+      if (n > 0) throw new SqliteException(n, SqliteLastError());
+    }
+
+    internal override void CreateCollation(string strCollation, SqliteCollation func)
+    {
+      int n = UnsafeNativeMethods.sqlite3_create_collation(_sql, ToUTF8(strCollation), 1, IntPtr.Zero, func);
+      if (n > 0) throw new SqliteException(n, SqliteLastError());
+    }
+
+    internal override long GetParamValueBytes(IntPtr p, int nDataOffset, byte[] bDest, int nStart, int nLength)
+    {
+      IntPtr ptr;
+      int nlen;
+      int nCopied = nLength;
+
+      nlen = UnsafeNativeMethods.sqlite3_value_bytes(p);
+      ptr = UnsafeNativeMethods.sqlite3_value_blob(p);
+
+      if (bDest == null) return nlen;
+
+      if (nCopied + nStart > bDest.Length) nCopied = bDest.Length - nStart;
+      if (nCopied + nDataOffset > nlen) nCopied = nlen - nDataOffset;
+
+	  unsafe {
+		  if (nCopied > 0)
+			  Marshal.Copy((IntPtr)((byte*)ptr + nDataOffset), bDest, nStart, nCopied);
+		  else nCopied = 0;
+	  }
+
+      return nCopied;
+    }
+
+    internal override double GetParamValueDouble(IntPtr ptr)
+    {
+      return UnsafeNativeMethods.sqlite3_value_double(ptr);
+    }
+
+    internal override int GetParamValueInt32(IntPtr ptr)
+    {
+      return UnsafeNativeMethods.sqlite3_value_int(ptr);
+    }
+
+    internal override long GetParamValueInt64(IntPtr ptr)
+    {
+      return UnsafeNativeMethods.sqlite3_value_int64(ptr);
+    }
+
+    internal override string GetParamValueText(IntPtr ptr)
+    {
+      return ToString(UnsafeNativeMethods.sqlite3_value_text(ptr));
+    }
+
+    internal override TypeAffinity GetParamValueType(IntPtr ptr)
+    {
+      return UnsafeNativeMethods.sqlite3_value_type(ptr);
+    }
+
+    internal override void ReturnBlob(IntPtr context, byte[] value)
+    {
+      UnsafeNativeMethods.sqlite3_result_blob(context, value, value.Length, (IntPtr)(-1));
+    }
+
+    internal override void ReturnDouble(IntPtr context, double value)
+    {
+      UnsafeNativeMethods.sqlite3_result_double(context, value);
+    }
+
+    internal override void ReturnError(IntPtr context, string value)
+    {
+      UnsafeNativeMethods.sqlite3_result_error(context, ToUTF8(value), value.Length);
+    }
+
+    internal override void ReturnInt32(IntPtr context, int value)
+    {
+      UnsafeNativeMethods.sqlite3_result_int(context, value);
+    }
+
+    internal override void ReturnInt64(IntPtr context, long value)
+    {
+      UnsafeNativeMethods.sqlite3_result_int64(context, value);
+    }
+
+    internal override void ReturnNull(IntPtr context)
+    {
+      UnsafeNativeMethods.sqlite3_result_null(context);
+    }
+
+    internal override void ReturnText(IntPtr context, string value)
+    {
+      byte[] b = ToUTF8(value);
+      UnsafeNativeMethods.sqlite3_result_text(context, ToUTF8(value), b.Length - 1, (IntPtr)(-1));
+    }
+
+    internal override IntPtr AggregateContext(IntPtr context)
+    {
+      return UnsafeNativeMethods.sqlite3_aggregate_context(context, 1);
+    }
+
+    internal override void SetUpdateHook(SqliteUpdateCallback func)
+    {
+      UnsafeNativeMethods.sqlite3_update_hook(_sql, func);
+    }
+
+    internal override void SetCommitHook(SqliteCommitCallback func)
+    {
+      UnsafeNativeMethods.sqlite3_commit_hook(_sql, func);
+    }
+
+    internal override void SetRollbackHook(SqliteRollbackCallback func)
+    {
+      UnsafeNativeMethods.sqlite3_rollback_hook(_sql, func);
+    }
+
+    /// <summary>
+    /// Helper function to retrieve a column of data from an active statement.
+    /// </summary>
+    /// <param name="stmt">The statement being step()'d through</param>
+    /// <param name="index">The column index to retrieve</param>
+    /// <param name="typ">The type of data contained in the column.  If Uninitialized, this function will retrieve the datatype information.</param>
+    /// <returns>Returns the data in the column</returns>
+    internal override object GetValue(SqliteStatement stmt, int index, ref SqliteType typ)
+    {
+      if (typ.Affinity == 0) typ = SqliteConvert.ColumnToType(stmt, index);
+      if (IsNull(stmt, index)) return DBNull.Value;
+
+      Type t = SqliteConvert.SqliteTypeToType(typ);
+
+      switch (TypeToAffinity(t))
+      {
+        case TypeAffinity.Blob:
+          if (typ.Type == DbType.Guid && typ.Affinity == TypeAffinity.Text)
+            return new Guid(GetText(stmt, index));
+
+          int n = (int)GetBytes(stmt, index, 0, null, 0, 0);
+          byte[] b = new byte[n];
+          GetBytes(stmt, index, 0, b, 0, n);
+
+          if (typ.Type == DbType.Guid && n == 16)
+            return new Guid(b);
+
+          return b;
+        case TypeAffinity.DateTime:
+          return GetDateTime(stmt, index);
+        case TypeAffinity.Double:
+          return Convert.ChangeType(GetDouble(stmt, index), t, null);
+        case TypeAffinity.Int64:
+          return Convert.ChangeType(GetInt64(stmt, index), t, null);
+        default:
+          return GetText(stmt, index);
+      }
+    }
+
+    internal override int GetLastInsertRowId ()
+    {
+	    return UnsafeNativeMethods.sqlite3_last_insert_rowid (_sql);
+    }
+  }
+}
+#endif

Added: trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLite3_UTF16.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLite3_UTF16.cs	Wed Feb  4 04:24:49 2009
@@ -0,0 +1,162 @@
+//
+// Mono.Data.Sqlite.SQLite3_UTF16.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.Runtime.InteropServices;
+
+  /// <summary>
+  /// Alternate Sqlite3 object, overriding many text behaviors to support UTF-16 (Unicode)
+  /// </summary>
+  internal class Sqlite3_UTF16 : Sqlite3
+  {
+    internal Sqlite3_UTF16(SqliteDateFormats fmt)
+      : base(fmt)
+    {
+    }
+
+    /// <summary>
+    /// Overrides SqliteConvert.ToString() to marshal UTF-16 strings instead of UTF-8
+    /// </summary>
+    /// <param name="b">A pointer to a UTF-16 string</param>
+    /// <param name="nbytelen">The length (IN BYTES) of the string</param>
+    /// <returns>A .NET string</returns>
+    public override string ToString(IntPtr b)
+    {
+      return Marshal.PtrToStringUni(b);
+    }
+
+    internal override string Version
+    {
+      get
+      {
+        return base.ToString(UnsafeNativeMethods.sqlite3_libversion());
+      }
+    }
+
+    internal override void Open(string strFilename)
+    {
+      if (_sql != IntPtr.Zero) return;
+      int n = UnsafeNativeMethods.sqlite3_open16(strFilename, out _sql);
+      if (n > 0) throw new SqliteException(n, SqliteLastError());
+
+      _functionsArray = SqliteFunction.BindFunctions(this);
+    }
+
+    internal override string SqliteLastError()
+    {
+      return ToString(UnsafeNativeMethods.sqlite3_errmsg16(_sql));
+    }
+
+    internal override void Bind_DateTime(SqliteStatement stmt, int index, DateTime dt)
+    {
+      Bind_Text(stmt, index, ToString(dt));
+    }
+
+    internal override string Bind_ParamName(SqliteStatement stmt, int index)
+    {
+      return base.ToString(UnsafeNativeMethods.sqlite3_bind_parameter_name(stmt._sqlite_stmt, index));
+    }
+
+    internal override void Bind_Text(SqliteStatement stmt, int index, string value)
+    {
+      int n = UnsafeNativeMethods.sqlite3_bind_text16(stmt._sqlite_stmt, index, value, value.Length * 2, -1);
+      if (n > 0) throw new SqliteException(n, SqliteLastError());
+    }
+
+    internal override string ColumnName(SqliteStatement stmt, int index)
+    {
+      return ToString(UnsafeNativeMethods.sqlite3_column_name16(stmt._sqlite_stmt, index));
+    }
+
+    internal override DateTime GetDateTime(SqliteStatement stmt, int index)
+    {
+      return ToDateTime(GetText(stmt, index));
+    }
+    internal override string GetText(SqliteStatement stmt, int index)
+    {
+	    return ToString (UnsafeNativeMethods.sqlite3_column_text16(stmt._sqlite_stmt, index));
+    }
+
+    internal override string ColumnOriginalName(SqliteStatement stmt, int index)
+    {
+      return ToString(UnsafeNativeMethods.sqlite3_column_origin_name16(stmt._sqlite_stmt, index));
+    }
+
+    internal override string ColumnDatabaseName(SqliteStatement stmt, int index)
+    {
+      return ToString(UnsafeNativeMethods.sqlite3_column_database_name16(stmt._sqlite_stmt, index));
+    }
+
+    internal override string ColumnTableName(SqliteStatement stmt, int index)
+    {
+      return ToString(UnsafeNativeMethods.sqlite3_column_table_name16(stmt._sqlite_stmt, index));
+    }
+
+    internal override void CreateFunction(string strFunction, int nArgs, SqliteCallback func, SqliteCallback funcstep, SqliteFinalCallback funcfinal)
+    {
+      int n = UnsafeNativeMethods.sqlite3_create_function16(_sql, strFunction, nArgs, 4, IntPtr.Zero, func, funcstep, funcfinal);
+      if (n > 0) throw new SqliteException(n, SqliteLastError());
+    }
+
+    internal override void CreateCollation(string strCollation, SqliteCollation func)
+    {
+      int n = UnsafeNativeMethods.sqlite3_create_collation16(_sql, strCollation, 4, IntPtr.Zero, func);
+      if (n > 0) throw new SqliteException(n, SqliteLastError());
+    }
+
+    internal override string GetParamValueText(IntPtr ptr)
+    {
+      return ToString(UnsafeNativeMethods.sqlite3_value_text16(ptr));
+    }
+
+    internal override void ReturnError(IntPtr context, string value)
+    {
+      UnsafeNativeMethods.sqlite3_result_error16(context, value, value.Length);
+    }
+
+    internal override void ReturnText(IntPtr context, string value)
+    {
+      UnsafeNativeMethods.sqlite3_result_text16(context, value, value.Length, (IntPtr)(-1));
+    }
+  }
+}
+#endif

Added: trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteBase.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteBase.cs	Wed Feb  4 04:24:49 2009
@@ -0,0 +1,195 @@
+//
+// Mono.Data.Sqlite.SQLiteBase.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;
+
+  /// <summary>
+  /// This internal class provides the foundation of Sqlite support.  It defines all the abstract members needed to implement
+  /// a Sqlite data provider, and inherits from SqliteConvert which allows for simple translations of string to and from Sqlite.
+  /// </summary>
+  internal abstract class SqliteBase : SqliteConvert, IDisposable
+  {
+    internal SqliteBase(SqliteDateFormats fmt)
+      : base(fmt) {}
+
+    /// <summary>
+    /// Returns a string representing the active version of Sqlite
+    /// </summary>
+    internal abstract string Version { get; }
+    /// <summary>
+    /// Returns the number of changes the last executing insert/update caused.
+    /// </summary>
+    internal abstract int    Changes { get; }
+    /// <summary>
+    /// Opens a database.
+    /// </summary>
+    /// <remarks>
+    /// Implementers should call SqliteFunction.BindFunctions() and save the array after opening a connection
+    /// to bind all attributed user-defined functions and collating sequences to the new connection.
+    /// </remarks>
+    /// <param name="strFilename">The filename of the database to open.  Sqlite automatically creates it if it doesn't exist.</param>
+    internal abstract void   Open(string strFilename);
+    /// <summary>
+    /// Closes the currently-open database.
+    /// </summary>
+    /// <remarks>
+    /// After the database has been closed implemeters should call SqliteFunction.UnbindFunctions() to deallocate all interop allocated
+    /// memory associated with the user-defined functions and collating sequences tied to the closed connection.
+    /// </remarks>
+    internal abstract void   Close();
+    /// <summary>
+    /// Sets the busy timeout on the connection.  SqliteCommand will call this before executing any command.
+    /// </summary>
+    /// <param name="nTimeoutMS">The number of milliseconds to wait before returning SQLITE_BUSY</param>
+    internal abstract void   SetTimeout(int nTimeoutMS);
+    /// <summary>
+    /// Returns the text of the last error issued by Sqlite
+    /// </summary>
+    /// <returns></returns>
+    internal abstract string SqliteLastError();
+
+    /// <summary>
+    /// Prepares a SQL statement for execution.
+    /// </summary>
+    /// <param name="strSql">The SQL command text to prepare</param>
+    /// <param name="previous">The previous statement in a multi-statement command, or null if no previous statement exists</param>
+    /// <param name="strRemain">The remainder of the statement that was not processed.  Each call to prepare parses the
+    /// SQL up to to either the end of the text or to the first semi-colon delimiter.  The remaining text is returned
+    /// here for a subsequent call to Prepare() until all the text has been processed.</param>
+    /// <returns>Returns an initialized SqliteStatement.</returns>
+    internal abstract SqliteStatement Prepare(string strSql, SqliteStatement previous, out string strRemain);
+    /// <summary>
+    /// Steps through a prepared statement.
+    /// </summary>
+    /// <param name="stmt">The SqliteStatement to step through</param>
+    /// <returns>True if a row was returned, False if not.</returns>
+    internal abstract bool Step(SqliteStatement stmt);
+    /// <summary>
+    /// Finalizes a prepared statement.
+    /// </summary>
+    /// <param name="stmt">The statement to finalize</param>
+    internal abstract void FinalizeStatement(SqliteStatement stmt);
+    /// <summary>
+    /// Resets a prepared statement so it can be executed again.  If the error returned is SQLITE_SCHEMA, 
+    /// transparently attempt to rebuild the SQL statement and throw an error if that was not possible.
+    /// </summary>
+    /// <param name="stmt">The statement to reset</param>
+    /// <returns>Returns -1 if the schema changed while resetting, 0 if the reset was sucessful or 6 (SQLITE_LOCKED) if the reset failed due to a lock</returns>
+    internal abstract int Reset(SqliteStatement stmt);
+
+    internal abstract void Cancel();
+
+    internal abstract void Bind_Double(SqliteStatement stmt, int index, double value);
+    internal abstract void Bind_Int32(SqliteStatement stmt, int index, Int32 value);
+    internal abstract void Bind_Int64(SqliteStatement stmt, int index, Int64 value);
+    internal abstract void Bind_Text(SqliteStatement stmt, int index, string value);
+    internal abstract void Bind_Blob(SqliteStatement stmt, int index, byte[] blobData);
+    internal abstract void Bind_DateTime(SqliteStatement stmt, int index, DateTime dt);
+    internal abstract void Bind_Null(SqliteStatement stmt, int index);
+
+    internal abstract int    Bind_ParamCount(SqliteStatement stmt);
+    internal abstract string Bind_ParamName(SqliteStatement stmt, int index);
+    internal abstract int    Bind_ParamIndex(SqliteStatement stmt, string paramName);
+
+    internal abstract int    ColumnCount(SqliteStatement stmt);
+    internal abstract string ColumnName(SqliteStatement stmt, int index);
+    internal abstract TypeAffinity ColumnAffinity(SqliteStatement stmt, int index);
+    internal abstract string ColumnType(SqliteStatement stmt, int index, out TypeAffinity nAffinity);
+    internal abstract int    ColumnIndex(SqliteStatement stmt, string columnName);
+    internal abstract string ColumnOriginalName(SqliteStatement stmt, int index);
+    internal abstract string ColumnDatabaseName(SqliteStatement stmt, int index);
+    internal abstract string ColumnTableName(SqliteStatement stmt, int index);
+    internal abstract void ColumnMetaData(string dataBase, string table, string column, out string dataType, out string collateSequence, out bool notNull, out bool primaryKey, out bool autoIncrement);
+
+    internal abstract double   GetDouble(SqliteStatement stmt, int index);
+    internal abstract Int32    GetInt32(SqliteStatement stmt, int index);
+    internal abstract Int64    GetInt64(SqliteStatement stmt, int index);
+    internal abstract string   GetText(SqliteStatement stmt, int index);
+    internal abstract long     GetBytes(SqliteStatement stmt, int index, int nDataoffset, byte[] bDest, int nStart, int nLength);
+    internal abstract long     GetChars(SqliteStatement stmt, int index, int nDataoffset, char[] bDest, int nStart, int nLength);
+    internal abstract DateTime GetDateTime(SqliteStatement stmt, int index);
+    internal abstract bool     IsNull(SqliteStatement stmt, int index);
+
+    internal abstract void  CreateCollation(string strCollation, SqliteCollation func);
+    internal abstract void  CreateFunction(string strFunction, int nArgs, SqliteCallback func, SqliteCallback funcstep, SqliteFinalCallback funcfinal);
+
+    internal abstract int AggregateCount(IntPtr context);
+    internal abstract IntPtr AggregateContext(IntPtr context);
+
+    internal abstract long   GetParamValueBytes(IntPtr ptr, int nDataOffset, byte[] bDest, int nStart, int nLength);
+    internal abstract double GetParamValueDouble(IntPtr ptr);
+    internal abstract int    GetParamValueInt32(IntPtr ptr);
+    internal abstract Int64  GetParamValueInt64(IntPtr ptr);
+    internal abstract string GetParamValueText(IntPtr ptr);
+    internal abstract TypeAffinity GetParamValueType(IntPtr ptr);
+
+    internal abstract void ReturnBlob(IntPtr context, byte[] value);
+    internal abstract void ReturnDouble(IntPtr context, double value);
+    internal abstract void ReturnError(IntPtr context, string value);
+    internal abstract void ReturnInt32(IntPtr context, Int32 value);
+    internal abstract void ReturnInt64(IntPtr context, Int64 value);
+    internal abstract void ReturnNull(IntPtr context);
+    internal abstract void ReturnText(IntPtr context, string value);
+
+    internal abstract void SetUpdateHook(SqliteUpdateCallback func);
+    internal abstract void SetCommitHook(SqliteCommitCallback func);
+    internal abstract void SetRollbackHook(SqliteRollbackCallback func);
+
+    internal abstract int GetLastInsertRowId ();
+    
+    internal abstract object GetValue(SqliteStatement stmt, int index, ref SqliteType typ);
+
+    protected virtual void Dispose(bool bDisposing)
+    {
+    }
+
+    public void Dispose()
+    {
+      Dispose(true);
+      GC.SuppressFinalize(this);
+    }
+  }
+}
+#endif

Added: trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteCommand.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteCommand.cs	Wed Feb  4 04:24:49 2009
@@ -0,0 +1,657 @@
+//
+// Mono.Data.Sqlite.SQLiteCommand.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.Data.Common;
+  using System.Collections.Generic;
+  using System.ComponentModel;
+
+  /// <summary>
+  /// Sqlite implementation of DbCommand.
+  /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+  [Designer("Sqlite.Designer.SqliteCommandDesigner, Sqlite.Designer, Version=1.0.31.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139"), ToolboxItem(true)]
+#endif
+  public sealed class SqliteCommand : DbCommand, ICloneable
+  {
+    /// <summary>
+    /// The command text this command is based on
+    /// </summary>
+    private string _commandText;
+    /// <summary>
+    /// The connection the command is associated with
+    /// </summary>
+    private SqliteConnection _cnn;
+    /// <summary>
+    /// Indicates whether or not a DataReader is active on the command.
+    /// </summary>
+    private SqliteDataReader _activeReader;
+    /// <summary>
+    /// The timeout for the command, kludged because Sqlite doesn't support per-command timeout values
+    /// </summary>
+    internal int _commandTimeout;
+    /// <summary>
+    /// Designer support
+    /// </summary>
+    private bool _designTimeVisible;
+    /// <summary>
+    /// Used by DbDataAdapter to determine updating behavior
+    /// </summary>
+    private UpdateRowSource _updateRowSource;
+    /// <summary>
+    /// The collection of parameters for the command
+    /// </summary>
+    private SqliteParameterCollection _parameterCollection;
+    /// <summary>
+    /// The SQL command text, broken into individual SQL statements as they are executed
+    /// </summary>
+    internal List<SqliteStatement> _statementList;
+    /// <summary>
+    /// Unprocessed SQL text that has not been executed
+    /// </summary>
+    internal string _remainingText;
+    /// <summary>
+    /// Transaction associated with this command
+    /// </summary>
+    private SqliteTransaction _transaction;
+
+    ///<overloads>
+    /// Constructs a new SqliteCommand
+    /// </overloads>
+    /// <summary>
+    /// Default constructor
+    /// </summary>
+    public SqliteCommand() :this(null, null)
+    {
+    }
+
+    /// <summary>
+    /// Initializes the command with the given command text
+    /// </summary>
+    /// <param name="commandText">The SQL command text</param>
+    public SqliteCommand(string commandText) 
+      : this(commandText, null, null)
+    {
+    }
+
+    /// <summary>
+    /// Initializes the command with the given SQL command text and attach the command to the specified
+    /// connection.
+    /// </summary>
+    /// <param name="commandText">The SQL command text</param>
+    /// <param name="connection">The connection to associate with the command</param>
+    public SqliteCommand(string commandText, SqliteConnection connection)
+      : this(commandText, connection, null)
+    {
+    }
+
+    /// <summary>
+    /// Initializes the command and associates it with the specified connection.
+    /// </summary>
+    /// <param name="connection">The connection to associate with the command</param>
+    public SqliteCommand(SqliteConnection connection) 
+      : this(null, connection, null)
+    {
+    }
+
+    private SqliteCommand(SqliteCommand source) : this(source.CommandText, source.Connection, source.Transaction)
+    {
+      CommandTimeout = source.CommandTimeout;
+      DesignTimeVisible = source.DesignTimeVisible;
+      UpdatedRowSource = source.UpdatedRowSource;
+
+      foreach (SqliteParameter param in source._parameterCollection)
+      {
+        Parameters.Add(param.Clone());
+      }
+    }
+
+    /// <summary>
+    /// Initializes a command with the given SQL, connection and transaction
+    /// </summary>
+    /// <param name="commandText">The SQL command text</param>
+    /// <param name="connection">The connection to associate with the command</param>
+    /// <param name="transaction">The transaction the command should be associated with</param>
+    public SqliteCommand(string commandText, SqliteConnection connection, SqliteTransaction transaction)
+    {
+      _statementList = null;
+      _activeReader = null;
+      _commandTimeout = connection != null ? connection._busyTimeout : 30;
+      _parameterCollection = new SqliteParameterCollection(this);
+      _designTimeVisible = true;
+      _updateRowSource = UpdateRowSource.FirstReturnedRecord;
+      _transaction = null;
+
+      if (commandText != null)
+        CommandText = commandText;
+
+      if (connection != null)
+        DbConnection = connection;
+
+      if (transaction != null)
+        Transaction = transaction;
+    }
+
+    /// <summary>
+    /// Disposes of the command and clears all member variables
+    /// </summary>
+    /// <param name="disposing">Whether or not the class is being explicitly or implicitly disposed</param>
+    protected override void Dispose(bool disposing)
+    {
+      base.Dispose(disposing);
+
+      // If a reader is active on this command, don't destroy it completely
+      if (_activeReader != null)
+      {
+        _activeReader._disposeCommand = true;
+        return;
+      }
+
+      Connection = null;
+      _parameterCollection.Clear();
+      _commandText = null;
+    }
+
+    /// <summary>
+    /// Clears and destroys all statements currently prepared
+    /// </summary>
+    internal void ClearCommands()
+    {
+      if (_activeReader != null)
+        _activeReader.Close();
+
+      if (_statementList == null) return;
+
+      int x = _statementList.Count;
+      for (int n = 0; n < x; n++)
+        _statementList[n].Dispose();
+
+      _statementList = null;
+
+      _parameterCollection.Unbind();
+    }
+
+    /// <summary>
+    /// Builds an array of prepared statements for each complete SQL statement in the command text
+    /// </summary>
+    internal SqliteStatement BuildNextCommand()
+    {
+      SqliteStatement stmt = null;
+
+      try
+      {
+        if (_statementList == null)
+          _remainingText = _commandText;
+
+        stmt = _cnn._sql.Prepare(_remainingText, (_statementList == null) ? null : _statementList[_statementList.Count - 1], out _remainingText);
+        if (stmt != null)
+        {
+          stmt._command = this;
+          if (_statementList == null)
+            _statementList = new List<SqliteStatement>();
+
+          _statementList.Add(stmt);
+
+          _parameterCollection.MapParameters(stmt);
+          stmt.BindParameters();
+        }        
+        return stmt;
+      }
+      catch (Exception)
+      {
+        if (stmt != null)
+        {
+          if (_statementList.Contains(stmt))
+            _statementList.Remove(stmt);
+
+          stmt.Dispose();
+        }
+
+        // If we threw an error compiling the statement, we cannot continue on so set the remaining text to null.
+        _remainingText = null;
+
+        throw;
+      }
+    }
+
+    internal SqliteStatement GetStatement(int index)
+    {
+      // Haven't built any statements yet
+      if (_statementList == null) return BuildNextCommand();
+
+      // If we're at the last built statement and want the next unbuilt statement, then build it
+      if (index == _statementList.Count)
+      {
+        if (String.IsNullOrEmpty(_remainingText) == false) return BuildNextCommand();
+        else return null; // No more commands
+      }
+
+      SqliteStatement stmt = _statementList[index];
+      stmt.BindParameters();
+
+      return stmt;
+    }
+
+    /// <summary>
+    /// Not implemented
+    /// </summary>
+    public override void Cancel()
+    {
+    }
+
+    /// <summary>
+    /// The SQL command text associated with the command
+    /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+    [DefaultValue(""), RefreshProperties(RefreshProperties.All), Editor("Microsoft.VSDesigner.Data.SQL.Design.SqlCommandTextEditor, Microsoft.VSDesigner, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Drawing.Design.UITypeEditor, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
+#endif
+    public override string CommandText
+    {
+      get
+      {
+        return _commandText;
+      }
+      set
+      {
+        if (_commandText == value) return;
+
+        if (_activeReader != null)
+        {
+          throw new InvalidOperationException("Cannot set CommandText while a DataReader is active");
+        }
+
+        ClearCommands();
+        _commandText = value;
+
+        if (_cnn == null) return;
+      }
+    }
+
+    /// <summary>
+    /// The amount of time to wait for the connection to become available before erroring out
+    /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+    [DefaultValue((int)30)]
+#endif
+    public override int CommandTimeout
+    {
+      get
+      {
+        return _commandTimeout;
+      }
+      set
+      {
+        _commandTimeout = value;
+      }
+    }
+
+    /// <summary>
+    /// The type of the command.  Sqlite only supports CommandType.Text
+    /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+    [RefreshProperties(RefreshProperties.All), DefaultValue(CommandType.Text)]
+#endif
+    public override CommandType CommandType
+    {
+      get
+      {
+        return CommandType.Text;
+      }
+      set
+      {
+        if (value != CommandType.Text)
+        {
+          throw new NotSupportedException();
+        }
+      }
+    }
+
+    /// <summary>
+    /// Forwards to the local CreateParameter() function
+    /// </summary>
+    /// <returns></returns>
+    protected override DbParameter CreateDbParameter()
+    {
+      return CreateParameter();
+    }
+
+    /// <summary>
+    /// Create a new parameter
+    /// </summary>
+    /// <returns></returns>
+    public new SqliteParameter CreateParameter()
+    {
+      return new SqliteParameter();
+    }
+
+    /// <summary>
+    /// The connection associated with this command
+    /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+    [DefaultValue((string)null), Editor("Microsoft.VSDesigner.Data.Design.DbConnectionEditor, Microsoft.VSDesigner, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Drawing.Design.UITypeEditor, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
+#endif
+    public new SqliteConnection Connection
+    {
+      get { return _cnn; }
+      set
+      {
+        if (_activeReader != null)
+          throw new InvalidOperationException("Cannot set Connection while a DataReader is active");
+
+        if (_cnn != null)
+        {
+          ClearCommands();
+          _cnn.RemoveCommand(this);
+        }
+
+        _cnn = value;
+
+        if (_cnn != null)
+          _cnn.AddCommand(this);
+      }
+    }
+
+    /// <summary>
+    /// Forwards to the local Connection property
+    /// </summary>
+    protected override DbConnection DbConnection
+    {
+      get
+      {
+        return Connection;
+      }
+      set
+      {
+        Connection = (SqliteConnection)value;
+      }
+    }
+
+    /// <summary>
+    /// Returns the SqliteParameterCollection for the given command
+    /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
+#endif
+    public new SqliteParameterCollection Parameters
+    {
+      get { return _parameterCollection; }
+    }
+
+    /// <summary>
+    /// Forwards to the local Parameters property
+    /// </summary>
+    protected override DbParameterCollection DbParameterCollection
+    {
+      get
+      {
+        return Parameters;
+      }
+    }
+
+    /// <summary>
+    /// The transaction associated with this command.  Sqlite only supports one transaction per connection, so this property forwards to the
+    /// command's underlying connection.
+    /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+    [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+#endif
+    public new SqliteTransaction Transaction
+    {
+      get { return _transaction; }
+      set
+      {
+        if (_cnn != null)
+        {
+          if (_activeReader != null)
+            throw new InvalidOperationException("Cannot set Transaction while a DataReader is active");
+
+          if (value != null)
+          {
+            if (value._cnn != _cnn)
+              throw new ArgumentException("Transaction is not associated with the command's connection");
+          }
+          _transaction = value;
+        }
+        else if (value != null)
+          throw new ArgumentOutOfRangeException("SqliteTransaction", "Not associated with a connection");
+      }
+    }
+
+    /// <summary>
+    /// Forwards to the local Transaction property
+    /// </summary>
+    protected override DbTransaction DbTransaction
+    {
+      get
+      {
+        return Transaction;
+      }
+      set
+      {
+        Transaction = (SqliteTransaction)value;
+      }
+    }
+
+    /// <summary>
+    /// This function ensures there are no active readers, that we have a valid connection,
+    /// that the connection is open, that all statements are prepared and all parameters are assigned
+    /// in preparation for allocating a data reader.
+    /// </summary>
+    private void InitializeForReader()
+    {
+      if (_activeReader != null)
+        throw new InvalidOperationException("DataReader already active on this command");
+
+      if (_cnn == null)
+        throw new InvalidOperationException("No connection associated with this command");
+
+      if (_cnn.State != ConnectionState.Open)
+        throw new InvalidOperationException("Database is not open");
+
+      // Map all parameters for statements already built
+      _parameterCollection.MapParameters(null);
+
+      // Set the default command timeout
+      _cnn._sql.SetTimeout(_commandTimeout * 1000);
+    }
+
+    /// <summary>
+    /// Creates a new SqliteDataReader to execute/iterate the array of Sqlite prepared statements
+    /// </summary>
+    /// <param name="behavior">The behavior the data reader should adopt</param>
+    /// <returns>Returns a SqliteDataReader object</returns>
+    protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior)
+    {
+      return ExecuteReader(behavior);
+    }
+
+    /// <summary>
+    /// Overrides the default behavior to return a SqliteDataReader specialization class
+    /// </summary>
+    /// <param name="behavior">The flags to be associated with the reader</param>
+    /// <returns>A SqliteDataReader</returns>
+    public new SqliteDataReader ExecuteReader(CommandBehavior behavior)
+    {
+      InitializeForReader();
+
+      SqliteDataReader rd = new SqliteDataReader(this, behavior);
+      _activeReader = rd;
+
+      return rd;
+    }
+
+    /// <summary>
+    /// Overrides the default behavior of DbDataReader to return a specialized SqliteDataReader class
+    /// </summary>
+    /// <returns>A SqliteDataReader</returns>
+    public new SqliteDataReader ExecuteReader()
+    {
+      return ExecuteReader(CommandBehavior.Default);
+    }
+
+    /// <summary>
+    /// Called by the SqliteDataReader when the data reader is closed.
+    /// </summary>
+    internal void ClearDataReader()
+    {
+      _activeReader = null;
+    }
+
+    /// <summary>
+    /// Execute the command and return the number of rows inserted/updated affected by it.
+    /// </summary>
+    /// <returns></returns>
+    public override int ExecuteNonQuery()
+    {
+      InitializeForReader();
+
+      int nAffected = 0;
+      int x = 0;
+      SqliteStatement stmt;
+
+      for(;;)
+      {
+        stmt = GetStatement(x);
+        x++;
+        if (stmt == null) break;
+
+        _cnn._sql.Step(stmt);
+        nAffected += _cnn._sql.Changes;
+        _cnn._sql.Reset(stmt);
+      }
+
+      return nAffected;
+    }
+
+    /// <summary>
+    /// Execute the command and return the first column of the first row of the resultset
+    /// (if present), or null if no resultset was returned.
+    /// </summary>
+    /// <returns>The first column of the first row of the first resultset from the query</returns>
+    public override object ExecuteScalar()
+    {
+      InitializeForReader();
+
+      int x = 0;
+      object ret = null;
+      SqliteType typ = new SqliteType();
+      SqliteStatement stmt;
+
+      // We step through every statement in the command, but only grab the first row of the first resultset.
+      // We keep going even after obtaining it.
+      for (;;)
+      {
+        stmt = GetStatement(x);
+        x++;
+        if (stmt == null) break;
+
+        if (_cnn._sql.Step(stmt) == true && ret == null)
+        {
+          ret = _cnn._sql.GetValue(stmt, 0, ref typ);
+        }
+        _cnn._sql.Reset(stmt);
+      }
+
+      return ret;
+    }
+
+    /// <summary>
+    /// Does nothing.  Commands are prepared as they are executed the first time, and kept in prepared state afterwards.
+    /// </summary>
+    public override void Prepare()
+    {
+    }
+
+    /// <summary>
+    /// Sets the method the SqliteCommandBuilder uses to determine how to update inserted or updated rows in a DataTable.
+    /// </summary>
+    [DefaultValue(UpdateRowSource.FirstReturnedRecord)]
+    public override UpdateRowSource UpdatedRowSource
+    {
+      get
+      {
+        return _updateRowSource;
+      }
+      set
+      {
+        _updateRowSource = value;
+      }
+    }
+
+    /// <summary>
+    /// Determines if the command is visible at design time.  Defaults to True.
+    /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+    [DesignOnly(true), Browsable(false), DefaultValue(true), EditorBrowsable(EditorBrowsableState.Never)]
+#endif
+    public override bool DesignTimeVisible
+    {
+      get
+      {
+        return _designTimeVisible;
+      }
+      set
+      {
+        _designTimeVisible = value;
+#if !PLATFORM_COMPACTFRAMEWORK
+        TypeDescriptor.Refresh(this);
+#endif
+      }
+    }
+
+    /// <summary>
+    /// Clones a command, including all its parameters
+    /// </summary>
+    /// <returns>A new SqliteCommand with the same commandtext, connection and parameters</returns>
+    public object Clone()
+    {
+      return new SqliteCommand(this);
+    }
+
+    public int LastInsertRowID ()
+    {
+	    return _cnn.LastInsertRowId;
+    }
+  }
+}
+#endif

Added: trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteCommandBuilder.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteCommandBuilder.cs	Wed Feb  4 04:24:49 2009
@@ -0,0 +1,375 @@
+//
+// Mono.Data.Sqlite.SQLiteCommandBuilder.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.Data.Common;
+  using System.Globalization;
+  using System.ComponentModel;
+
+  /// <summary>
+  /// Sqlite implementation of DbCommandBuilder.
+  /// </summary>
+  public sealed class SqliteCommandBuilder : DbCommandBuilder
+  {
+    private EventHandler<RowUpdatingEventArgs> _handler;
+
+    /// <summary>
+    /// Default constructor
+    /// </summary>
+    public SqliteCommandBuilder() : this(null)
+    {
+    }
+
+    /// <summary>
+    /// Initializes the command builder and associates it with the specified data adapter.
+    /// </summary>
+    /// <param name="adp"></param>
+    public SqliteCommandBuilder(SqliteDataAdapter adp)
+    {
+      QuotePrefix = "[";
+      QuoteSuffix = "]";
+      DataAdapter = adp;
+    }
+
+    /// <summary>
+    /// Minimal amount of parameter processing.  Primarily sets the DbType for the parameter equal to the provider type in the schema
+    /// </summary>
+    /// <param name="parameter">The parameter to use in applying custom behaviors to a row</param>
+    /// <param name="row">The row to apply the parameter to</param>
+    /// <param name="statementType">The type of statement</param>
+    /// <param name="whereClause">Whether the application of the parameter is part of a WHERE clause</param>
+    protected override void ApplyParameterInfo(DbParameter parameter, DataRow row, StatementType statementType, bool whereClause)
+    {
+      SqliteParameter param = (SqliteParameter)parameter;
+      param.DbType = (DbType)row[SchemaTableColumn.ProviderType];
+    }
+
+    /// <summary>
+    /// Returns a valid named parameter
+    /// </summary>
+    /// <param name="parameterName">The name of the parameter</param>
+    /// <returns>Error</returns>
+    protected override string GetParameterName(string parameterName)
+    {
+      return String.Format(CultureInfo.InvariantCulture, "@{0}", parameterName);
+    }
+
+    /// <summary>
+    /// Returns a named parameter for the given ordinal
+    /// </summary>
+    /// <param name="parameterOrdinal">The i of the parameter</param>
+    /// <returns>Error</returns>
+    protected override string GetParameterName(int parameterOrdinal)
+    {
+      return String.Format(CultureInfo.InvariantCulture, "@param{0}", parameterOrdinal);
+    }
+
+    /// <summary>
+    /// Returns a placeholder character for the specified parameter i.
+    /// </summary>
+    /// <param name="parameterOrdinal">The index of the parameter to provide a placeholder for</param>
+    /// <returns>Returns a named parameter</returns>
+    protected override string GetParameterPlaceholder(int parameterOrdinal)
+    {
+      return GetParameterName(parameterOrdinal);
+    }
+
+    /// <summary>
+    /// Sets the handler for receiving row updating events.  Used by the DbCommandBuilder to autogenerate SQL
+    /// statements that may not have previously been generated.
+    /// </summary>
+    /// <param name="adapter">A data adapter to receive events on.</param>
+    protected override void SetRowUpdatingHandler(DbDataAdapter adapter)
+    {
+      SqliteDataAdapter adp = (SqliteDataAdapter)adapter;
+
+      _handler = new EventHandler<RowUpdatingEventArgs>(RowUpdatingEventHandler);
+      adp.RowUpdating += _handler;
+    }
+
+    private void RowUpdatingEventHandler(object sender, RowUpdatingEventArgs e)
+    {
+      base.RowUpdatingHandler(e);
+    }
+
+    /// <summary>
+    /// Gets/sets the DataAdapter for this CommandBuilder
+    /// </summary>
+    public new SqliteDataAdapter DataAdapter
+    {
+      get { return (SqliteDataAdapter)base.DataAdapter; }
+      set { base.DataAdapter = value; }
+    }
+
+    /// <summary>
+    /// Returns the automatically-generated Sqlite command to delete rows from the database
+    /// </summary>
+    /// <returns></returns>
+    public new SqliteCommand GetDeleteCommand()
+    {
+      return (SqliteCommand)base.GetDeleteCommand();
+    }
+
+    /// <summary>
+    /// Returns the automatically-generated Sqlite command to delete rows from the database
+    /// </summary>
+    /// <param name="useColumnsForParameterNames"></param>
+    /// <returns></returns>
+    public new SqliteCommand GetDeleteCommand(bool useColumnsForParameterNames)
+    {
+      return (SqliteCommand)base.GetDeleteCommand(useColumnsForParameterNames);
+    }
+
+    /// <summary>
+    /// Returns the automatically-generated Sqlite command to update rows in the database
+    /// </summary>
+    /// <returns></returns>
+    public new SqliteCommand GetUpdateCommand()
+    {
+      return (SqliteCommand)base.GetUpdateCommand();
+    }
+
+    /// <summary>
+    /// Returns the automatically-generated Sqlite command to update rows in the database
+    /// </summary>
+    /// <param name="useColumnsForParameterNames"></param>
+    /// <returns></returns>
+    public new SqliteCommand GetUpdateCommand(bool useColumnsForParameterNames)
+    {
+      return (SqliteCommand)base.GetUpdateCommand(useColumnsForParameterNames);
+    }
+
+    /// <summary>
+    /// Returns the automatically-generated Sqlite command to insert rows into the database
+    /// </summary>
+    /// <returns></returns>
+    public new SqliteCommand GetInsertCommand()
+    {
+      return (SqliteCommand)base.GetInsertCommand();
+    }
+
+    /// <summary>
+    /// Returns the automatically-generated Sqlite command to insert rows into the database
+    /// </summary>
+    /// <param name="useColumnsForParameterNames"></param>
+    /// <returns></returns>
+    public new SqliteCommand GetInsertCommand(bool useColumnsForParameterNames)
+    {
+      return (SqliteCommand)base.GetInsertCommand(useColumnsForParameterNames);
+    }
+
+    /// <summary>
+    /// Overridden to hide its property from the designer
+    /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+    [Browsable(false)]
+#endif
+    public override CatalogLocation CatalogLocation
+    {
+      get
+      {
+        return base.CatalogLocation;
+      }
+      set
+      {
+        base.CatalogLocation = value;
+      }
+    }
+
+    /// <summary>
+    /// Overridden to hide its property from the designer
+    /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+    [Browsable(false)]
+#endif
+    public override string CatalogSeparator
+    {
+      get
+      {
+        return base.CatalogSeparator;
+      }
+      set
+      {
+        base.CatalogSeparator = value;
+      }
+    }
+
+    /// <summary>
+    /// Overridden to hide its property from the designer
+    /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+    [Browsable(false)]
+#endif
+    [DefaultValue("[")]
+    public override string QuotePrefix
+    {
+      get
+      {
+        return base.QuotePrefix;
+      }
+      set
+      {
+        base.QuotePrefix = value;
+      }
+    }
+
+    /// <summary>
+    /// Overridden to hide its property from the designer
+    /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+    [Browsable(false)]
+#endif
+    public override string QuoteSuffix
+    {
+      get
+      {
+        return base.QuoteSuffix;
+      }
+      set
+      {
+        base.QuoteSuffix = value;
+      }
+    }
+
+    /// <summary>
+    /// Places brackets around an identifier
+    /// </summary>
+    /// <param name="unquotedIdentifier">The identifier to quote</param>
+    /// <returns>The bracketed identifier</returns>
+    public override string QuoteIdentifier(string unquotedIdentifier)
+    {
+      if (String.IsNullOrEmpty(QuotePrefix)
+        || String.IsNullOrEmpty(QuoteSuffix)
+        || String.IsNullOrEmpty(unquotedIdentifier))
+        return unquotedIdentifier;
+
+      return QuotePrefix + unquotedIdentifier.Replace(QuoteSuffix, QuoteSuffix + QuoteSuffix) + QuoteSuffix;
+    }
+
+    /// <summary>
+    /// Removes brackets around an identifier
+    /// </summary>
+    /// <param name="quotedIdentifier">The quoted (bracketed) identifier</param>
+    /// <returns>The undecorated identifier</returns>
+    public override string UnquoteIdentifier(string quotedIdentifier)
+    {
+      if (String.IsNullOrEmpty(QuotePrefix)
+        || String.IsNullOrEmpty(QuoteSuffix)
+        || String.IsNullOrEmpty(quotedIdentifier))
+        return quotedIdentifier;
+
+      if (quotedIdentifier.StartsWith(QuotePrefix, StringComparison.InvariantCultureIgnoreCase) == false
+        || quotedIdentifier.EndsWith(QuoteSuffix, StringComparison.InvariantCultureIgnoreCase) == false)
+        return quotedIdentifier;
+
+      return quotedIdentifier.Substring(QuotePrefix.Length, quotedIdentifier.Length - (QuotePrefix.Length + QuoteSuffix.Length)).Replace(QuoteSuffix + QuoteSuffix, QuoteSuffix);
+    }
+
+    /// <summary>
+    /// Overridden to hide its property from the designer
+    /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+    [Browsable(false)]
+#endif
+    public override string SchemaSeparator
+    {
+      get
+      {
+        return base.SchemaSeparator;
+      }
+      set
+      {
+        base.SchemaSeparator = value;
+      }
+    }
+
+    /// <summary>
+    /// Override helper, which can help the base command builder choose the right keys for the given query
+    /// </summary>
+    /// <param name="sourceCommand"></param>
+    /// <returns></returns>
+    protected override DataTable GetSchemaTable(DbCommand sourceCommand)
+    {
+      using (IDataReader reader = sourceCommand.ExecuteReader(CommandBehavior.KeyInfo | CommandBehavior.SchemaOnly))
+      {
+        DataTable schema = reader.GetSchemaTable();
+
+        // If the query contains a primary key, turn off the IsUnique property
+        // for all the non-key columns
+        if (HasSchemaPrimaryKey(schema))
+          ResetIsUniqueSchemaColumn(schema);
+
+        // if table has no primary key we use unique columns as a fall back
+        return schema;
+      }
+    }
+
+    private bool HasSchemaPrimaryKey(DataTable schema)
+    {
+      DataColumn IsKeyColumn = schema.Columns[SchemaTableColumn.IsKey];
+      
+      foreach (DataRow schemaRow in schema.Rows)
+      {
+        if ((bool)schemaRow[IsKeyColumn] == true)
+          return true;
+      }
+
+      return false;
+    }
+
+    private void ResetIsUniqueSchemaColumn(DataTable schema)
+    {
+      DataColumn IsUniqueColumn = schema.Columns[SchemaTableColumn.IsUnique];
+      DataColumn IsKeyColumn = schema.Columns[SchemaTableColumn.IsKey];
+
+      foreach (DataRow schemaRow in schema.Rows)
+      {
+        if ((bool)schemaRow[IsKeyColumn] == false)
+          schemaRow[IsUniqueColumn] = false;
+      }
+
+      schema.AcceptChanges();
+    }
+  }
+}
+#endif

Added: trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteConnection.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteConnection.cs	Wed Feb  4 04:24:49 2009
@@ -0,0 +1,2078 @@
+//
+// Mono.Data.Sqlite.SQLiteConnection.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.Data.Common;
+  using System.Collections.Generic;
+  using System.Globalization;
+  using System.ComponentModel;
+	
+  /// <summary>
+  /// Sqlite implentation of DbConnection.
+  /// </summary>
+  /// <remarks>
+  /// The <see cref="ConnectionString">ConnectionString</see> property of the SqliteConnection class can contain the following parameter(s), delimited with a semi-colon:
+  /// <list type="table">
+  /// <listheader>
+  /// <term>Parameter</term>
+  /// <term>Values</term>
+  /// <term>Required</term>
+  /// <term>Default</term>
+  /// </listheader>
+  /// <item>
+  /// <description>Data Source</description>
+  /// <description>{filename}</description>
+  /// <description>Y</description>
+  /// <description></description>
+  /// </item>
+  /// <item>
+  /// <description>Version</description>
+  /// <description>3</description>
+  /// <description>N</description>
+  /// <description>3</description>
+  /// </item>
+  /// <item>
+  /// <description>UseUTF16Encoding</description>
+  /// <description><b>True</b><br/><b>False</b></description>
+  /// <description>N</description>
+  /// <description>False</description>
+  /// </item>
+  /// <item>
+  /// <description>DateTimeFormat</description>
+  /// <description><b>Ticks</b> - Use DateTime.Ticks<br/><b>ISO8601</b> - Use ISO8601 DateTime format</description>
+  /// <description>N</description>
+  /// <description>ISO8601</description>
+  /// </item>
+  /// <item>
+  /// <description>BinaryGUID</description>
+  /// <description><b>True</b> - Store GUID columns in binary form<br/><b>False</b> - Store GUID columns as text</description>
+  /// <description>N</description>
+  /// <description>True</description>
+  /// </item>
+  /// <item>
+  /// <description>Cache Size</description>
+  /// <description>{size in bytes}</description>
+  /// <description>N</description>
+  /// <description>2000</description>
+  /// </item>
+  /// <item>
+  /// <description>Synchronous</description>
+  /// <description><b>Normal</b> - Normal file flushing behavior<br/><b>Full</b> - Full flushing after all writes<br/><b>Off</b> - Underlying OS flushes I/O's</description>
+  /// <description>N</description>
+  /// <description>Normal</description>
+  /// </item>
+  /// <item>
+  /// <description>Page Size</description>
+  /// <description>{size in bytes}</description>
+  /// <description>N</description>
+  /// <description>1024</description>
+  /// </item>
+  /// <item>
+  /// <description>Password</description>
+  /// <description>{password}</description>
+  /// <description>N</description>
+  /// <description></description>
+  /// </item>
+  /// <item>
+  /// <description>Enlist</description>
+  /// <description><B>Y</B> - Automatically enlist in distributed transactions<br/><b>N</b> - No automatic enlistment</description>
+  /// <description>N</description>
+  /// <description>Y</description>
+  /// </item>
+  /// </list>
+  /// </remarks>
+  public sealed class SqliteConnection : DbConnection, ICloneable
+  {
+    private const string _dataDirectory = "|DataDirectory|";
+
+    /// <summary>
+    /// State of the current connection
+    /// </summary>
+    private ConnectionState      _connectionState;
+    /// <summary>
+    /// The connection string
+    /// </summary>
+    private string               _connectionString;
+    /// <summary>
+    /// Nesting level of the transactions open on the connection
+    /// </summary>
+    internal int                 _transactionLevel;
+    /// <summary>
+    /// Busy command timeout value. Defaults to 30
+    /// </summary>
+    internal int                 _busyTimeout;
+    
+#if !PLATFORM_COMPACTFRAMEWORK
+    /// <summary>
+    /// Whether or not the connection is enlisted in a distrubuted transaction
+    /// </summary>
+    internal SqliteEnlistment    _enlistment;
+#endif
+    /// <summary>
+    /// The base Sqlite object to interop with
+    /// </summary>
+    internal SqliteBase          _sql;
+    /// <summary>
+    /// Commands associated with this connection
+    /// </summary>
+    internal List<SqliteCommand> _commandList;
+    /// <summary>
+    /// The database filename minus path and extension
+    /// </summary>
+    private string               _dataSource;
+#if MONO_SUPPORT_PASSWORDS
+    /// <summary>
+    /// Temporary password storage, emptied after the database has been opened
+    /// </summary>
+    private byte[]               _password;
+#endif
+    
+    internal bool                _binaryGuid;
+
+    internal long                _version;
+
+    private event SqliteUpdateEventHandler _updateHandler;
+    private event SqliteCommitHandler      _commitHandler;
+    private event EventHandler             _rollbackHandler;
+
+    private SqliteUpdateCallback   _updateCallback;
+    private SqliteCommitCallback   _commitCallback;
+    private SqliteRollbackCallback _rollbackCallback;
+
+    /// <summary>
+    /// This event is raised whenever the database is opened or closed.
+    /// </summary>
+    //public override event StateChangeEventHandler StateChange;
+
+    /// <summary>
+    /// This event is raised whenever Sqlite makes an update/delete/insert into the database on
+    /// this connection.  It only applies to the given connection.
+    /// </summary>
+    public event SqliteUpdateEventHandler Update
+    {
+      add
+      {
+        if (_updateHandler == null)
+        {
+          _updateCallback = new SqliteUpdateCallback(UpdateCallback);
+          _sql.SetUpdateHook(_updateCallback);
+        }
+        _updateHandler += value;
+      }
+      remove
+      {
+        _updateHandler -= value;
+        if (_updateHandler == null)
+        {
+          _sql.SetUpdateHook(null);
+          _updateCallback = null;
+        }
+      }
+    }
+
+    private void UpdateCallback(int type, IntPtr database, int databaseLen, IntPtr table, int tableLen, Int64 rowid)
+    {
+      _updateHandler(this, new UpdateEventArgs(
+        _sql.UTF8ToString(database),
+        _sql.UTF8ToString(table),
+        (UpdateEventType)type,
+        rowid));
+    }
+
+    /// <summary>
+    /// This event is raised whenever Sqlite is committing a transaction.
+    /// Return non-zero to trigger a rollback
+    /// </summary>
+    public event SqliteCommitHandler Commit
+    {
+      add
+      {
+        if (_commitHandler == null)
+        {
+          _commitCallback = new SqliteCommitCallback(CommitCallback);
+          _sql.SetCommitHook(_commitCallback);
+        }
+        _commitHandler += value;
+      }
+      remove
+      {
+        _commitHandler -= value;
+        if (_commitHandler == null)
+        {
+          _sql.SetCommitHook(null);
+          _commitCallback = null;
+        }
+      }
+    }
+
+    /// <summary>
+    /// This event is raised whenever Sqlite is committing a transaction.
+    /// Return non-zero to trigger a rollback
+    /// </summary>
+    public event EventHandler RollBack
+    {
+      add
+      {
+        if (_rollbackHandler == null)
+        {
+          _rollbackCallback = new SqliteRollbackCallback(RollbackCallback);
+          _sql.SetRollbackHook(_rollbackCallback);
+        }
+        _rollbackHandler += value;
+      }
+      remove
+      {
+        _rollbackHandler -= value;
+        if (_rollbackHandler == null)
+        {
+          _sql.SetRollbackHook(null);
+          _rollbackCallback = null;
+        }
+      }
+    }
+
+
+    private int CommitCallback()
+    {
+      CommitEventArgs e = new CommitEventArgs();
+      _commitHandler(this, e);
+      return (e.AbortTransaction == true) ? 1 : 0;
+    }
+
+    private void RollbackCallback()
+    {
+      _rollbackHandler(this, EventArgs.Empty);
+    }
+
+    ///<overloads>
+    /// Constructs a new SqliteConnection object
+    /// </overloads>
+    /// <summary>
+    /// Default constructor
+    /// </summary>
+    public SqliteConnection() : this("")
+    {
+    }
+
+    /// <summary>
+    /// Initializes the connection with the specified connection string
+    /// </summary>
+    /// <param name="connectionString">The connection string to use on the connection</param>
+    public SqliteConnection(string connectionString)
+    {
+      _sql = null;
+      _connectionState = ConnectionState.Closed;
+      _connectionString = "";
+      _transactionLevel = 0;
+      _busyTimeout = 30;
+      _version = 0;
+      _commandList = new List<SqliteCommand>();
+
+      if (connectionString != null)
+        ConnectionString = connectionString;
+    }
+
+    /// <summary>
+    /// Clones the settings and connection string from an existing connection.  If the existing connection is already open, this
+    /// function will open its own connection, enumerate any attached databases of the original connection, and automatically
+    /// attach to them.
+    /// </summary>
+    /// <param name="connection"></param>
+    public SqliteConnection(SqliteConnection connection) : this(connection.ConnectionString)
+    {
+      string str;
+
+      if (connection.State == ConnectionState.Open)
+      {
+        Open();
+
+        // Reattach all attached databases from the existing connection
+        using (DataTable tbl = connection.GetSchema("Catalogs"))
+        {
+          foreach (DataRow row in tbl.Rows)
+          {
+            str = row[0].ToString();
+            if (String.Compare(str, "main", true, CultureInfo.InvariantCulture) != 0
+              && String.Compare(str, "temp", true, CultureInfo.InvariantCulture) != 0)
+            {
+              using (SqliteCommand cmd = CreateCommand())
+              {
+                cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "ATTACH DATABASE '{0}' AS [{1}]", row[1], row[0]);
+                cmd.ExecuteNonQuery();
+              }
+            }
+          }
+        }
+      }
+    }
+
+    /// <summary>
+    /// Creates a clone of the connection.  All attached databases and user-defined functions are cloned.  If the existing connection is open, the cloned connection 
+    /// will also be opened.
+    /// </summary>
+    /// <returns></returns>
+    public object Clone()
+    {
+      return new SqliteConnection(this);
+    }
+
+    /// <summary>
+    /// Disposes of the SqliteConnection, closing it if it is active.
+    /// </summary>
+    /// <param name="disposing">True if the connection is being explicitly closed.</param>
+    protected override void Dispose(bool disposing)
+    {
+      base.Dispose(disposing);
+      Close();
+    }
+
+    /// <summary>
+    /// Creates a database file.  This just creates a zero-byte file which Sqlite
+    /// will turn into a database when the file is opened properly.
+    /// </summary>
+    /// <param name="databaseFileName">The file to create</param>
+    static public void CreateFile(string databaseFileName)
+    {
+      System.IO.FileStream fs = System.IO.File.Create(databaseFileName);
+      fs.Close();
+    }
+
+    /// <summary>
+    /// On NTFS volumes, this function turns on the compression attribute for the given file.
+    /// It must not be open or referenced at the time of the function call.
+    /// </summary>
+    /// <param name="databaseFileName">The file to compress</param>
+    static public void CompressFile(string databaseFileName)
+    {
+      UnsafeNativeMethods.sqlite3_compressfile(databaseFileName);
+    }
+
+    /// <summary>
+    /// On NTFS volumes, this function removes the compression attribute for the given file.
+    /// It must not be open or referenced at the time of the function call.
+    /// </summary>
+    /// <param name="databaseFileName">The file to decompress</param>
+    static public void DecompressFile(string databaseFileName)
+    {
+      UnsafeNativeMethods.sqlite3_decompressfile(databaseFileName);
+    }
+
+    /// <summary>
+    /// Raises the state change event when the state of the connection changes
+    /// </summary>
+    /// <param name="newState">The new state.  If it is different from the previous state, an event is raised.</param>
+    internal void OnStateChange(ConnectionState newState)
+    {
+      // FIXME: breaks when the commented out code is used
+      ConnectionState oldState = _connectionState;
+      _connectionState = newState;
+
+//      if (StateChange != null && oldState != newState)
+      if (oldState != newState)
+      {
+        StateChangeEventArgs e = new StateChangeEventArgs(oldState, newState);
+        //StateChange(this, e);
+	base.OnStateChange (e);
+      }
+    }
+
+    /// <summary>
+    /// Creates a new SqliteTransaction if one isn't already active on the connection.
+    /// </summary>
+    /// <param name="isolationLevel">Sqlite doesn't support varying isolation levels, so this parameter is ignored.</param>
+    /// <param name="deferredLock">When TRUE, Sqlite defers obtaining a write lock until a write operation is requested.
+    /// When FALSE, a writelock is obtained immediately.  The default is TRUE, but in a multi-threaded multi-writer 
+    /// environment, one may instead choose to lock the database immediately to avoid any possible writer deadlock.</param>
+    /// <returns>Returns a SqliteTransaction object.</returns>
+    public SqliteTransaction BeginTransaction(System.Data.IsolationLevel isolationLevel, bool deferredLock)
+    {
+      return BeginTransaction(deferredLock);
+    }
+
+    /// <summary>
+    /// Creates a new SqliteTransaction if one isn't already active on the connection.
+    /// </summary>
+    /// <param name="deferredLock">When TRUE, Sqlite defers obtaining a write lock until a write operation is requested.
+    /// When FALSE, a writelock is obtained immediately.  The default is TRUE, but in a multi-threaded multi-writer 
+    /// environment, one may instead choose to lock the database immediately to avoid any possible writer deadlock.</param>
+    /// <returns>Returns a SqliteTransaction object.</returns>
+    public SqliteTransaction BeginTransaction(bool deferredLock)
+    {
+      if (_connectionState != ConnectionState.Open)
+        throw new InvalidOperationException();
+
+      return new SqliteTransaction(this, deferredLock);
+    }
+
+    /// <summary>
+    /// Creates a new SqliteTransaction if one isn't already active on the connection.
+    /// </summary>
+    /// <param name="isolationLevel">Sqlite supports only serializable transactions.</param>
+    /// <returns>Returns a SqliteTransaction object.</returns>
+    public new SqliteTransaction BeginTransaction(System.Data.IsolationLevel isolationLevel)
+    {
+      return BeginTransaction(false);
+    }
+
+    /// <summary>
+    /// Creates a new SqliteTransaction if one isn't already active on the connection.
+    /// </summary>
+    /// <returns>Returns a SqliteTransaction object.</returns>
+    public new SqliteTransaction BeginTransaction()
+    {
+      return BeginTransaction(false);
+    }
+
+    /// <summary>
+    /// Forwards to the local BeginTransaction() function
+    /// </summary>
+    /// <param name="isolationLevel"></param>
+    /// <returns></returns>
+    protected override DbTransaction BeginDbTransaction(System.Data.IsolationLevel isolationLevel)
+    {
+      return BeginTransaction(false);
+    }
+
+    /// <summary>
+    /// Not implemented
+    /// </summary>
+    /// <param name="databaseName"></param>
+    public override void ChangeDatabase(string databaseName)
+    {
+      throw new NotImplementedException();
+    }
+
+    /// <summary>
+    /// When the database connection is closed, all commands linked to this connection are automatically reset.
+    /// </summary>
+    public override void Close()
+    {
+      if (_sql != null)
+      {
+        // Force any commands associated with this connection to release their unmanaged
+        // resources.  The commands are still valid and will automatically re-acquire the
+        // unmanaged resources the next time they are run -- provided this connection is
+        // re-opened before then.
+        lock (_commandList)
+        {
+          foreach (SqliteCommand cmd in _commandList)
+            cmd.ClearCommands();
+        }
+
+#if !PLATFORM_COMPACTFRAMEWORK
+        if (_enlistment != null)
+        {
+          // If the connection is enlisted in a transaction scope and the scope is still active,
+          // we cannot truly shut down this connection until the scope has completed.  Therefore make a 
+          // hidden connection temporarily to hold open the connection until the scope has completed.
+          SqliteConnection cnn = new SqliteConnection();
+          cnn._sql = _sql;
+          cnn._transactionLevel = _transactionLevel;
+          cnn._enlistment = _enlistment;
+          cnn._connectionState = _connectionState;
+          cnn._version = _version;
+          
+          cnn._enlistment._transaction._cnn = cnn;
+          cnn._enlistment._disposeConnection = true;
+        }
+        else
+        {
+          _sql.Close();
+        }
+        _enlistment = null;
+#else
+        _sql.Close();
+#endif
+        _sql = null;
+        _transactionLevel = 0;
+      }
+
+      OnStateChange(ConnectionState.Closed);
+    }
+
+    /// <summary>
+    /// The connection string containing the parameters for the connection
+    /// </summary>
+    /// <remarks>
+    /// <list type="table">
+    /// <listheader>
+    /// <term>Parameter</term>
+    /// <term>Values</term>
+    /// <term>Required</term>
+    /// <term>Default</term>
+    /// </listheader>
+    /// <item>
+    /// <description>Data Source</description>
+    /// <description>{filename}</description>
+    /// <description>Y</description>
+    /// <description></description>
+    /// </item>
+    /// <item>
+    /// <description>Version</description>
+    /// <description>3</description>
+    /// <description>N</description>
+    /// <description>3</description>
+    /// </item>
+    /// <item>
+    /// <description>UseUTF16Encoding</description>
+    /// <description><b>True</b><br/><b>False</b></description>
+    /// <description>N</description>
+    /// <description>False</description>
+    /// </item>
+    /// <item>
+    /// <description>DateTimeFormat</description>
+    /// <description><b>Ticks</b> - Use DateTime.Ticks<br/><b>ISO8601</b> - Use ISO8601 DateTime format</description>
+    /// <description>N</description>
+    /// <description>ISO8601</description>
+    /// </item>
+    /// <item>
+    /// <description>BinaryGUID</description>
+    /// <description><b>Yes/On/1</b> - Store GUID columns in binary form<br/><b>No/Off/0</b> - Store GUID columns as text</description>
+    /// <description>N</description>
+    /// <description>On</description>
+    /// </item>
+    /// <item>
+    /// <description>Cache Size</description>
+    /// <description>{size in bytes}</description>
+    /// <description>N</description>
+    /// <description>2000</description>
+    /// </item>
+    /// <item>
+    /// <description>Synchronous</description>
+    /// <description><b>Normal</b> - Normal file flushing behavior<br/><b>Full</b> - Full flushing after all writes<br/><b>Off</b> - Underlying OS flushes I/O's</description>
+    /// <description>N</description>
+    /// <description>Normal</description>
+    /// </item>
+    /// <item>
+    /// <description>Page Size</description>
+    /// <description>{size in bytes}</description>
+    /// <description>N</description>
+    /// <description>1024</description>
+    /// </item>
+    /// <item>
+    /// <description>Password</description>
+    /// <description>{password}</description>
+    /// <description>N</description>
+    /// <description></description>
+    /// </item>
+    /// <item>
+    /// <description>Enlist</description>
+    /// <description><B>Y</B> - Automatically enlist in distributed transactions<br/><b>N</b> - No automatic enlistment</description>
+    /// <description>N</description>
+    /// <description>Y</description>
+    /// </item>
+    /// </list>
+    /// </remarks>
+#if !PLATFORM_COMPACTFRAMEWORK
+    [RefreshProperties(RefreshProperties.All), DefaultValue("")]
+    [Editor("Sqlite.Designer.SqliteConnectionStringEditor, Sqlite.Designer, Version=1.0.31.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139", "System.Drawing.Design.UITypeEditor, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
+#endif
+    public override string ConnectionString
+    {
+      get
+      {
+        return _connectionString;
+      }
+      set
+      {
+        if (value == null)
+          throw new ArgumentNullException();
+
+        else if (_connectionState != ConnectionState.Closed)
+          throw new InvalidOperationException();
+
+        _connectionString = value;
+      }
+    }
+
+    /// <summary>
+    /// Create a new SqliteCommand and associate it with this connection.
+    /// </summary>
+    /// <returns>Returns an instantiated SqliteCommand object already assigned to this connection.</returns>
+    public new SqliteCommand CreateCommand()
+    {
+      return new SqliteCommand(this);
+    }
+
+    /// <summary>
+    /// Forwards to the local CreateCommand() function
+    /// </summary>
+    /// <returns></returns>
+    protected override DbCommand CreateDbCommand()
+    {
+      return CreateCommand();
+    }
+
+    /// <summary>
+    /// Returns the filename without extension or path
+    /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+#endif
+    public override string DataSource
+    {
+      get 
+      {
+        return _dataSource;
+      }
+    }
+
+    /// <summary>
+    /// Returns "main'
+    /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+#endif
+    public override string Database
+    {
+      get
+      {
+        return "main";
+      }
+    }
+
+    /// <summary>
+    /// Maps mono-specific connection string keywords to the standard ones
+    /// </summary>
+    /// <returns>The mapped keyword name</returns>
+    internal void MapMonoKeyword (string[] arPiece, List<KeyValuePair<string, string>> ls)
+    {
+	    string keyword, value;
+	    
+	    switch (arPiece[0].ToLower (CultureInfo.InvariantCulture)) {
+		    case "uri":
+			    keyword = "Data Source";
+			    value = MapMonoUriPath (arPiece[1]);
+			    break;
+			    
+		    default:
+			    keyword = arPiece[0];
+			    value = arPiece[1];
+			    break;
+	    }
+
+	    ls.Add(new KeyValuePair<string, string>(keyword, value));
+    }
+
+    internal string MapMonoUriPath (string path)
+    {
+	    if (path.StartsWith ("file://")) {
+		    return path.Substring (7);
+	    } else if (path.StartsWith ("file:")) {
+		    return path.Substring (5);
+	    } else if (path.StartsWith ("/")) {
+		    return path;
+	    } else {
+		    throw new InvalidOperationException ("Invalid connection string: invalid URI");
+	    }
+    }
+    
+    /// <summary>
+    /// Parses the connection string into component parts
+    /// </summary>
+    /// <returns>An array of key-value pairs representing each parameter of the connection string</returns>
+    internal KeyValuePair<string, string>[] ParseConnectionString()
+    {
+      string s = _connectionString.Replace (',', ';'); // Mono compatibility
+      int n;
+      List<KeyValuePair<string, string>> ls = new List<KeyValuePair<string, string>>();
+
+      // First split into semi-colon delimited values.  The Split() function of SqliteBase accounts for and properly
+      // skips semi-colons in quoted strings
+      string[] arParts = SqliteConvert.Split(s, ';');
+      string[] arPiece;
+
+      int x = arParts.Length;
+      // For each semi-colon piece, split into key and value pairs by the presence of the = sign
+      for (n = 0; n < x; n++)
+      {
+        arPiece = SqliteConvert.Split(arParts[n], '=');
+        if (arPiece.Length == 2)
+	  MapMonoKeyword (arPiece, ls);
+        else throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, "Invalid ConnectionString format for parameter \"{0}\"", (arPiece.Length > 0) ? arPiece[0] : "null"));
+      }
+      KeyValuePair<string, string>[] ar = new KeyValuePair<string, string>[ls.Count];
+      ls.CopyTo(ar, 0);
+
+      // Return the array of key-value pairs
+      return ar;
+    }
+
+#if !PLATFORM_COMPACTFRAMEWORK
+    /// <summary>
+    /// Manual distributed transaction enlistment support
+    /// </summary>
+    /// <param name="transaction">The distributed transaction to enlist in</param>
+    public override void EnlistTransaction(System.Transactions.Transaction transaction)
+    {
+      if (_transactionLevel > 0 && transaction != null)
+        throw new ArgumentException("Unable to enlist in transaction, a local transaction already exists");
+
+      if (_enlistment != null && transaction != _enlistment._scope)
+        throw new ArgumentException("Already enlisted in a transaction");
+
+      _enlistment = new SqliteEnlistment(this, transaction);
+    }
+#endif
+
+    /// <summary>
+    /// Looks for a key in the array of key/values of the parameter string.  If not found, return the specified default value
+    /// </summary>
+    /// <param name="opts">The Key/Value pair array to look in</param>
+    /// <param name="key">The key to find</param>
+    /// <param name="defValue">The default value to return if the key is not found</param>
+    /// <returns>The value corresponding to the specified key, or the default value if not found.</returns>
+    static internal string FindKey(KeyValuePair<string, string>[] opts, string key, string defValue)
+    {
+      int x = opts.Length;
+      for (int n = 0; n < x; n++)
+      {
+        if (String.Compare(opts[n].Key, key, true, CultureInfo.InvariantCulture) == 0)
+        {
+          return opts[n].Value;
+        }
+      }
+      return defValue;
+    }
+
+    /// <summary>
+    /// Opens the connection using the parameters found in the <see cref="ConnectionString">ConnectionString</see>
+    /// </summary>
+    public override void Open()
+    {
+      if (_connectionState != ConnectionState.Closed)
+        throw new InvalidOperationException();
+
+      Close();
+
+      KeyValuePair<string, string>[] opts = ParseConnectionString();
+      string fileName;
+
+      if (Convert.ToInt32(FindKey(opts, "Version", "3"), CultureInfo.InvariantCulture) != 3)
+        throw new NotSupportedException("Only Sqlite Version 3 is supported at this time");
+
+      fileName = FindKey(opts, "Data Source", "");
+
+      if (String.IsNullOrEmpty(fileName))
+        throw new ArgumentException("Data Source cannot be empty.  Use :memory: to open an in-memory database");
+
+      if (String.Compare(fileName, ":MEMORY:", true, CultureInfo.InvariantCulture) == 0)
+        fileName = ":memory:";
+#if PLATFORM_COMPACTFRAMEWORK
+      else if (fileName.StartsWith(".\\"))
+        fileName = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetCallingAssembly().GetName().CodeBase) + fileName.Substring(1);
+#endif
+      string bt = FindKey (opts, "busy_timeout", "30");
+      try {
+	      _busyTimeout = Int32.Parse (bt);
+      } catch (Exception) {
+	      // ignore
+      }
+      
+      try
+      {
+        bool bUTF16 = (Convert.ToBoolean(FindKey(opts, "UseUTF16Encoding", "False"), CultureInfo.InvariantCulture) == true);
+        SqliteDateFormats dateFormat = String.Compare(FindKey(opts, "DateTimeFormat", "ISO8601"), "ticks", true, CultureInfo.InvariantCulture) == 0 ? SqliteDateFormats.Ticks : SqliteDateFormats.ISO8601;
+
+        if (bUTF16) // Sqlite automatically sets the encoding of the database to UTF16 if called from sqlite3_open16()
+          _sql = new Sqlite3_UTF16(dateFormat);
+        else
+          _sql = new Sqlite3(dateFormat);
+
+        fileName = ExpandFileName(fileName);
+
+        try
+        {
+          if (System.IO.File.Exists(fileName) == false)
+            throw new System.IO.FileNotFoundException(String.Format(CultureInfo.CurrentCulture, "Unable to locate file \"{0}\", creating new database.", fileName));
+        }
+        catch
+        {
+        }
+
+        _sql.Open(fileName);
+
+        _binaryGuid = (Convert.ToBoolean(FindKey(opts, "BinaryGUID", "True"), CultureInfo.InvariantCulture) == true);
+
+#if MONO_SUPPORT_PASSWORDS
+	// Not used under mono now
+        string password = FindKey(opts, "Password", null);
+
+        if (String.IsNullOrEmpty(password) == false)
+          _sql.SetPassword(System.Text.UTF8Encoding.UTF8.GetBytes(password));
+        else if (_password != null)
+          _sql.SetPassword(_password);
+        _password = null;
+#endif
+        _dataSource = System.IO.Path.GetFileNameWithoutExtension(fileName);
+
+        OnStateChange(ConnectionState.Open);
+        _version++;
+
+        using (SqliteCommand cmd = CreateCommand())
+        {
+          string defValue;
+
+          defValue = FindKey(opts, "Synchronous", "Normal");
+          if (String.Compare(defValue, "Normal", true, CultureInfo.InvariantCulture) != 0)
+          {
+            cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA Synchronous={0}", defValue);
+            cmd.ExecuteNonQuery();
+          }
+
+          defValue = FindKey(opts, "Cache Size", "2000");
+          if (Convert.ToInt32(defValue) != 2000)
+          {
+            cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA Cache_Size={0}", defValue);
+            cmd.ExecuteNonQuery();
+          }
+
+          if (fileName != ":memory:")
+          {
+            defValue = FindKey(opts, "Page Size", "1024");
+            if (Convert.ToInt32(defValue) != 1024)
+            {
+              cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "PRAGMA Page_Size={0}", defValue);
+              cmd.ExecuteNonQuery();
+            }
+          }
+        }
+
+#if !PLATFORM_COMPACTFRAMEWORK
+        if (FindKey(opts, "Enlist", "Y").ToUpper()[0] == 'Y' && System.Transactions.Transaction.Current != null)
+          EnlistTransaction(System.Transactions.Transaction.Current);
+#endif
+      }
+      catch (SqliteException)
+      {
+        OnStateChange(ConnectionState.Broken);
+        throw;
+      }
+    }
+
+    /// <summary>
+    /// Returns the version of the underlying Sqlite database engine
+    /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+    [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+#endif
+    public override string ServerVersion
+    {
+      get
+      {
+        if (_connectionState != ConnectionState.Open)
+          throw new InvalidOperationException();
+
+        return _sql.Version;
+      }
+    }
+
+    /// <summary>
+    /// Returns the state of the connection.
+    /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+    [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+#endif
+    public override ConnectionState State
+    {
+      get
+      {
+        return _connectionState;
+      }
+    }
+
+#if MONO_SUPPORT_PASSWORDS // Not used on mono now
+    /// <summary>
+    /// Change the password (or assign a password) to an open database.
+    /// </summary>
+    /// <remarks>
+    /// No readers or writers may be active for this process.  The database must already be open
+    /// and if it already was password protected, the existing password must already have been supplied.
+    /// </remarks>
+    /// <param name="newPassword">The new password to assign to the database</param>
+    public void ChangePassword(string newPassword)
+    {
+      ChangePassword(String.IsNullOrEmpty(newPassword) ? null : System.Text.UTF8Encoding.UTF8.GetBytes(newPassword));
+    }
+
+    /// <summary>
+    /// Change the password (or assign a password) to an open database.
+    /// </summary>
+    /// <remarks>
+    /// No readers or writers may be active for this process.  The database must already be open
+    /// and if it already was password protected, the existing password must already have been supplied.
+    /// </remarks>
+    /// <param name="newPassword">The new password to assign to the database</param>
+    public void ChangePassword(byte[] newPassword)
+    {
+      if (_connectionState != ConnectionState.Open)
+        throw new InvalidOperationException("Database must be opened before changing the password.");
+
+      _sql.ChangePassword(newPassword);
+    }
+
+    /// <summary>
+    /// Sets the password for a password-protected database.  A password-protected database is
+    /// unusable for any operation until the password has been set.
+    /// </summary>
+    /// <param name="databasePassword">The password for the database</param>
+    public void SetPassword(string databasePassword)
+    {
+      SetPassword(String.IsNullOrEmpty(databasePassword) ? null : System.Text.UTF8Encoding.UTF8.GetBytes(databasePassword));
+    }
+    
+    /// <summary>
+    /// Sets the password for a password-protected database.  A password-protected database is
+    /// unusable for any operation until the password has been set.
+    /// </summary>
+    /// <param name="databasePassword">The password for the database</param>
+    public void SetPassword(byte[] databasePassword)
+    {
+      if (_connectionState != ConnectionState.Closed)
+        throw new InvalidOperationException("Password can only be set before the database is opened.");
+
+      if (databasePassword != null)
+        if (databasePassword.Length == 0) databasePassword = null;
+
+      _password = databasePassword;
+    }
+#endif
+    
+    /// <summary>
+    /// Expand the filename of the data source, resolving the |DataDirectory| macro as appropriate.
+    /// </summary>
+    /// <param name="sourceFile">The database filename to expand</param>
+    /// <returns>The expanded path and filename of the filename</returns>
+    private string ExpandFileName(string sourceFile)
+    {
+      if (String.IsNullOrEmpty(sourceFile)) return sourceFile;
+
+      if (sourceFile.StartsWith(_dataDirectory, StringComparison.OrdinalIgnoreCase))
+      {
+        string dataDirectory;
+
+#if PLATFORM_COMPACTFRAMEWORK
+        dataDirectory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetCallingAssembly().GetName().CodeBase);
+#else
+        dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory") as string;
+        if (String.IsNullOrEmpty(dataDirectory))
+          dataDirectory = AppDomain.CurrentDomain.BaseDirectory;
+#endif
+
+        if (sourceFile.Length > _dataDirectory.Length)
+        {
+          if (sourceFile[_dataDirectory.Length] == System.IO.Path.DirectorySeparatorChar ||
+              sourceFile[_dataDirectory.Length] == System.IO.Path.AltDirectorySeparatorChar)
+            sourceFile = sourceFile.Remove(_dataDirectory.Length, 1);
+        }
+        sourceFile = System.IO.Path.Combine(dataDirectory, sourceFile.Substring(_dataDirectory.Length));
+      }
+
+      return sourceFile;
+    }
+    ///<overloads>
+    /// The following commands are used to extract schema information out of the database.  Valid schema types are:
+    /// <list type="bullet">
+    /// <item>
+    /// <description>MetaDataCollections</description>
+    /// </item>
+    /// <item>
+    /// <description>DataSourceInformation</description>
+    /// </item>
+    /// <item>
+    /// <description>Catalogs</description>
+    /// </item>
+    /// <item>
+    /// <description>Columns</description>
+    /// </item>
+    /// <item>
+    /// <description>ForeignKeys</description>
+    /// </item>
+    /// <item>
+    /// <description>Indexes</description>
+    /// </item>
+    /// <item>
+    /// <description>IndexColumns</description>
+    /// </item>
+    /// <item>
+    /// <description>Tables</description>
+    /// </item>
+    /// <item>
+    /// <description>Views</description>
+    /// </item>
+    /// <item>
+    /// <description>ViewColumns</description>
+    /// </item>
+    /// </list>
+    /// </overloads>
+    /// <summary>
+    /// Returns the MetaDataCollections schema
+    /// </summary>
+    /// <returns>A DataTable of the MetaDataCollections schema</returns>
+    public override DataTable GetSchema()
+    {
+      return GetSchema("MetaDataCollections", null);
+    }
+
+    /// <summary>
+    /// Returns schema information of the specified collection
+    /// </summary>
+    /// <param name="collectionName">The schema collection to retrieve</param>
+    /// <returns>A DataTable of the specified collection</returns>
+    public override DataTable GetSchema(string collectionName)
+    {
+      return GetSchema(collectionName, new string[0]);
+    }
+
+    /// <summary>
+    /// Retrieves schema information using the specified constraint(s) for the specified collection
+    /// </summary>
+    /// <param name="collectionName">The collection to retrieve</param>
+    /// <param name="restrictionValues">The restrictions to impose</param>
+    /// <returns>A DataTable of the specified collection</returns>
+    public override DataTable GetSchema(string collectionName, string[] restrictionValues)
+    {
+      if (_connectionState != ConnectionState.Open)
+        throw new InvalidOperationException();
+
+      string[] parms = new string[5];
+
+      if (restrictionValues == null) restrictionValues = new string[0];
+      restrictionValues.CopyTo(parms, 0);
+
+      switch (collectionName.ToUpper(CultureInfo.InvariantCulture))
+      {
+        case "METADATACOLLECTIONS":
+          return Schema_MetaDataCollections();
+        case "DATASOURCEINFORMATION":
+          return Schema_DataSourceInformation();
+        case "DATATYPES":
+          return Schema_DataTypes();
+        case "COLUMNS":
+          return Schema_Columns(parms[0], parms[2], parms[3]);
+        case "INDEXES":
+          return Schema_Indexes(parms[0], parms[2], parms[4]);
+        case "INDEXCOLUMNS":
+          return Schema_IndexColumns(parms[0], parms[2], parms[3], parms[4]);
+        case "TABLES":
+          return Schema_Tables(parms[0], parms[2], parms[3]);
+        case "VIEWS":
+          return Schema_Views(parms[0], parms[2]);
+        case "VIEWCOLUMNS":
+          return Schema_ViewColumns(parms[0], parms[2], parms[3]);
+        case "FOREIGNKEYS":
+          return Schema_ForeignKeys(parms[0], parms[2], parms[3]);
+        case "CATALOGS":
+          return Schema_Catalogs(parms[0]);
+        case "RESERVEDWORDS":
+          return Schema_ReservedWords();
+      }
+      throw new NotSupportedException();
+    }
+
+    private static DataTable Schema_ReservedWords()
+    {
+      DataTable tbl = new DataTable("MetaDataCollections");
+
+      tbl.Locale = CultureInfo.InvariantCulture;
+      tbl.Columns.Add("ReservedWord", typeof(string));
+      tbl.Columns.Add("MaximumVersion", typeof(string));
+      tbl.Columns.Add("MinimumVersion", typeof(string));
+
+      tbl.BeginLoadData();
+      DataRow row;
+      foreach (string word in SR.Keywords.Split(new char[] { ',' }))
+      {
+        row = tbl.NewRow();
+        row[0] = word;
+        tbl.Rows.Add(row);
+      }
+
+      tbl.AcceptChanges();
+      tbl.EndLoadData();
+
+      return tbl;
+    }
+
+    /// <summary>
+    /// Builds a MetaDataCollections schema datatable
+    /// </summary>
+    /// <returns>DataTable</returns>
+    private static DataTable Schema_MetaDataCollections()
+    {
+      DataTable tbl = new DataTable("MetaDataCollections");
+
+      tbl.Locale = CultureInfo.InvariantCulture;
+      tbl.Columns.Add("CollectionName", typeof(string));
+      tbl.Columns.Add("NumberOfRestrictions", typeof(int));
+      tbl.Columns.Add("NumberOfIdentifierParts", typeof(int));
+
+      tbl.BeginLoadData();
+
+      System.IO.StringReader reader = new System.IO.StringReader(SR.MetaDataCollections);
+      tbl.ReadXml(reader);
+      reader.Close();
+
+      tbl.AcceptChanges();
+      tbl.EndLoadData();
+
+      return tbl;
+    }
+
+    /// <summary>
+    /// Builds a DataSourceInformation datatable
+    /// </summary>
+    /// <returns>DataTable</returns>
+    private DataTable Schema_DataSourceInformation()
+    {
+      DataTable tbl = new DataTable("DataSourceInformation");
+      DataRow row;
+
+      tbl.Locale = CultureInfo.InvariantCulture;
+      tbl.Columns.Add(DbMetaDataColumnNames.CompositeIdentifierSeparatorPattern, typeof(string));
+      tbl.Columns.Add(DbMetaDataColumnNames.DataSourceProductName, typeof(string));
+      tbl.Columns.Add(DbMetaDataColumnNames.DataSourceProductVersion, typeof(string));
+      tbl.Columns.Add(DbMetaDataColumnNames.DataSourceProductVersionNormalized, typeof(string));
+      tbl.Columns.Add(DbMetaDataColumnNames.GroupByBehavior, typeof(int));
+      tbl.Columns.Add(DbMetaDataColumnNames.IdentifierPattern, typeof(string));
+      tbl.Columns.Add(DbMetaDataColumnNames.IdentifierCase, typeof(int));
+      tbl.Columns.Add(DbMetaDataColumnNames.OrderByColumnsInSelect, typeof(bool));
+      tbl.Columns.Add(DbMetaDataColumnNames.ParameterMarkerFormat, typeof(string));
+      tbl.Columns.Add(DbMetaDataColumnNames.ParameterMarkerPattern, typeof(string));
+      tbl.Columns.Add(DbMetaDataColumnNames.ParameterNameMaxLength, typeof(int));
+      tbl.Columns.Add(DbMetaDataColumnNames.ParameterNamePattern, typeof(string));
+      tbl.Columns.Add(DbMetaDataColumnNames.QuotedIdentifierPattern, typeof(string));
+      tbl.Columns.Add(DbMetaDataColumnNames.QuotedIdentifierCase, typeof(int));
+      tbl.Columns.Add(DbMetaDataColumnNames.StatementSeparatorPattern, typeof(string));
+      tbl.Columns.Add(DbMetaDataColumnNames.StringLiteralPattern, typeof(string));
+      tbl.Columns.Add(DbMetaDataColumnNames.SupportedJoinOperators, typeof(int));
+
+      tbl.BeginLoadData();
+
+      row = tbl.NewRow();
+      row.ItemArray = new object[] {
+        null,
+        "Sqlite",
+        _sql.Version,
+        _sql.Version,
+        3,
+        @"(^\[\p{Lo}\p{Lu}\p{Ll}_ #][\p{Lo}\p{Lu}\p{Ll}\p{Nd}@$#_]*$)|(^\[[^\]\0]|\]\]+\]$)|(^\""[^\""\0]|\""\""+\""$)",
+        1,
+        false,
+        "{0}",
+        @"@[\p{Lo}\p{Lu}\p{Ll}\p{Lm}_ #][\p{Lo}\p{Lu}\p{Ll}\p{Lm}\p{Nd}\uff3f_@#\$]*(?=\s+|$)",
+        255,
+        @"^[\p{Lo}\p{Lu}\p{Ll}\p{Lm}_ #][\p{Lo}\p{Lu}\p{Ll}\p{Lm}\p{Nd}\uff3f_@#\$]*(?=\s+|$)",
+        @"(([^\[]|\]\])*)",
+        1,
+        ";",
+        @"'(([^']|'')*)'", // ' a bug in c-sharp mode for emacs
+        15
+      };
+      tbl.Rows.Add(row);
+
+      tbl.AcceptChanges();
+      tbl.EndLoadData();
+
+      return tbl;
+    }
+
+    /// <summary>
+    /// Build a Columns schema
+    /// </summary>
+    /// <param name="strCatalog">The catalog (attached database) to query, can be null</param>
+    /// <param name="strTable">The table to retrieve schema information for, must not be null</param>
+    /// <param name="strColumn">The column to retrieve schema information for, can be null</param>
+    /// <returns>DataTable</returns>
+    private DataTable Schema_Columns(string strCatalog, string strTable, string strColumn)
+    {
+      DataTable tbl = new DataTable("Columns");
+      DataRow row;
+
+      tbl.Locale = CultureInfo.InvariantCulture;
+      tbl.Columns.Add("TABLE_CATALOG", typeof(string));
+      tbl.Columns.Add("TABLE_SCHEMA", typeof(string));
+      tbl.Columns.Add("TABLE_NAME", typeof(string));
+      tbl.Columns.Add("COLUMN_NAME", typeof(string));
+      tbl.Columns.Add("COLUMN_GUID", typeof(Guid));
+      tbl.Columns.Add("COLUMN_PROPID", typeof(long));
+      tbl.Columns.Add("ORDINAL_POSITION", typeof(int));
+      tbl.Columns.Add("COLUMN_HASDEFAULT", typeof(bool));
+      tbl.Columns.Add("COLUMN_DEFAULT", typeof(string));
+      tbl.Columns.Add("COLUMN_FLAGS", typeof(long));
+      tbl.Columns.Add("IS_NULLABLE", typeof(bool));
+      tbl.Columns.Add("DATA_TYPE", typeof(string));
+      tbl.Columns.Add("TYPE_GUID", typeof(Guid));
+      tbl.Columns.Add("CHARACTER_MAXIMUM_LENGTH", typeof(int));
+      tbl.Columns.Add("CHARACTER_OCTET_LENGTH", typeof(int));
+      tbl.Columns.Add("NUMERIC_PRECISION", typeof(int));
+      tbl.Columns.Add("NUMERIC_SCALE", typeof(int));
+      tbl.Columns.Add("DATETIME_PRECISION", typeof(long));
+      tbl.Columns.Add("CHARACTER_SET_CATALOG", typeof(string));
+      tbl.Columns.Add("CHARACTER_SET_SCHEMA", typeof(string));
+      tbl.Columns.Add("CHARACTER_SET_NAME", typeof(string));
+      tbl.Columns.Add("COLLATION_CATALOG", typeof(string));
+      tbl.Columns.Add("COLLATION_SCHEMA", typeof(string));
+      tbl.Columns.Add("COLLATION_NAME", typeof(string));
+      tbl.Columns.Add("DOMAIN_CATALOG", typeof(string));
+      tbl.Columns.Add("DOMAIN_NAME", typeof(string));
+      tbl.Columns.Add("DESCRIPTION", typeof(string));
+      tbl.Columns.Add("PRIMARY_KEY", typeof(bool));
+
+      tbl.BeginLoadData();
+
+      if (String.IsNullOrEmpty(strCatalog)) strCatalog = "main";
+
+      using (SqliteCommand cmdTables = new SqliteCommand(String.Format(CultureInfo.InvariantCulture, "SELECT * FROM [{0}].[sqlite_master] WHERE [type] LIKE 'table' OR [type] LIKE 'view'", strCatalog), this))
+      using (SqliteDataReader rdTables = cmdTables.ExecuteReader())
+      {
+        while (rdTables.Read())
+        {
+          if (String.IsNullOrEmpty(strTable) || String.Compare(strTable, rdTables.GetString(2), true, CultureInfo.InvariantCulture) == 0)
+          {
+            using (SqliteCommand cmd = new SqliteCommand(String.Format(CultureInfo.InvariantCulture, "SELECT * FROM [{0}].[{1}]", strCatalog, rdTables.GetString(2)), this))
+            using (SqliteDataReader rd = (SqliteDataReader)cmd.ExecuteReader(CommandBehavior.SchemaOnly))
+            using (DataTable tblSchema = rd.GetSchemaTable(false, true))
+            {
+              foreach (DataRow schemaRow in tblSchema.Rows)
+              {
+                if (String.Compare(schemaRow[SchemaTableColumn.ColumnName].ToString(), strColumn, true, CultureInfo.InvariantCulture) == 0
+                  || strColumn == null)
+                {
+                  row = tbl.NewRow();
+
+                  row["TABLE_NAME"] = rdTables.GetString(2);
+                  row["COLUMN_NAME"] = schemaRow[SchemaTableColumn.ColumnName];
+                  row["TABLE_CATALOG"] = strCatalog;
+                  row["ORDINAL_POSITION"] = schemaRow[SchemaTableColumn.ColumnOrdinal];
+                  row["COLUMN_HASDEFAULT"] = (schemaRow[SchemaTableOptionalColumn.DefaultValue] != DBNull.Value);
+                  row["COLUMN_DEFAULT"] = schemaRow[SchemaTableOptionalColumn.DefaultValue];
+                  row["IS_NULLABLE"] = schemaRow[SchemaTableColumn.AllowDBNull];
+                  row["DATA_TYPE"] = schemaRow["DataTypeName"]; // SqliteConvert.DbTypeToType((DbType)schemaRow[SchemaTableColumn.ProviderType]).ToString();
+                  row["CHARACTER_MAXIMUM_LENGTH"] = schemaRow[SchemaTableColumn.ColumnSize];
+                  row["TABLE_SCHEMA"] = schemaRow[SchemaTableColumn.BaseSchemaName];
+                  row["PRIMARY_KEY"] = schemaRow[SchemaTableColumn.IsKey];
+
+                  tbl.Rows.Add(row);
+                }
+              }
+            }
+          }
+        }
+      }
+
+      tbl.AcceptChanges();
+      tbl.EndLoadData();
+
+      return tbl;
+    }
+
+    /// <summary>
+    /// Returns index information for the given database and catalog
+    /// </summary>
+    /// <param name="strCatalog">The catalog (attached database) to query, can be null</param>
+    /// <param name="strIndex">The name of the index to retrieve information for, can be null</param>
+    /// <param name="strTable">The table to retrieve index information for, can be null</param>
+    /// <returns>DataTable</returns>
+    private DataTable Schema_Indexes(string strCatalog, string strTable, string strIndex)
+    {
+      DataTable tbl = new DataTable("Indexes");
+      DataRow row;
+      System.Collections.Generic.List<int> primaryKeys = new List<int>();
+      bool maybeRowId;
+
+      tbl.Locale = CultureInfo.InvariantCulture;
+      tbl.Columns.Add("TABLE_CATALOG", typeof(string));
+      tbl.Columns.Add("TABLE_SCHEMA", typeof(string));
+      tbl.Columns.Add("TABLE_NAME", typeof(string));
+      tbl.Columns.Add("INDEX_CATALOG", typeof(string));
+      tbl.Columns.Add("INDEX_SCHEMA", typeof(string));
+      tbl.Columns.Add("INDEX_NAME", typeof(string));
+      tbl.Columns.Add("PRIMARY_KEY", typeof(bool));
+      tbl.Columns.Add("UNIQUE", typeof(bool));
+      tbl.Columns.Add("CLUSTERED", typeof(bool));
+      tbl.Columns.Add("TYPE", typeof(int));
+      tbl.Columns.Add("FILL_FACTOR", typeof(int));
+      tbl.Columns.Add("INITIAL_SIZE", typeof(int));
+      tbl.Columns.Add("NULLS", typeof(int));
+      tbl.Columns.Add("SORT_BOOKMARKS", typeof(bool));
+      tbl.Columns.Add("AUTO_UPDATE", typeof(bool));
+      tbl.Columns.Add("NULL_COLLATION", typeof(int));
+      tbl.Columns.Add("ORDINAL_POSITION", typeof(int));
+      tbl.Columns.Add("COLUMN_NAME", typeof(string));
+      tbl.Columns.Add("COLUMN_GUID", typeof(Guid));
+      tbl.Columns.Add("COLUMN_PROPID", typeof(long));
+      tbl.Columns.Add("COLLATION", typeof(short));
+      tbl.Columns.Add("CARDINALITY", typeof(Decimal));
+      tbl.Columns.Add("PAGES", typeof(int));
+      tbl.Columns.Add("FILTER_CONDITION", typeof(string));
+      tbl.Columns.Add("INTEGRATED", typeof(bool));
+
+      tbl.BeginLoadData();
+
+      if (String.IsNullOrEmpty(strCatalog)) strCatalog = "main";
+
+      using (SqliteCommand cmdTables = new SqliteCommand(String.Format(CultureInfo.InvariantCulture, "SELECT * FROM [{0}].[sqlite_master] WHERE [type] LIKE 'table'", strCatalog), this))
+      using (SqliteDataReader rdTables = cmdTables.ExecuteReader())
+      {
+        while (rdTables.Read())
+        {
+          maybeRowId = false;
+          primaryKeys.Clear();
+          if (String.IsNullOrEmpty(strTable) || String.Compare(rdTables.GetString(2), strTable, true, CultureInfo.InvariantCulture) == 0)
+          {
+            // First, look for any rowid indexes -- which sqlite defines are INTEGER PRIMARY KEY columns.
+            // Such indexes are not listed in the indexes list but count as indexes just the same.
+            using (SqliteCommand cmdTable = new SqliteCommand(String.Format(CultureInfo.InvariantCulture, "PRAGMA [{0}].table_info([{1}])", strCatalog, rdTables.GetString(2)), this))
+            using (SqliteDataReader rdTable = cmdTable.ExecuteReader())
+            {
+              while (rdTable.Read())
+              {
+                if (rdTable.GetInt32(5) == 1)
+                {
+                  primaryKeys.Add(rdTable.GetInt32(0));
+
+                  // If the primary key is of type INTEGER, then its a rowid and we need to make a fake index entry for it.
+                  if (String.Compare(rdTable.GetString(2), "INTEGER", true, CultureInfo.InvariantCulture) == 0)
+                    maybeRowId = true;
+                }
+              }
+            }
+
+            if (primaryKeys.Count == 1 && maybeRowId == true)
+            {
+              row = tbl.NewRow();
+
+              row["TABLE_CATALOG"] = strCatalog;
+              row["TABLE_NAME"] = rdTables.GetString(2);
+              row["INDEX_CATALOG"] = strCatalog;
+              row["PRIMARY_KEY"] = true;
+              row["INDEX_NAME"] = String.Format(CultureInfo.InvariantCulture, "sqlite_master_PK_{0}", rdTables.GetString(2));
+              row["UNIQUE"] = true;
+
+              if (String.Compare((string)row["INDEX_NAME"], strIndex, true, CultureInfo.InvariantCulture) == 0
+              || strIndex == null)
+              {
+                tbl.Rows.Add(row);
+              }
+
+              primaryKeys.Clear();
+            }
+
+            // Now fetch all the rest of the indexes.
+            using (SqliteCommand cmd = new SqliteCommand(String.Format(CultureInfo.InvariantCulture, "PRAGMA [{0}].index_list([{1}])", strCatalog, rdTables.GetString(2)), this))
+            using (SqliteDataReader rd = (SqliteDataReader)cmd.ExecuteReader())
+            {
+              while (rd.Read())
+              {
+                if (String.Compare(rd.GetString(1), strIndex, true, CultureInfo.InvariantCulture) == 0
+                || strIndex == null)
+                {
+                  row = tbl.NewRow();
+
+                  row["TABLE_CATALOG"] = strCatalog;
+                  row["TABLE_NAME"] = rdTables.GetString(2);
+                  row["INDEX_CATALOG"] = strCatalog;
+                  row["INDEX_NAME"] = rd.GetString(1);
+                  row["UNIQUE"] = rd.GetBoolean(2);
+                  row["PRIMARY_KEY"] = false;
+
+                  // Now for the really hard work.  Figure out which index is the primary key index.
+                  // The only way to figure it out is to check if the index was an autoindex and if we have a non-rowid
+                  // primary key, and all the columns in the given index match the primary key columns
+                  if (primaryKeys.Count > 0 && rd.GetString(1).StartsWith("sqlite_autoindex_" + rdTables.GetString(2), StringComparison.InvariantCultureIgnoreCase) == true)
+                  {
+                    using (SqliteCommand cmdDetails = new SqliteCommand(String.Format(CultureInfo.InvariantCulture, "PRAGMA [{0}].index_info([{1}])", strCatalog, rd.GetString(1)), this))
+                    using (SqliteDataReader rdDetails = cmdDetails.ExecuteReader())
+                    {
+                      int nMatches = 0;
+                      while (rdDetails.Read())
+                      {
+                        if (primaryKeys.Contains(rdDetails.GetInt32(1)) == false)
+                        {
+                          nMatches = 0;
+                          break;
+                        }
+                        nMatches++;
+                      }
+                      if (nMatches == primaryKeys.Count)
+                      {
+                        row["PRIMARY_KEY"] = true;
+                        primaryKeys.Clear();
+                      }
+                    }
+                  }
+
+                  tbl.Rows.Add(row);
+                }
+              }
+            }
+          }
+        }
+      }
+
+      tbl.AcceptChanges();
+      tbl.EndLoadData();
+
+      return tbl;
+    }
+
+    /// <summary>
+    /// Retrieves table schema information for the database and catalog
+    /// </summary>
+    /// <param name="strCatalog">The catalog (attached database) to retrieve tables on</param>
+    /// <param name="strTable">The table to retrieve, can be null</param>
+    /// <param name="strType">The table type, can be null</param>
+    /// <returns>DataTable</returns>
+    private DataTable Schema_Tables(string strCatalog, string strTable, string strType)
+    {
+      DataTable tbl = new DataTable("Tables");
+      DataRow row;
+      string strItem;
+
+      tbl.Locale = CultureInfo.InvariantCulture;
+      tbl.Columns.Add("TABLE_CATALOG", typeof(string));
+      tbl.Columns.Add("TABLE_SCHEMA", typeof(string));
+      tbl.Columns.Add("TABLE_NAME", typeof(string));
+      tbl.Columns.Add("TABLE_TYPE", typeof(string));
+      tbl.Columns.Add("TABLE_ID", typeof(long));
+      tbl.Columns.Add("TABLE_ROOTPAGE", typeof(int));
+
+      tbl.BeginLoadData();
+
+      if (String.IsNullOrEmpty(strCatalog)) strCatalog = "main";
+
+      using (SqliteCommand cmd = new SqliteCommand(String.Format(CultureInfo.InvariantCulture, "SELECT [type], [name], [tbl_name], [rootpage], [sql], [rowid] FROM [{0}].[sqlite_master] WHERE [type] LIKE 'table'", strCatalog), this))
+      using (SqliteDataReader rd = (SqliteDataReader)cmd.ExecuteReader())
+      {
+        while (rd.Read())
+        {
+          strItem = rd.GetString(0);
+          if (String.Compare(rd.GetString(2), 0, "SQLITE_", 0, 7, true, CultureInfo.InvariantCulture) == 0)
+            strItem = "SYSTEM_TABLE";
+
+          if (String.Compare(strType, strItem, true, CultureInfo.InvariantCulture) == 0
+            || strType == null)
+          {
+            if (String.Compare(rd.GetString(2), strTable, true, CultureInfo.InvariantCulture) == 0
+              || strTable == null)
+            {
+              row = tbl.NewRow();
+
+              row["TABLE_CATALOG"] = strCatalog;
+              row["TABLE_NAME"] = rd.GetString(2);
+              row["TABLE_TYPE"] = strItem;
+              row["TABLE_ID"] = rd.GetInt64(5);
+              row["TABLE_ROOTPAGE"] = rd.GetInt32(3);
+
+              tbl.Rows.Add(row);
+            }
+          }
+        }
+      }
+
+      tbl.AcceptChanges();
+      tbl.EndLoadData();
+
+      return tbl;
+    }
+
+    /// <summary>
+    /// Retrieves view schema information for the database
+    /// </summary>
+    /// <param name="strCatalog">The catalog (attached database) to retrieve views on</param>
+    /// <param name="strView">The view name, can be null</param>
+    /// <returns>DataTable</returns>
+    private DataTable Schema_Views(string strCatalog, string strView)
+    {
+      DataTable tbl = new DataTable("Views");
+      DataRow row;
+      string strItem;
+      int nPos;
+
+      tbl.Locale = CultureInfo.InvariantCulture;
+      tbl.Columns.Add("TABLE_CATALOG", typeof(string));
+      tbl.Columns.Add("TABLE_SCHEMA", typeof(string));
+      tbl.Columns.Add("TABLE_NAME", typeof(string));
+      tbl.Columns.Add("VIEW_DEFINITION", typeof(string));
+      tbl.Columns.Add("CHECK_OPTION", typeof(bool));
+      tbl.Columns.Add("IS_UPDATABLE", typeof(bool));
+      tbl.Columns.Add("DESCRIPTION", typeof(string));
+      tbl.Columns.Add("DATE_CREATED", typeof(DateTime));
+      tbl.Columns.Add("DATE_MODIFIED", typeof(DateTime));
+
+      tbl.BeginLoadData();
+
+      if (String.IsNullOrEmpty(strCatalog)) strCatalog = "main";
+
+      using (SqliteCommand cmd = new SqliteCommand(String.Format(CultureInfo.InvariantCulture, "SELECT * FROM [{0}].[sqlite_master] WHERE [type] LIKE 'view'", strCatalog), this))
+      using (SqliteDataReader rd = (SqliteDataReader)cmd.ExecuteReader())
+      {
+        while (rd.Read())
+        {
+          if (String.Compare(rd.GetString(1), strView, true, CultureInfo.InvariantCulture) == 0
+            || String.IsNullOrEmpty(strView))
+          {
+            strItem = rd.GetString(4).Replace('\r', ' ').Replace('\n', ' ').Replace('\t', ' ');
+            nPos = System.Globalization.CultureInfo.InvariantCulture.CompareInfo.IndexOf(strItem, " AS ", CompareOptions.IgnoreCase);
+            if (nPos > -1)
+            {
+              strItem = strItem.Substring(nPos + 4).Trim();
+              row = tbl.NewRow();
+
+              row["TABLE_CATALOG"] = strCatalog;
+              row["TABLE_NAME"] = rd.GetString(2);
+              row["IS_UPDATABLE"] = false;
+              row["VIEW_DEFINITION"] = strItem;
+
+              tbl.Rows.Add(row);
+            }
+          }
+        }
+      }
+
+      tbl.AcceptChanges();
+      tbl.EndLoadData();
+
+      return tbl;
+    }
+
+    /// <summary>
+    /// Retrieves catalog (attached databases) schema information for the database
+    /// </summary>
+    /// <param name="strCatalog">The catalog to retrieve, can be null</param>
+    /// <returns>DataTable</returns>
+    private DataTable Schema_Catalogs(string strCatalog)
+    {
+      DataTable tbl = new DataTable("Catalogs");
+      DataRow row;
+
+      tbl.Locale = CultureInfo.InvariantCulture;
+      tbl.Columns.Add("CATALOG_NAME", typeof(string));
+      tbl.Columns.Add("DESCRIPTION", typeof(string));
+      tbl.Columns.Add("ID", typeof(long));
+
+      tbl.BeginLoadData();
+
+      using (SqliteCommand cmd = new SqliteCommand("PRAGMA database_list", this))
+      using (SqliteDataReader rd = (SqliteDataReader)cmd.ExecuteReader())
+      {
+        while (rd.Read())
+        {
+          if (String.Compare(rd.GetString(1), strCatalog, true, CultureInfo.InvariantCulture) == 0
+            || strCatalog == null)
+          {
+            row = tbl.NewRow();
+
+            row["CATALOG_NAME"] = rd.GetString(1);
+            row["DESCRIPTION"] = rd.GetString(2);
+            row["ID"] = rd.GetInt64(0);
+
+            tbl.Rows.Add(row);
+          }
+        }
+      }
+
+      tbl.AcceptChanges();
+      tbl.EndLoadData();
+
+      return tbl;
+    }
+
+    private DataTable Schema_DataTypes()
+    {
+      DataTable tbl = new DataTable("DataTypes");
+
+      tbl.Locale = CultureInfo.InvariantCulture;
+      tbl.Columns.Add("TypeName", typeof(String));
+      tbl.Columns.Add("ProviderDbType", typeof(int));
+      tbl.Columns.Add("ColumnSize", typeof(long));
+      tbl.Columns.Add("CreateFormat", typeof(String));
+      tbl.Columns.Add("CreateParameters", typeof(String));
+      tbl.Columns.Add("DataType", typeof(String));
+      tbl.Columns.Add("IsAutoIncrementable", typeof(bool));
+      tbl.Columns.Add("IsBestMatch", typeof(bool));
+      tbl.Columns.Add("IsCaseSensitive", typeof(bool));
+      tbl.Columns.Add("IsFixedLength", typeof(bool));
+      tbl.Columns.Add("IsFixedPrecisionScale", typeof(bool));
+      tbl.Columns.Add("IsLong", typeof(bool));
+      tbl.Columns.Add("IsNullable", typeof(bool));
+      tbl.Columns.Add("IsSearchable", typeof(bool));
+      tbl.Columns.Add("IsSearchableWithLike", typeof(bool));
+      tbl.Columns.Add("IsLiteralSupported", typeof(bool));
+      tbl.Columns.Add("LiteralPrefix", typeof(String));
+      tbl.Columns.Add("LiteralSuffix", typeof(String));
+      tbl.Columns.Add("IsUnsigned", typeof(bool));
+      tbl.Columns.Add("MaximumScale", typeof(short));
+      tbl.Columns.Add("MinimumScale", typeof(short));
+      tbl.Columns.Add("IsConcurrencyType", typeof(bool));
+
+      tbl.BeginLoadData();
+
+      System.IO.StringReader reader = new System.IO.StringReader(SR.DataTypes);
+      tbl.ReadXml(reader);
+      reader.Close();
+
+      tbl.AcceptChanges();
+      tbl.EndLoadData();
+
+      return tbl;
+    }
+
+    /// <summary>
+    /// Returns the base column information for indexes in a database
+    /// </summary>
+    /// <param name="strCatalog">The catalog to retrieve indexes for (can be null)</param>
+    /// <param name="strTable">The table to restrict index information by (can be null)</param>
+    /// <param name="strIndex">The index to restrict index information by (can be null)</param>
+    /// <param name="strColumn">The source column to restrict index information by (can be null)</param>
+    /// <returns>A DataTable containing the results</returns>
+    private DataTable Schema_IndexColumns(string strCatalog, string strTable, string strIndex, string strColumn)
+    {
+      DataTable tbl = new DataTable("IndexColumns");
+      DataRow row;
+      List<KeyValuePair<int, string>> primaryKeys = new List<KeyValuePair<int, string>>();
+      bool maybeRowId;
+
+      tbl.Locale = CultureInfo.InvariantCulture;
+      tbl.Columns.Add("CONSTRAINT_CATALOG", typeof(string));
+      tbl.Columns.Add("CONSTRAINT_SCHEMA", typeof(string));
+      tbl.Columns.Add("CONSTRAINT_NAME", typeof(string));
+      tbl.Columns.Add("TABLE_CATALOG", typeof(string));
+      tbl.Columns.Add("TABLE_SCHEMA", typeof(string));
+      tbl.Columns.Add("TABLE_NAME", typeof(string));
+      tbl.Columns.Add("COLUMN_NAME", typeof(string));
+      tbl.Columns.Add("ORDINAL_POSITION", typeof(int));
+      tbl.Columns.Add("INDEX_NAME", typeof(string));
+
+      if (String.IsNullOrEmpty(strCatalog)) strCatalog = "main";
+
+      tbl.BeginLoadData();
+
+      using (SqliteCommand cmdTables = new SqliteCommand(String.Format(CultureInfo.InvariantCulture, "SELECT * FROM [{0}].[sqlite_master] WHERE [type] LIKE 'table'", strCatalog), this))
+      using (SqliteDataReader rdTables = cmdTables.ExecuteReader())
+      {
+        while (rdTables.Read())
+        {
+          maybeRowId = false;
+          primaryKeys.Clear();
+          if (String.IsNullOrEmpty(strTable) || String.Compare(rdTables.GetString(2), strTable, true, CultureInfo.InvariantCulture) == 0)
+          {
+            using (SqliteCommand cmdTable = new SqliteCommand(String.Format(CultureInfo.InvariantCulture, "PRAGMA [{0}].table_info([{1}])", strCatalog, rdTables.GetString(2)), this))
+            using (SqliteDataReader rdTable = cmdTable.ExecuteReader())
+            {
+              while (rdTable.Read())
+              {
+                if (rdTable.GetInt32(5) == 1) // is a primary key
+                {
+                  primaryKeys.Add(new KeyValuePair<int, string>(rdTable.GetInt32(0), rdTable.GetString(1)));
+                  // Is an integer -- could be a rowid if no other primary keys exist in the table
+                  if (String.Compare(rdTable.GetString(2), "INTEGER", true, CultureInfo.InvariantCulture) == 0)
+                    maybeRowId = true;
+                }
+              }
+            }
+            if (primaryKeys.Count == 1 && maybeRowId == true)
+            {
+              row = tbl.NewRow();
+              row["CONSTRAINT_CATALOG"] = strCatalog;
+              row["CONSTRAINT_NAME"] = String.Format(CultureInfo.InvariantCulture, "sqlite_master_PK_{0}", rdTables.GetString(2));
+              row["TABLE_CATALOG"] = strCatalog;
+              row["TABLE_NAME"] = rdTables.GetString(2);
+              row["COLUMN_NAME"] = primaryKeys[0].Value;
+              row["INDEX_NAME"] = row["CONSTRAINT_NAME"];
+              row["ORDINAL_POSITION"] = primaryKeys[0].Key;
+
+              if (String.IsNullOrEmpty(strIndex) || String.Compare(strIndex, (string)row["INDEX_NAME"], true, CultureInfo.InvariantCulture) == 0)
+                tbl.Rows.Add(row);
+            }
+
+            using (SqliteCommand cmdIndexes = new SqliteCommand(String.Format(CultureInfo.InvariantCulture, "SELECT * FROM [{0}].[sqlite_master] WHERE [type] LIKE 'index' AND [tbl_name] LIKE '{1}'", strCatalog, rdTables.GetString(2).Replace("'", "''")), this))
+            using (SqliteDataReader rdIndexes = cmdIndexes.ExecuteReader())
+            {
+              while (rdIndexes.Read())
+              {
+                if (String.IsNullOrEmpty(strIndex) || String.Compare(strIndex, rdIndexes.GetString(1), true, CultureInfo.InvariantCulture) == 0)
+                {
+                  using (SqliteCommand cmdIndex = new SqliteCommand(String.Format(CultureInfo.InvariantCulture, "PRAGMA [{0}].index_info([{1}])", strCatalog, rdIndexes.GetString(1)), this))
+                  using (SqliteDataReader rdIndex = cmdIndex.ExecuteReader())
+                  {
+                    while (rdIndex.Read())
+                    {
+                      row = tbl.NewRow();
+                      row["CONSTRAINT_CATALOG"] = strCatalog;
+                      row["CONSTRAINT_NAME"] = rdIndexes.GetString(1);
+                      row["TABLE_CATALOG"] = strCatalog;
+                      row["TABLE_NAME"] = rdIndexes.GetString(2);
+                      row["COLUMN_NAME"] = rdIndex.GetString(2);
+                      row["INDEX_NAME"] = rdIndexes.GetString(1);
+                      row["ORDINAL_POSITION"] = rdIndex.GetInt32(1);
+
+                      if (String.IsNullOrEmpty(strColumn) || String.Compare(strColumn, row["COLUMN_NAME"].ToString(), true, CultureInfo.InvariantCulture) == 0)
+                        tbl.Rows.Add(row);
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+
+      tbl.EndLoadData();
+      tbl.AcceptChanges();
+
+      return tbl;
+    }
+
+    /// <summary>
+    /// Returns detailed column information for a specified view
+    /// </summary>
+    /// <param name="strCatalog">The catalog to retrieve columns for (can be null)</param>
+    /// <param name="strView">The view to restrict column information by (can be null)</param>
+    /// <param name="strColumn">The source column to restrict column information by (can be null)</param>
+    /// <returns>A DataTable containing the results</returns>
+    private DataTable Schema_ViewColumns(string strCatalog, string strView, string strColumn)
+    {
+      DataTable tbl = new DataTable("ViewColumns");
+      DataRow row;
+      string strSql;
+      int n;
+      DataRow schemaRow;
+      DataRow viewRow;
+
+      tbl.Locale = CultureInfo.InvariantCulture;
+      tbl.Columns.Add("VIEW_CATALOG", typeof(string));
+      tbl.Columns.Add("VIEW_SCHEMA", typeof(string));
+      tbl.Columns.Add("VIEW_NAME", typeof(string));
+      tbl.Columns.Add("VIEW_COLUMN_NAME", typeof(String));
+      tbl.Columns.Add("TABLE_CATALOG", typeof(string));
+      tbl.Columns.Add("TABLE_SCHEMA", typeof(string));
+      tbl.Columns.Add("TABLE_NAME", typeof(string));
+      tbl.Columns.Add("COLUMN_NAME", typeof(string));
+
+      if (String.IsNullOrEmpty(strCatalog)) strCatalog = "main";
+
+      tbl.BeginLoadData();
+
+      using (SqliteCommand cmdViews = new SqliteCommand(String.Format(CultureInfo.InvariantCulture, "SELECT * FROM [{0}].[sqlite_master] WHERE [type] LIKE 'view'", strCatalog), this))
+      using (SqliteDataReader rdViews = cmdViews.ExecuteReader())
+      {
+        while (rdViews.Read())
+        {
+          if (String.IsNullOrEmpty(strView) || String.Compare(strView, rdViews.GetString(2), true, CultureInfo.InvariantCulture) == 0)
+          {
+            using (SqliteCommand cmdViewSelect = new SqliteCommand(String.Format(CultureInfo.InvariantCulture, "SELECT * FROM [{0}].[{1}]", strCatalog, rdViews.GetString(2)), this))
+            {
+              strSql = rdViews.GetString(4).Replace('\r', ' ').Replace('\n', ' ').Replace('\t', ' ');
+              n = CultureInfo.InvariantCulture.CompareInfo.IndexOf(strSql, " AS ", CompareOptions.IgnoreCase);
+              if (n < 0)
+                continue;
+
+              strSql = strSql.Substring(n + 4);
+
+              using (SqliteCommand cmd = new SqliteCommand(strSql, this))
+              using (SqliteDataReader rdViewSelect = cmdViewSelect.ExecuteReader(CommandBehavior.SchemaOnly))
+              using (SqliteDataReader rd = (SqliteDataReader)cmd.ExecuteReader(CommandBehavior.SchemaOnly))
+              using (DataTable tblSchemaView = rdViewSelect.GetSchemaTable(false, false))
+              using (DataTable tblSchema = rd.GetSchemaTable(false, false))
+              {
+                for (n = 0; n < tblSchema.Rows.Count; n++)
+                {
+                  viewRow = tblSchemaView.Rows[n];
+                  schemaRow = tblSchema.Rows[n];
+
+                  if (String.Compare(viewRow[SchemaTableColumn.ColumnName].ToString(), strColumn, true, CultureInfo.InvariantCulture) == 0
+                    || strColumn == null)
+                  {
+                    row = tbl.NewRow();
+
+                    row["VIEW_CATALOG"] = strCatalog;
+                    row["VIEW_NAME"] = rdViews.GetString(2);
+                    row["TABLE_CATALOG"] = strCatalog;
+                    row["TABLE_SCHEMA"] = schemaRow[SchemaTableColumn.BaseSchemaName];
+                    row["TABLE_NAME"] = schemaRow[SchemaTableColumn.BaseTableName];
+                    row["COLUMN_NAME"] = schemaRow[SchemaTableColumn.ColumnName];
+                    row["VIEW_COLUMN_NAME"] = viewRow[SchemaTableColumn.ColumnName];
+
+                    tbl.Rows.Add(row);
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+
+      tbl.EndLoadData();
+      tbl.AcceptChanges();
+
+      return tbl;
+    }
+
+    /// <summary>
+    /// Retrieves foreign key information from the specified set of filters
+    /// </summary>
+    /// <param name="strCatalog">An optional catalog to restrict results on</param>
+    /// <param name="strTable">An optional table to restrict results on</param>
+    /// <param name="strKeyName">An optional foreign key name to restrict results on</param>
+    /// <returns>A DataTable with the results of the query</returns>
+    private DataTable Schema_ForeignKeys(string strCatalog, string strTable, string strKeyName)
+    {
+      DataTable tbl = new DataTable("ForeignKeys");
+      DataRow row;
+
+      tbl.Locale = CultureInfo.InvariantCulture;
+      tbl.Columns.Add("CONSTRAINT_CATALOG", typeof(string));
+      tbl.Columns.Add("CONSTRAINT_SCHEMA", typeof(string));
+      tbl.Columns.Add("CONSTRAINT_NAME", typeof(string));
+      tbl.Columns.Add("TABLE_CATALOG", typeof(string));
+      tbl.Columns.Add("TABLE_SCHEMA", typeof(string));
+      tbl.Columns.Add("TABLE_NAME", typeof(string));
+      tbl.Columns.Add("CONSTRAINT_TYPE", typeof(string));
+      tbl.Columns.Add("IS_DEFERRABLE", typeof(bool));
+      tbl.Columns.Add("INITIALLY_DEFERRED", typeof(bool));
+      tbl.Columns.Add("FKEY_FROM_COLUMN", typeof(string));
+      tbl.Columns.Add("FKEY_FROM_ORDINAL_POSITION", typeof(int));
+      tbl.Columns.Add("FKEY_TO_CATALOG", typeof(string));
+      tbl.Columns.Add("FKEY_TO_SCHEMA", typeof(string));
+      tbl.Columns.Add("FKEY_TO_TABLE", typeof(string));
+      tbl.Columns.Add("FKEY_TO_COLUMN", typeof(string));
+
+      if (String.IsNullOrEmpty(strCatalog)) strCatalog = "main";
+
+      tbl.BeginLoadData();
+
+      using (SqliteCommand cmdTables = new SqliteCommand(String.Format(CultureInfo.InvariantCulture, "SELECT * FROM [{0}].[sqlite_master] WHERE [type] LIKE 'table'", strCatalog), this))
+      using (SqliteDataReader rdTables = cmdTables.ExecuteReader())
+      {
+        while (rdTables.Read())
+        {
+          if (String.IsNullOrEmpty(strTable) || String.Compare(strTable, rdTables.GetString(2), true, CultureInfo.InvariantCulture) == 0)
+          {
+            using (SqliteCommand cmdTable = new SqliteCommand(String.Format(CultureInfo.InvariantCulture, "SELECT * FROM [{0}].[{1}]", strCatalog, rdTables.GetString(2)), this))
+            using (SqliteDataReader rdTable = cmdTable.ExecuteReader(CommandBehavior.SchemaOnly))
+            using (SqliteCommand cmdKey = new SqliteCommand(String.Format(CultureInfo.InvariantCulture, "PRAGMA [{0}].foreign_key_list([{1}])", strCatalog, rdTables.GetString(2)), this))
+            using (SqliteDataReader rdKey = cmdKey.ExecuteReader())
+            {
+              while (rdKey.Read())
+              {
+                row = tbl.NewRow();
+                row["CONSTRAINT_CATALOG"] = strCatalog;
+                row["CONSTRAINT_NAME"] = String.Format(CultureInfo.InvariantCulture, "FK_{0}_{1}_{2}", rdTables.GetString(2), rdKey.GetString(3), rdKey.GetString(4));
+                row["TABLE_CATALOG"] = strCatalog;
+                row["TABLE_NAME"] = rdTables.GetString(2);
+                row["CONSTRAINT_TYPE"] = "FOREIGN KEY";
+                row["IS_DEFERRABLE"] = false;
+                row["INITIALLY_DEFERRED"] = false;
+                row["FKEY_FROM_COLUMN"] = rdKey.GetString(3);
+                row["FKEY_FROM_ORDINAL_POSITION"] = rdTable.GetOrdinal(row["FKEY_FROM_COLUMN"].ToString());
+                row["FKEY_TO_CATALOG"] = strCatalog;
+                row["FKEY_TO_TABLE"] = rdKey.GetString(2);
+                row["FKEY_TO_COLUMN"] = rdKey.GetString(4);
+
+                if (String.IsNullOrEmpty(strKeyName) || String.Compare(strKeyName, row["CONSTRAINT_NAME"].ToString(), true, CultureInfo.InvariantCulture) == 0)
+                  tbl.Rows.Add(row);
+              }
+            }
+          }
+        }
+      }
+
+      tbl.EndLoadData();
+      tbl.AcceptChanges();
+
+      return tbl;
+    }
+
+    internal void AddCommand(SqliteCommand cmd)
+    {
+      lock (_commandList)
+      {
+        _commandList.Add(cmd);
+      }
+    }
+
+    internal void RemoveCommand(SqliteCommand cmd)
+    {
+      lock (_commandList)
+      {
+        _commandList.Remove(cmd);
+      }
+    }
+
+#if MONO_BACKWARD_COMPAT
+    /// <summary>
+    /// Obsolete
+    /// </summary>
+    public override int ConnectionTimeout
+    {
+      get
+      {
+        return 30;
+      }
+    }
+
+    public int Version {
+      get { return 3; }
+    }
+
+    public int LastInsertRowId {
+	get { return _sql.GetLastInsertRowId (); }
+    }
+
+    public int BusyTimeout {
+	    get { return _busyTimeout; }
+    }
+#endif
+  }
+
+  /// <summary>
+  /// The I/O file cache flushing behavior for the connection
+  /// </summary>
+  public enum SynchronizationModes
+  {
+    /// <summary>
+    /// Normal file flushing at critical sections of the code
+    /// </summary>
+    Normal = 0,
+    /// <summary>
+    /// Full file flushing after every write operation
+    /// </summary>
+    Full = 1,
+    /// <summary>
+    /// Use the default operating system's file flushing, Sqlite does not explicitly flush the file buffers after writing
+    /// </summary>
+    Off = 2,
+  }
+
+  internal delegate void SqliteUpdateCallback(int type, IntPtr database, int databaseLen, IntPtr table, int tableLen, Int64 rowid);
+  internal delegate int SqliteCommitCallback();
+  internal delegate void SqliteRollbackCallback();
+
+  /// <summary>
+  /// Raised when a transaction is about to be committed.  To roll back a transaction, set the 
+  /// rollbackTrans boolean value to true.
+  /// </summary>
+  /// <param name="sender">The connection committing the transaction</param>
+  /// <param name="e">Event arguments on the transaction</param>
+  public delegate void SqliteCommitHandler(object sender, CommitEventArgs e);
+
+  /// <summary>
+  /// Raised when data is inserted, updated and deleted on a given connection
+  /// </summary>
+  /// <param name="sender">The connection committing the transaction</param>
+  /// <param name="e">The event parameters which triggered the event</param>
+  public delegate void SqliteUpdateEventHandler(object sender, UpdateEventArgs e);
+
+  /// <summary>
+  /// Whenever an update event is triggered on a connection, this enum will indicate
+  /// exactly what type of operation is being performed.
+  /// </summary>
+  public enum UpdateEventType
+  {
+    /// <summary>
+    /// A row is being deleted from the given database and table
+    /// </summary>
+    Delete = 9,
+    /// <summary>
+    /// A row is being inserted into the table.
+    /// </summary>
+    Insert = 18,
+    /// <summary>
+    /// A row is being updated in the table.
+    /// </summary>
+    Update = 23,
+  }
+
+  /// <summary>
+  /// Passed during an Update callback, these event arguments detail the type of update operation being performed
+  /// on the given connection.
+  /// </summary>
+  public class UpdateEventArgs : EventArgs
+  {
+    /// <summary>
+    /// The name of the database being updated (usually "main" but can be any attached or temporary database)
+    /// </summary>
+    public readonly string Database;
+
+    /// <summary>
+    /// The name of the table being updated
+    /// </summary>
+    public readonly string Table;
+
+    /// <summary>
+    /// The type of update being performed (insert/update/delete)
+    /// </summary>
+    public readonly UpdateEventType Event;
+
+    /// <summary>
+    /// The RowId affected by this update.
+    /// </summary>
+    public readonly Int64 RowId;
+
+    internal UpdateEventArgs(string database, string table, UpdateEventType eventType, Int64 rowid)
+    {
+      Database = database;
+      Table = table;
+      Event = eventType;
+      RowId = rowid;
+    }
+  }
+
+  /// <summary>
+  /// Event arguments raised when a transaction is being committed
+  /// </summary>
+  public class CommitEventArgs : EventArgs
+  {
+    internal CommitEventArgs()
+    {
+    }
+
+    /// <summary>
+    /// Set to true to abort the transaction and trigger a rollback
+    /// </summary>
+    public bool AbortTransaction;
+  }
+}
+#endif

Added: trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteConnectionStringBuilder.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteConnectionStringBuilder.cs	Wed Feb  4 04:24:49 2009
@@ -0,0 +1,323 @@
+//
+// Mono.Data.Sqlite.SQLiteConnectionStringBuilder.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.Common;
+  using System.ComponentModel;
+  using System.Collections;
+  using System.Globalization;
+  using System.Reflection;
+
+#if !PLATFORM_COMPACTFRAMEWORK
+  using System.ComponentModel.Design;
+
+  /// <summary>
+  /// Sqlite implementation of DbConnectionStringBuilder.
+  /// </summary>
+  [DefaultProperty("DataSource")]
+  [DefaultMember("Item")]
+  public sealed class SqliteConnectionStringBuilder : DbConnectionStringBuilder
+  {
+    /// <summary>
+    /// Properties of this class
+    /// </summary>
+    private Hashtable _properties;
+
+    /// <overloads>
+    /// Constructs a new instance of the class
+    /// </overloads>
+    /// <summary>
+    /// Default constructor
+    /// </summary>
+    public SqliteConnectionStringBuilder()
+    {
+      Initialize(null);
+    }
+
+    /// <summary>
+    /// Constructs a new instance of the class using the specified connection string.
+    /// </summary>
+    /// <param name="connectionString">The connection string to parse</param>
+    public SqliteConnectionStringBuilder(string connectionString)
+    {
+      Initialize(connectionString);
+    }
+
+    /// <summary>
+    /// Private initializer, which assigns the connection string and resets the builder
+    /// </summary>
+    /// <param name="cnnString">The connection string to assign</param>
+    private void Initialize(string cnnString)
+    {
+      _properties = new Hashtable();
+      base.GetProperties(_properties);
+
+      if (String.IsNullOrEmpty(cnnString) == false)
+        ConnectionString = cnnString;
+    }
+
+    /// <summary>
+    /// Gets/Sets the default version of the Sqlite engine to instantiate.  Currently the only valid value is 3, indicating version 3 of the sqlite library.
+    /// </summary>
+    [Browsable(true)]
+    [DefaultValue(3)]
+    public int Version
+    {
+      get
+      {
+        if (ContainsKey("Version") == false) return 3;
+
+        return Convert.ToInt32(this["Version"], CultureInfo.CurrentCulture);
+      }
+      set
+      {
+        if (value != 3)
+          throw new NotSupportedException();
+
+        this["Version"] = value;
+      }
+    }
+
+    /// <summary>
+    /// Gets/Sets the synchronous mode of the connection string.  Default is "Normal".
+    /// </summary>
+    [DisplayName("Synchronous")]
+    [Browsable(true)]
+    [DefaultValue(SynchronizationModes.Normal)]
+    public SynchronizationModes SyncMode
+    {
+      get
+      {
+        return (SynchronizationModes)TypeDescriptor.GetConverter(typeof(SynchronizationModes)).ConvertFrom(this["Synchronous"]);
+      }
+      set
+      {
+        this["Synchronous"] = value;
+      }
+    }
+
+    /// <summary>
+    /// Gets/Sets the encoding for the connection string.  The default is "False" which indicates UTF-8 encoding.
+    /// </summary>
+    [Browsable(true)]
+    [DefaultValue(false)]
+    public bool UseUTF16Encoding
+    {
+      get
+      {
+        return Convert.ToBoolean(this["UseUTF16Encoding"], CultureInfo.CurrentCulture);
+      }
+      set
+      {
+        this["UseUTF16Encoding"] = value;
+      }
+    }
+
+    /// <summary>
+    /// Gets/Sets the filename to open on the connection string.
+    /// </summary>
+    [DisplayName("Data Source")]
+    [Browsable(true)]
+    public string DataSource
+    {
+      get
+      {
+        if (ContainsKey("Data Source") == false) return "";
+
+        return this["Data Source"].ToString();
+      }
+      set
+      {
+        this["Data Source"] = value;
+      }
+    }
+
+#region Mono-specific
+    /// <summary>
+    /// Gets/Sets the filename to open on the connection string (Mono-specific, uses DataSource).
+    /// </summary>
+    [DisplayName("Data Source")]
+    [Browsable(true)]
+    public string Uri
+    {
+      get
+      {
+	return DataSource;
+      }
+      set
+      {
+        DataSource = value;
+      }
+    }
+#endregion
+    
+    /// <summary>
+    /// Determines whether or not the connection will automatically participate
+    /// in the current distributed transaction (if one exists)
+    /// </summary>
+    [DisplayName("Automatic Enlistment")]
+    [Browsable(true)]
+    [DefaultValue(true)]
+    public bool Enlist
+    {
+      get
+      {
+        if (ContainsKey("Enlist") == false) return true;
+
+        return (this["Enlist"].ToString() == "Y");
+      }
+      set
+      {
+        this["Enlist"] = (value == true) ? "Y" : "N";
+      }
+    }
+    /// <summary>
+    /// Gets/sets the database encryption password
+    /// </summary>
+    [Browsable(true)]
+    [PasswordPropertyText(true)]
+    public string Password
+    {
+      get
+      {
+        if (ContainsKey("Password") == false) return "";
+
+        return this["Password"].ToString();
+      }
+      set
+      {
+        this["Password"] = value;
+      }
+    }
+
+    /// <summary>
+    /// Gets/Sets the page size for the connection.
+    /// </summary>
+    [DisplayName("Page Size")]
+    [Browsable(true)]
+    [DefaultValue(1024)]
+    public int PageSize
+    {
+      get
+      {
+        if (ContainsKey("Page Size") == false) return 1024;
+        return Convert.ToInt32(this["Page Size"], CultureInfo.InvariantCulture);
+      }
+      set
+      {
+        this["Page Size"] = value;
+      }
+    }
+
+    /// <summary>
+    /// Gets/Sets the cache size for the connection.
+    /// </summary>
+    [DisplayName("Cache Size")]
+    [Browsable(true)]
+    [DefaultValue(2000)]
+    public int CacheSize
+    {
+      get
+      {
+        if (ContainsKey("Cache Size") == false) return 2000;
+        return Convert.ToInt32(this["Cache Size"], CultureInfo.InvariantCulture);
+      }
+      set
+      {
+        this["Cache Size"] = value;
+      }
+    }
+
+    /// <summary>
+    /// Gets/Sets the datetime format for the connection.
+    /// </summary>
+    [Browsable(true)]
+    [DefaultValue(SqliteDateFormats.ISO8601)]
+    public SqliteDateFormats DateTimeFormat
+    {
+      get
+      {
+        if (ContainsKey("DateTimeFormat") == false) return SqliteDateFormats.ISO8601;
+
+        return (SqliteDateFormats)TypeDescriptor.GetConverter(typeof(SqliteDateFormats)).ConvertFrom(this["DateTimeFormat"]);
+      }
+      set
+      {
+        this["DateTimeFormat"] = value;
+      }
+    }
+
+    /// <summary>
+    /// Helper function for retrieving values from the connectionstring
+    /// </summary>
+    /// <param name="keyword">The keyword to retrieve settings for</param>
+    /// <param name="value">The resulting parameter value</param>
+    /// <returns>Returns true if the value was found and returned</returns>
+    public override bool TryGetValue(string keyword, out object value)
+    {
+      bool b = base.TryGetValue(keyword, out value);
+
+      if (!_properties.ContainsKey(keyword)) return b;
+
+      PropertyDescriptor pd = _properties[keyword] as PropertyDescriptor;
+
+      if (pd == null) return b;
+
+      if (b)
+      {
+        value = TypeDescriptor.GetConverter(pd.PropertyType).ConvertFrom(value);
+      }
+      else
+      {
+        DefaultValueAttribute att = pd.Attributes[typeof(DefaultValueAttribute)] as DefaultValueAttribute;
+        if (att != null)
+        {
+          value = att.Value;
+          b = true;
+        }
+      }
+      return b;
+    }
+  }
+#endif
+}
+#endif

Added: trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteConvert.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteConvert.cs	Wed Feb  4 04:24:49 2009
@@ -0,0 +1,651 @@
+//
+// 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)
+    {
+      if (nativestring == IntPtr.Zero)
+        return null;
+    
+      // This assumes a single byte terminates the string.
+
+      int len = 0;
+      while (Marshal.ReadByte (nativestring, len) != 0)
+        checked {++len;}
+
+      unsafe { 
+        string s = new string ((sbyte*) nativestring, 0, len, _utf8);
+        len = s.Length;
+        while (len > 0 && s [len-1] == 0)
+          --len;
+        if (len == s.Length) 
+          return s;
+        return s.Substring (0, len);
+      }
+    }
+
+
+    #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

Added: trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteDataAdapter.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteDataAdapter.cs	Wed Feb  4 04:24:49 2009
@@ -0,0 +1,192 @@
+//
+// Mono.Data.Sqlite.SQLiteDataAdapter.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.Data.Common;
+  using System.ComponentModel;
+
+  /// <summary>
+  /// Sqlite implementation of DbDataAdapter.
+  /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+  [DefaultEvent("RowUpdated")]
+  [ToolboxItem("Sqlite.Designer.SqliteDataAdapterToolboxItem, Sqlite.Designer, Version=1.0.31.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139")]
+  [Designer("Microsoft.VSDesigner.Data.VS.SqlDataAdapterDesigner, Microsoft.VSDesigner, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
+#endif
+  public sealed class SqliteDataAdapter : DbDataAdapter
+  {
+    private static object _updatingEventPH = new object();
+    private static object _updatedEventPH = new object();
+
+    /// <overloads>
+    /// This class is just a shell around the DbDataAdapter.  Nothing from DbDataAdapter is overridden here, just a few constructors are defined.
+    /// </overloads>
+    /// <summary>
+    /// Default constructor.
+    /// </summary>
+    public SqliteDataAdapter()
+    {
+    }
+
+    /// <summary>
+    /// Constructs a data adapter using the specified select command.
+    /// </summary>
+    /// <param name="cmd">The select command to associate with the adapter.</param>
+    public SqliteDataAdapter(SqliteCommand cmd)
+    {
+      SelectCommand = cmd;
+    }
+
+    /// <summary>
+    /// Constructs a data adapter with the supplied select command text and associated with the specified connection.
+    /// </summary>
+    /// <param name="commandText">The select command text to associate with the data adapter.</param>
+    /// <param name="connection">The connection to associate with the select command.</param>
+    public SqliteDataAdapter(string commandText, SqliteConnection connection)
+    {
+      SelectCommand = new SqliteCommand(commandText, connection);
+    }
+
+    /// <summary>
+    /// Constructs a data adapter with the specified select command text, and using the specified database connection string.
+    /// </summary>
+    /// <param name="commandText">The select command text to use to construct a select command.</param>
+    /// <param name="connectionString">A connection string suitable for passing to a new SqliteConnection, which is associated with the select command.</param>
+    public SqliteDataAdapter(string commandText, string connectionString)
+    {
+      SqliteConnection cnn = new SqliteConnection(connectionString);
+      SelectCommand = new SqliteCommand(commandText, cnn);
+    }
+
+    /// <summary>
+    /// Row updating event handler
+    /// </summary>
+    public event EventHandler<RowUpdatingEventArgs> RowUpdating
+    {
+      add { base.Events.AddHandler(_updatingEventPH, value); }
+      remove { base.Events.RemoveHandler(_updatingEventPH, value); }
+    }
+
+    /// <summary>
+    /// Row updated event handler
+    /// </summary>
+    public event EventHandler<RowUpdatedEventArgs> RowUpdated
+    {
+      add { base.Events.AddHandler(_updatedEventPH, value); }
+      remove { base.Events.RemoveHandler(_updatedEventPH, value); }
+    }
+
+    /// <summary>
+    /// Raised by the underlying DbDataAdapter when a row is being updated
+    /// </summary>
+    /// <param name="value">The event's specifics</param>
+    protected override void OnRowUpdating(RowUpdatingEventArgs value)
+    {
+      EventHandler<RowUpdatingEventArgs> handler = base.Events[_updatingEventPH] as EventHandler<RowUpdatingEventArgs>;
+
+      if (handler != null)
+        handler(this, value);
+    }
+
+    /// <summary>
+    /// Raised by DbDataAdapter after a row is updated
+    /// </summary>
+    /// <param name="value">The event's specifics</param>
+    protected override void OnRowUpdated(RowUpdatedEventArgs value)
+    {
+      EventHandler<RowUpdatedEventArgs> handler = base.Events[_updatedEventPH] as EventHandler<RowUpdatedEventArgs>;
+
+      if (handler != null)
+        handler(this, value);
+    }
+
+    /// <summary>
+    /// Gets/sets the select command for this DataAdapter
+    /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+    [DefaultValue((string)null), Editor("Microsoft.VSDesigner.Data.Design.DBCommandEditor, Microsoft.VSDesigner, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Drawing.Design.UITypeEditor, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
+#endif
+    public new SqliteCommand SelectCommand
+    {
+      get { return (SqliteCommand)base.SelectCommand; }
+      set { base.SelectCommand = value; }
+    }
+
+    /// <summary>
+    /// Gets/sets the insert command for this DataAdapter
+    /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+    [DefaultValue((string)null), Editor("Microsoft.VSDesigner.Data.Design.DBCommandEditor, Microsoft.VSDesigner, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Drawing.Design.UITypeEditor, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
+#endif
+    public new SqliteCommand InsertCommand
+    {
+      get { return (SqliteCommand)base.InsertCommand; }
+      set { base.InsertCommand = value; }
+    }
+
+    /// <summary>
+    /// Gets/sets the update command for this DataAdapter
+    /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+    [DefaultValue((string)null), Editor("Microsoft.VSDesigner.Data.Design.DBCommandEditor, Microsoft.VSDesigner, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Drawing.Design.UITypeEditor, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
+#endif
+    public new SqliteCommand UpdateCommand
+    {
+      get { return (SqliteCommand)base.UpdateCommand; }
+      set { base.UpdateCommand = value; }
+    }
+
+    /// <summary>
+    /// Gets/sets the delete command for this DataAdapter
+    /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+    [DefaultValue((string)null), Editor("Microsoft.VSDesigner.Data.Design.DBCommandEditor, Microsoft.VSDesigner, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Drawing.Design.UITypeEditor, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
+#endif
+    public new SqliteCommand DeleteCommand
+    {
+      get { return (SqliteCommand)base.DeleteCommand; }
+      set { base.DeleteCommand = value; }
+    }
+  }
+}
+#endif

Added: trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteDataReader.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteDataReader.cs	Wed Feb  4 04:24:49 2009
@@ -0,0 +1,1066 @@
+//
+// Mono.Data.Sqlite.SQLiteDataReader.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.Data.Common;
+  using System.Collections;
+  using System.Collections.Generic;
+  using System.Globalization;
+  using System.Reflection;
+
+  /// <summary>
+  /// Sqlite implementation of DbDataReader.
+  /// </summary>
+  public class SqliteDataReader : DbDataReader
+  {
+    /// <summary>
+    /// Underlying command this reader is attached to
+    /// </summary>
+    private SqliteCommand   _command;
+    /// <summary>
+    /// Index of the current statement in the command being processed
+    /// </summary>
+    private int             _activeStatementIndex;
+    /// <summary>
+    /// Current statement being Read()
+    /// </summary>
+    private SqliteStatement _activeStatement;
+    /// <summary>
+    /// State of the current statement being processed.
+    /// -1 = First Step() executed, so the first Read() will be ignored
+    ///  0 = Actively reading
+    ///  1 = Finished reading
+    ///  2 = Non-row-returning statement, no records
+    /// </summary>
+    private int             _readingState;
+    /// <summary>
+    /// Number of records affected by the insert/update statements executed on the command
+    /// </summary>
+    private int             _rowsAffected;
+    /// <summary>
+    /// Count of fields (columns) in the row-returning statement currently being processed
+    /// </summary>
+    private int             _fieldCount;
+    /// <summary>
+    /// Datatypes of active fields (columns) in the current statement, used for type-restricting data
+    /// </summary>
+    private SqliteType[]    _fieldTypeArray;
+
+    /// <summary>
+    /// The behavior of the datareader
+    /// </summary>
+    private CommandBehavior _commandBehavior;
+
+    /// <summary>
+    /// If set, then dispose of the command object when the reader is finished
+    /// </summary>
+    internal bool           _disposeCommand;
+
+#if MONO_SUPPORT_KEYREADER
+    /// <summary>
+    /// An array of rowid's for the active statement if CommandBehavior.KeyInfo is specified
+    /// </summary>
+    private SqliteKeyReader _keyInfo;
+#endif
+    
+    /// <summary>
+    /// Internal constructor, initializes the datareader and sets up to begin executing statements
+    /// </summary>
+    /// <param name="cmd">The SqliteCommand this data reader is for</param>
+    /// <param name="behave">The expected behavior of the data reader</param>
+    internal SqliteDataReader(SqliteCommand cmd, CommandBehavior behave)
+    {
+      _command = cmd;
+      _commandBehavior = behave;
+      _activeStatementIndex = -1;
+      _activeStatement = null;
+      _rowsAffected = -1;
+      _fieldCount = -1;
+
+      if (_command != null)
+        NextResult();
+    }
+
+    /// <summary>
+    /// Closes the datareader, potentially closing the connection as well if CommandBehavior.CloseConnection was specified.
+    /// </summary>
+    public override void Close()
+    {
+      if (_command != null)
+      {
+        while (NextResult())
+        {
+        }
+        _command.ClearDataReader();
+
+        // If the datareader's behavior includes closing the connection, then do so here.
+        if ((_commandBehavior & CommandBehavior.CloseConnection) != 0 && _command.Connection != null)
+          _command.Connection.Close();
+
+        if (_disposeCommand)
+          ((IDisposable)_command).Dispose();
+      }
+
+      _command = null;
+      _activeStatement = null;
+      _fieldTypeArray = null;
+
+#if MONO_SUPPORT_KEYREADER
+      if (_keyInfo != null)
+      {
+        _keyInfo.Dispose();
+        _keyInfo = null;
+      }
+#endif
+    }
+
+    /// <summary>
+    /// Disposes the datareader.  Calls Close() to ensure everything is cleaned up.
+    /// </summary>
+    protected override void Dispose(bool disposing)
+    {
+      base.Dispose(disposing);
+      GC.SuppressFinalize(this);
+    }
+
+    /// <summary>
+    /// Throw an error if the datareader is closed
+    /// </summary>
+    private void CheckClosed()
+    {
+      if (_command == null)
+        throw new InvalidOperationException("DataReader has been closed");
+    }
+
+    /// <summary>
+    /// Throw an error if a row is not loaded
+    /// </summary>
+    private void CheckValidRow()
+    {
+      if (_readingState != 0)
+        throw new InvalidOperationException("No current row");
+    }
+
+    /// <summary>
+    /// Enumerator support
+    /// </summary>
+    /// <returns>Returns a DbEnumerator object.</returns>
+    public override System.Collections.IEnumerator GetEnumerator()
+    {
+      return new DbEnumerator(this);
+    }
+
+    /// <summary>
+    /// Not implemented.  Returns 0
+    /// </summary>
+    public override int Depth
+    {
+      get
+      {
+        CheckClosed();
+        return 0;
+      }
+    }
+
+    /// <summary>
+    /// Returns the number of columns in the current resultset
+    /// </summary>
+    public override int FieldCount
+    {
+      get
+      {
+        CheckClosed();
+#if MONO_SUPPORT_KEYREADER
+        if (_keyInfo == null)
+          return _fieldCount;
+
+        return _fieldCount + _keyInfo.Count;
+#else
+	return _fieldCount;
+#endif
+      }
+    }
+
+    /// <summary>
+    /// Returns the number of visible fielsd in the current resultset
+    /// </summary>
+    public override int VisibleFieldCount
+    {
+      get
+      {
+        CheckClosed();
+        return _fieldCount;
+      }
+    }
+
+    /// <summary>
+    /// Sqlite is inherently un-typed.  All datatypes in Sqlite are natively strings.  The definition of the columns of a table
+    /// and the affinity of returned types are all we have to go on to type-restrict data in the reader.
+    /// 
+    /// This function attempts to verify that the type of data being requested of a column matches the datatype of the column.  In
+    /// the case of columns that are not backed into a table definition, we attempt to match up the affinity of a column (int, double, string or blob)
+    /// to a set of known types that closely match that affinity.  It's not an exact science, but its the best we can do.
+    /// </summary>
+    /// <returns>
+    /// This function throws an InvalidTypeCast() exception if the requested type doesn't match the column's definition or affinity.
+    /// </returns>
+    /// <param name="i">The index of the column to type-check</param>
+    /// <param name="typ">The type we want to get out of the column</param>
+    private TypeAffinity VerifyType(int i, DbType typ)
+    {
+      CheckClosed();
+      CheckValidRow();
+      TypeAffinity affinity;
+
+      affinity = _activeStatement._sql.ColumnAffinity(_activeStatement, i);
+
+      switch (affinity)
+      {
+        case TypeAffinity.Int64:
+          if (typ == DbType.Int16) return affinity;
+          if (typ == DbType.Int32) return affinity;
+          if (typ == DbType.Int64) return affinity;
+          if (typ == DbType.Boolean) return affinity;
+          if (typ == DbType.Byte) return affinity;
+          if (typ == DbType.DateTime && _command.Connection._sql._datetimeFormat == SqliteDateFormats.Ticks) return affinity;
+          if (typ == DbType.Single) return affinity;
+          if (typ == DbType.Double) return affinity;
+          if (typ == DbType.Decimal) return affinity;
+          break;
+        case TypeAffinity.Double:
+          if (typ == DbType.Single) return affinity;
+          if (typ == DbType.Double) return affinity;
+          if (typ == DbType.Decimal) return affinity;
+          break;
+        case TypeAffinity.Text:
+          if (typ == DbType.SByte) return affinity;
+          if (typ == DbType.String) return affinity;
+          if (typ == DbType.SByte) return affinity;
+          if (typ == DbType.Guid) return affinity;
+          if (typ == DbType.DateTime) return affinity;
+          break;
+        case TypeAffinity.Blob:
+          if (typ == DbType.Guid) return affinity;
+          if (typ == DbType.String) return affinity;
+          if (typ == DbType.Binary) return affinity;
+          break;
+      }
+
+      throw new InvalidCastException();
+    }
+
+    /// <summary>
+    /// Retrieves the column as a boolean value
+    /// </summary>
+    /// <param name="i">The index of the column to retrieve</param>
+    /// <returns>bool</returns>
+    public override bool GetBoolean(int i)
+    {
+#if MONO_SUPPORT_KEYREADER
+      if (i >= VisibleFieldCount && _keyInfo != null)
+        return _keyInfo.GetBoolean(i - VisibleFieldCount);
+#endif
+      
+      VerifyType(i, DbType.Boolean);
+      return Convert.ToBoolean(GetValue(i), CultureInfo.CurrentCulture);
+    }
+
+    /// <summary>
+    /// Retrieves the column as a single byte value
+    /// </summary>
+    /// <param name="i">The index of the column to retrieve</param>
+    /// <returns>byte</returns>
+    public override byte GetByte(int i)
+    {
+#if MONO_SUPPORT_KEYREADER
+      if (i >= VisibleFieldCount && _keyInfo != null)
+        return _keyInfo.GetByte(i - VisibleFieldCount);
+#endif
+      
+      VerifyType(i, DbType.Byte);
+      return Convert.ToByte(_activeStatement._sql.GetInt32(_activeStatement, i));
+    }
+
+    /// <summary>
+    /// Retrieves a column as an array of bytes (blob)
+    /// </summary>
+    /// <param name="i">The index of the column to retrieve</param>
+    /// <param name="fieldOffset">The zero-based index of where to begin reading the data</param>
+    /// <param name="buffer">The buffer to write the bytes into</param>
+    /// <param name="bufferoffset">The zero-based index of where to begin writing into the array</param>
+    /// <param name="length">The number of bytes to retrieve</param>
+    /// <returns>The actual number of bytes written into the array</returns>
+    /// <remarks>
+    /// To determine the number of bytes in the column, pass a null value for the buffer.  The total length will be returned.
+    /// </remarks>
+    public override long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)
+    {
+#if MONO_SUPPORT_KEYREADER
+      if (i >= VisibleFieldCount && _keyInfo != null)
+        return _keyInfo.GetBytes(i - VisibleFieldCount, fieldOffset, buffer, bufferoffset, length);
+#endif
+      
+      VerifyType(i, DbType.Binary);
+      return _activeStatement._sql.GetBytes(_activeStatement, i, (int)fieldOffset, buffer, bufferoffset, length);
+    }
+
+    /// <summary>
+    /// Returns the column as a single character
+    /// </summary>
+    /// <param name="i">The index of the column to retrieve</param>
+    /// <returns>char</returns>
+    public override char GetChar(int i)
+    {
+#if MONO_SUPPORT_KEYREADER
+      if (i >= VisibleFieldCount && _keyInfo != null)
+        return _keyInfo.GetChar(i - VisibleFieldCount);
+#endif
+      
+      VerifyType(i, DbType.SByte);
+      return Convert.ToChar(_activeStatement._sql.GetInt32(_activeStatement, i));
+    }
+
+    /// <summary>
+    /// Retrieves a column as an array of chars (blob)
+    /// </summary>
+    /// <param name="i">The index of the column to retrieve</param>
+    /// <param name="fieldoffset">The zero-based index of where to begin reading the data</param>
+    /// <param name="buffer">The buffer to write the characters into</param>
+    /// <param name="bufferoffset">The zero-based index of where to begin writing into the array</param>
+    /// <param name="length">The number of bytes to retrieve</param>
+    /// <returns>The actual number of characters written into the array</returns>
+    /// <remarks>
+    /// To determine the number of characters in the column, pass a null value for the buffer.  The total length will be returned.
+    /// </remarks>
+    public override long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length)
+    {
+#if MONO_SUPPORT_KEYREADER
+      if (i >= VisibleFieldCount && _keyInfo != null)
+        return _keyInfo.GetChars(i - VisibleFieldCount, fieldoffset, buffer, bufferoffset, length);
+#endif
+      
+      VerifyType(i, DbType.String);
+      return _activeStatement._sql.GetChars(_activeStatement, i, (int)fieldoffset, buffer, bufferoffset, length);
+    }
+
+    /// <summary>
+    /// Retrieves the name of the back-end datatype of the column
+    /// </summary>
+    /// <param name="i">The index of the column to retrieve</param>
+    /// <returns>string</returns>
+    public override string GetDataTypeName(int i)
+    {
+      CheckClosed();
+
+#if MONO_SUPPORT_KEYREADER
+      if (i >= VisibleFieldCount && _keyInfo != null)
+        return _keyInfo.GetDataTypeName(i - VisibleFieldCount);
+#endif
+      
+      SqliteType typ = GetSqliteType(i);
+      if (typ.Type == DbType.Object) return SqliteConvert.SqliteTypeToType(typ).Name;
+      return _activeStatement._sql.ColumnType(_activeStatement, i, out typ.Affinity);
+    }
+
+    /// <summary>
+    /// Retrieve the column as a date/time value
+    /// </summary>
+    /// <param name="i">The index of the column to retrieve</param>
+    /// <returns>DateTime</returns>
+    public override DateTime GetDateTime(int i)
+    {
+#if MONO_SUPPORT_KEYREADER
+      if (i >= VisibleFieldCount && _keyInfo != null)
+        return _keyInfo.GetDateTime(i - VisibleFieldCount);
+#endif
+      
+      VerifyType(i, DbType.DateTime);
+      return _activeStatement._sql.GetDateTime(_activeStatement, i);
+    }
+
+    /// <summary>
+    /// Retrieve the column as a decimal value
+    /// </summary>
+    /// <param name="i">The index of the column to retrieve</param>
+    /// <returns>decimal</returns>
+    public override decimal GetDecimal(int i)
+    {
+#if MONO_SUPPORT_KEYREADER
+      if (i >= VisibleFieldCount && _keyInfo != null)
+        return _keyInfo.GetDecimal(i - VisibleFieldCount);
+#endif
+      
+      VerifyType(i, DbType.Decimal);
+      return Convert.ToDecimal(_activeStatement._sql.GetDouble(_activeStatement, i));
+    }
+
+    /// <summary>
+    /// Returns the column as a double
+    /// </summary>
+    /// <param name="i">The index of the column to retrieve</param>
+    /// <returns>double</returns>
+    public override double GetDouble(int i)
+    {
+#if MONO_SUPPORT_KEYREADER
+      if (i >= VisibleFieldCount && _keyInfo != null)
+        return _keyInfo.GetDouble(i - VisibleFieldCount);
+#endif
+      
+      VerifyType(i, DbType.Double);
+      return _activeStatement._sql.GetDouble(_activeStatement, i);
+    }
+
+    /// <summary>
+    /// Returns the .NET type of a given column
+    /// </summary>
+    /// <param name="i">The index of the column to retrieve</param>
+    /// <returns>Type</returns>
+    public override Type GetFieldType(int i)
+    {
+      CheckClosed();
+
+#if MONO_SUPPORT_KEYREADER
+      if (i >= VisibleFieldCount && _keyInfo != null)
+        return _keyInfo.GetFieldType(i - VisibleFieldCount);
+#endif
+      
+      return SqliteConvert.SqliteTypeToType(GetSqliteType(i));
+    }
+
+    /// <summary>
+    /// Returns a column as a float value
+    /// </summary>
+    /// <param name="i">The index of the column to retrieve</param>
+    /// <returns>float</returns>
+    public override float GetFloat(int i)
+    {
+#if MONO_SUPPORT_KEYREADER
+      if (i >= VisibleFieldCount && _keyInfo != null)
+        return _keyInfo.GetFloat(i - VisibleFieldCount);
+#endif
+      
+      VerifyType(i, DbType.Single);
+      return Convert.ToSingle(_activeStatement._sql.GetDouble(_activeStatement, i));
+    }
+
+    /// <summary>
+    /// Returns the column as a Guid
+    /// </summary>
+    /// <param name="i">The index of the column to retrieve</param>
+    /// <returns>Guid</returns>
+    public override Guid GetGuid(int i)
+    {
+#if MONO_SUPPORT_KEYREADER
+      if (i >= VisibleFieldCount && _keyInfo != null)
+        return _keyInfo.GetGuid(i - VisibleFieldCount);
+#endif
+      
+      TypeAffinity affinity = VerifyType(i, DbType.Guid);
+      if (affinity == TypeAffinity.Blob)
+      {
+        byte[] buffer = new byte[16];
+        _activeStatement._sql.GetBytes(_activeStatement, i, 0, buffer, 0, 16);
+        return new Guid(buffer);
+      }
+      else
+        return new Guid(_activeStatement._sql.GetText(_activeStatement, i));
+    }
+
+    /// <summary>
+    /// Returns the column as a short
+    /// </summary>
+    /// <param name="i">The index of the column to retrieve</param>
+    /// <returns>Int16</returns>
+    public override Int16 GetInt16(int i)
+    {
+#if MONO_SUPPORT_KEYREADER
+      if (i >= VisibleFieldCount && _keyInfo != null)
+        return _keyInfo.GetInt16(i - VisibleFieldCount);
+#endif
+      
+      VerifyType(i, DbType.Int16);
+      return Convert.ToInt16(_activeStatement._sql.GetInt32(_activeStatement, i));
+    }
+
+    /// <summary>
+    /// Retrieves the column as an int
+    /// </summary>
+    /// <param name="i">The index of the column to retrieve</param>
+    /// <returns>Int32</returns>
+    public override Int32 GetInt32(int i)
+    {
+#if MONO_SUPPORT_KEYREADER
+      if (i >= VisibleFieldCount && _keyInfo != null)
+        return _keyInfo.GetInt32(i - VisibleFieldCount);
+#endif
+      
+      VerifyType(i, DbType.Int32);
+      return _activeStatement._sql.GetInt32(_activeStatement, i);
+    }
+
+    /// <summary>
+    /// Retrieves the column as a long
+    /// </summary>
+    /// <param name="i">The index of the column to retrieve</param>
+    /// <returns>Int64</returns>
+    public override Int64 GetInt64(int i)
+    {
+#if MONO_SUPPORT_KEYREADER
+      if (i >= VisibleFieldCount && _keyInfo != null)
+        return _keyInfo.GetInt64(i - VisibleFieldCount);
+#endif
+      
+      VerifyType(i, DbType.Int64);
+      return _activeStatement._sql.GetInt64(_activeStatement, i);
+    }
+
+    /// <summary>
+    /// Retrieves the name of the column
+    /// </summary>
+    /// <param name="i">The index of the column to retrieve</param>
+    /// <returns>string</returns>
+    public override string GetName(int i)
+    {
+      CheckClosed();
+#if MONO_SUPPORT_KEYREADER
+      if (i >= VisibleFieldCount && _keyInfo != null)
+        return _keyInfo.GetName(i - VisibleFieldCount);
+#endif
+      
+      return _activeStatement._sql.ColumnName(_activeStatement, i);
+    }
+
+    /// <summary>
+    /// Retrieves the i of a column, given its name
+    /// </summary>
+    /// <param name="name">The name of the column to retrieve</param>
+    /// <returns>The int i of the column</returns>
+    public override int GetOrdinal(string name)
+    {
+      CheckClosed();
+      int r = _activeStatement._sql.ColumnIndex(_activeStatement, name);
+#if MONO_SUPPORT_KEYREADER
+      if (r == -1 && _keyInfo != null)
+      {
+        r = _keyInfo.GetOrdinal(name);
+        if (r > -1) r += VisibleFieldCount;
+      }
+#endif
+      
+      return r;
+    }
+
+    /// <summary>
+    /// Schema information in Sqlite is difficult to map into .NET conventions, so a lot of work must be done
+    /// to gather the necessary information so it can be represented in an ADO.NET manner.
+    /// </summary>
+    /// <returns>Returns a DataTable containing the schema information for the active SELECT statement being processed.</returns>
+    public override DataTable GetSchemaTable()
+    {
+      return GetSchemaTable(true, false);
+    }
+
+    internal DataTable GetSchemaTable(bool wantUniqueInfo, bool wantDefaultValue)
+    {
+      CheckClosed();
+
+      DataTable tbl = new DataTable("SchemaTable");
+      DataTable tblIndexes = null;
+      DataTable tblIndexColumns;
+      DataRow row;
+      string temp;
+      string strCatalog = "";
+      string strTable = "";
+      string strColumn = "";
+
+      tbl.Locale = CultureInfo.InvariantCulture;
+      tbl.Columns.Add(SchemaTableColumn.ColumnName, typeof(String));
+      tbl.Columns.Add(SchemaTableColumn.ColumnOrdinal, typeof(int));
+      tbl.Columns.Add(SchemaTableColumn.ColumnSize, typeof(int));
+      tbl.Columns.Add(SchemaTableColumn.NumericPrecision, typeof(short));
+      tbl.Columns.Add(SchemaTableColumn.NumericScale, typeof(short));
+      tbl.Columns.Add(SchemaTableColumn.IsUnique, typeof(Boolean));
+      tbl.Columns.Add(SchemaTableColumn.IsKey, typeof(Boolean));
+      tbl.Columns.Add(SchemaTableOptionalColumn.BaseServerName, typeof(string));
+      tbl.Columns.Add(SchemaTableOptionalColumn.BaseCatalogName, typeof(String));
+      tbl.Columns.Add(SchemaTableColumn.BaseColumnName, typeof(String));
+      tbl.Columns.Add(SchemaTableColumn.BaseSchemaName, typeof(String));
+      tbl.Columns.Add(SchemaTableColumn.BaseTableName, typeof(String));
+      tbl.Columns.Add(SchemaTableColumn.DataType, typeof(Type));
+      tbl.Columns.Add(SchemaTableColumn.AllowDBNull, typeof(Boolean));
+      tbl.Columns.Add(SchemaTableColumn.ProviderType, typeof(int));
+      tbl.Columns.Add(SchemaTableColumn.IsAliased, typeof(Boolean));
+      tbl.Columns.Add(SchemaTableColumn.IsExpression, typeof(Boolean));
+      tbl.Columns.Add(SchemaTableOptionalColumn.IsAutoIncrement, typeof(Boolean));
+      tbl.Columns.Add(SchemaTableOptionalColumn.IsRowVersion, typeof(Boolean));
+      tbl.Columns.Add(SchemaTableOptionalColumn.IsHidden, typeof(Boolean));
+      tbl.Columns.Add(SchemaTableColumn.IsLong, typeof(Boolean));
+      tbl.Columns.Add(SchemaTableOptionalColumn.IsReadOnly, typeof(Boolean));
+      tbl.Columns.Add(SchemaTableOptionalColumn.ProviderSpecificDataType, typeof(Type));
+      tbl.Columns.Add(SchemaTableOptionalColumn.DefaultValue, typeof(object));
+      tbl.Columns.Add("DataTypeName", typeof(string));
+
+      tbl.BeginLoadData();
+
+      for (int n = 0; n < _fieldCount; n++)
+      {
+        row = tbl.NewRow();
+
+        // Default settings for the column
+        row[SchemaTableColumn.ColumnName] = GetName(n);
+        row[SchemaTableColumn.ColumnOrdinal] = n;
+        row[SchemaTableColumn.ColumnSize] = SqliteConvert.DbTypeToColumnSize(GetSqliteType(n).Type);
+        row[SchemaTableColumn.NumericPrecision] = 255;
+        row[SchemaTableColumn.NumericScale] = 255;
+        row[SchemaTableColumn.ProviderType] = GetSqliteType(n).Type;
+        row[SchemaTableColumn.IsLong] = (GetSqliteType(n).Type == DbType.Binary);
+        row[SchemaTableColumn.AllowDBNull] = true;
+        row[SchemaTableOptionalColumn.IsReadOnly] = false;
+        row[SchemaTableOptionalColumn.IsRowVersion] = false;
+        row[SchemaTableColumn.IsUnique] = false;
+        row[SchemaTableColumn.IsKey] = false;
+        row[SchemaTableOptionalColumn.IsAutoIncrement] = false;
+        row[SchemaTableOptionalColumn.IsReadOnly] = false;
+        row[SchemaTableColumn.DataType] = GetFieldType(n);
+        row[SchemaTableOptionalColumn.IsHidden] = false;
+
+        strColumn = _command.Connection._sql.ColumnOriginalName(_activeStatement, n);
+        if (String.IsNullOrEmpty(strColumn) == false) row[SchemaTableColumn.BaseColumnName] = strColumn;
+        
+        row[SchemaTableColumn.IsExpression] = String.IsNullOrEmpty(strColumn);
+        row[SchemaTableColumn.IsAliased] = (String.Compare(GetName(n), strColumn, true, CultureInfo.InvariantCulture) != 0);
+
+        temp = _command.Connection._sql.ColumnTableName(_activeStatement, n);
+        if (String.IsNullOrEmpty(temp) == false) row[SchemaTableColumn.BaseTableName] = temp;
+
+        temp = _command.Connection._sql.ColumnDatabaseName(_activeStatement, n);
+        if (String.IsNullOrEmpty(temp) == false) row[SchemaTableOptionalColumn.BaseCatalogName] = temp;
+
+        string dataType = null;
+        // If we have a table-bound column, extract the extra information from it
+        if (String.IsNullOrEmpty(strColumn) == false)
+        {
+          string collSeq;
+          bool bNotNull;
+          bool bPrimaryKey;
+          bool bAutoIncrement;
+          string[] arSize;
+
+          // Get the column meta data
+          _command.Connection._sql.ColumnMetaData(
+            (string)row[SchemaTableOptionalColumn.BaseCatalogName],
+            (string)row[SchemaTableColumn.BaseTableName],
+            strColumn,
+            out dataType, out collSeq, out bNotNull, out bPrimaryKey, out bAutoIncrement);
+
+          if (bNotNull || bPrimaryKey) row[SchemaTableColumn.AllowDBNull] = false;
+
+          row[SchemaTableColumn.IsKey] = bPrimaryKey;
+          row[SchemaTableOptionalColumn.IsAutoIncrement] = bAutoIncrement;
+
+          // For types like varchar(50) and such, extract the size
+          arSize = dataType.Split('(');
+          if (arSize.Length > 1)
+          {
+            dataType = arSize[0];
+            arSize = arSize[1].Split(')');
+            if (arSize.Length > 1)
+            {
+              arSize = arSize[0].Split(',', '.');
+              if (GetSqliteType(n).Type == DbType.String || GetSqliteType(n).Type == DbType.Binary)
+              {
+                row[SchemaTableColumn.ColumnSize] = Convert.ToInt32(arSize[0], CultureInfo.InvariantCulture);
+              }
+              else
+              {
+                row[SchemaTableColumn.NumericPrecision] = Convert.ToInt32(arSize[0], CultureInfo.InvariantCulture);
+                if (arSize.Length > 1)
+                  row[SchemaTableColumn.NumericScale] = Convert.ToInt32(arSize[1], CultureInfo.InvariantCulture);
+              }
+            }
+          }
+
+          if (wantDefaultValue)
+          {
+            // Determine the default value for the column, which sucks because we have to query the schema for each column
+            using (SqliteCommand cmdTable = new SqliteCommand(String.Format(CultureInfo.InvariantCulture, "PRAGMA [{0}].TABLE_INFO([{1}])",
+              row[SchemaTableOptionalColumn.BaseCatalogName],
+              row[SchemaTableColumn.BaseTableName]
+              ), _command.Connection))
+            using (DbDataReader rdTable = cmdTable.ExecuteReader())
+            {
+              // Find the matching column
+              while (rdTable.Read())
+              {
+                if (String.Compare((string)row[SchemaTableColumn.BaseColumnName], rdTable.GetString(1), true, CultureInfo.InvariantCulture) == 0)
+                {
+                  if (rdTable.IsDBNull(4) == false)
+                    row[SchemaTableOptionalColumn.DefaultValue] = rdTable[4];
+
+                  break;
+                }
+              }
+            }
+          }
+
+          // Determine IsUnique properly, which is a pain in the butt!
+          if (wantUniqueInfo)
+          {
+            if ((string)row[SchemaTableOptionalColumn.BaseCatalogName] != strCatalog
+              || (string)row[SchemaTableColumn.BaseTableName] != strTable)
+            {
+              strCatalog = (string)row[SchemaTableOptionalColumn.BaseCatalogName];
+              strTable = (string)row[SchemaTableColumn.BaseTableName];
+
+              tblIndexes = _command.Connection.GetSchema("Indexes", new string[] {
+                (string)row[SchemaTableOptionalColumn.BaseCatalogName],
+                null,
+                (string)row[SchemaTableColumn.BaseTableName],
+                null });
+            }
+
+            foreach (DataRow rowIndexes in tblIndexes.Rows)
+            {
+              tblIndexColumns = _command.Connection.GetSchema("IndexColumns", new string[] {
+                (string)row[SchemaTableOptionalColumn.BaseCatalogName],
+                null,
+                (string)row[SchemaTableColumn.BaseTableName],
+                (string)rowIndexes["INDEX_NAME"],
+                null
+                });
+              foreach (DataRow rowColumnIndex in tblIndexColumns.Rows)
+              {
+                if (String.Compare((string)rowColumnIndex["COLUMN_NAME"], strColumn, true, CultureInfo.InvariantCulture) == 0)
+                {
+                  if (tblIndexColumns.Rows.Count == 1 && (bool)row[SchemaTableColumn.AllowDBNull] == false)
+                    row[SchemaTableColumn.IsUnique] = rowIndexes["UNIQUE"];
+
+                  break;
+                }
+              }
+            }
+          }
+        }
+        
+        if (String.IsNullOrEmpty(dataType))
+        {
+          TypeAffinity affin;
+          dataType = _activeStatement._sql.ColumnType(_activeStatement, n, out affin);
+        }
+
+        if (String.IsNullOrEmpty(dataType) == false)
+          row["DataTypeName"] = dataType;
+
+        tbl.Rows.Add(row);
+      }
+
+#if MONO_SUPPORT_KEYREADER
+      if (_keyInfo != null)
+        _keyInfo.AppendSchemaTable(tbl);
+#endif
+      
+      tbl.AcceptChanges();
+      tbl.EndLoadData();
+
+      return tbl;
+    }
+
+    /// <summary>
+    /// Retrieves the column as a string
+    /// </summary>
+    /// <param name="i">The index of the column to retrieve</param>
+    /// <returns>string</returns>
+    public override string GetString(int i)
+    {
+#if MONO_SUPPORT_KEYREADER
+      if (i >= VisibleFieldCount && _keyInfo != null)
+        return _keyInfo.GetString(i - VisibleFieldCount);
+#endif
+      
+      VerifyType(i, DbType.String);
+      return _activeStatement._sql.GetText(_activeStatement, i);
+    }
+
+    /// <summary>
+    /// Retrieves the column as an object corresponding to the underlying datatype of the column
+    /// </summary>
+    /// <param name="i">The index of the column to retrieve</param>
+    /// <returns>object</returns>
+    public override object GetValue(int i)
+    {
+      CheckClosed();
+
+#if MONO_SUPPORT_KEYREADER
+      if (i >= VisibleFieldCount && _keyInfo != null)
+        return _keyInfo.GetValue(i - VisibleFieldCount);
+#endif
+      SqliteType typ = GetSqliteType(i);
+      typ.Affinity = _activeStatement._sql.ColumnAffinity(_activeStatement, i);
+      return _activeStatement._sql.GetValue(_activeStatement, i, ref typ);
+    }
+
+    /// <summary>
+    /// Retreives the values of multiple columns, up to the size of the supplied array
+    /// </summary>
+    /// <param name="values">The array to fill with values from the columns in the current resultset</param>
+    /// <returns>The number of columns retrieved</returns>
+    public override int GetValues(object[] values)
+    {
+      int nMax = FieldCount;
+      if (values.Length < nMax) nMax = values.Length;
+
+      for (int n = 0; n < nMax; n++)
+      {
+        values[n] = GetValue(n);
+      }
+
+      return nMax;
+    }
+
+    /// <summary>
+    /// Returns True if the resultset has rows that can be fetched
+    /// </summary>
+    public override bool HasRows
+    {
+      get
+      {
+        CheckClosed();
+        return (_readingState != 1);
+      }
+    }
+
+    /// <summary>
+    /// Returns True if the data reader is closed
+    /// </summary>
+    public override bool IsClosed
+    {
+      get { return (_command == null); }
+    }
+
+    /// <summary>
+    /// Returns True if the specified column is null
+    /// </summary>
+    /// <param name="i">The index of the column to retrieve</param>
+    /// <returns>True or False</returns>
+    public override bool IsDBNull(int i)
+    {
+      CheckClosed();
+#if MONO_SUPPORT_KEYREADER
+      if (i >= VisibleFieldCount && _keyInfo != null)
+        return _keyInfo.IsDBNull(i - VisibleFieldCount);
+#endif
+      return _activeStatement._sql.IsNull(_activeStatement, i);
+    }
+
+    /// <summary>
+    /// Moves to the next resultset in multiple row-returning SQL command.
+    /// </summary>
+    /// <returns>True if the command was successful and a new resultset is available, False otherwise.</returns>
+    public override bool NextResult()
+    {
+      CheckClosed();
+
+      SqliteStatement stmt = null;
+      int fieldCount;
+
+      while (true)
+      {
+        if (_activeStatement != null && stmt == null)
+        {
+          // Reset the previously-executed statement
+          _activeStatement._sql.Reset(_activeStatement);
+          
+          // If we're only supposed to return a single rowset, step through all remaining statements once until
+          // they are all done and return false to indicate no more resultsets exist.
+          if ((_commandBehavior & CommandBehavior.SingleResult) != 0)
+          {
+            for (; ; )
+            {
+              stmt = _command.GetStatement(_activeStatementIndex + 1);
+              if (stmt == null) break;
+              _activeStatementIndex++;
+
+              stmt._sql.Step(stmt);
+              if (stmt._sql.ColumnCount(stmt) == 0)
+              {
+                if (_rowsAffected == -1) _rowsAffected = 0;
+                _rowsAffected += stmt._sql.Changes;
+              }
+              stmt._sql.Reset(stmt); // Gotta reset after every step to release any locks and such!
+            }
+            return false;
+          }
+        }
+
+        // Get the next statement to execute
+        stmt = _command.GetStatement(_activeStatementIndex + 1);
+
+        // If we've reached the end of the statements, return false, no more resultsets
+        if (stmt == null)
+          return false;
+
+        // If we were on a current resultset, set the state to "done reading" for it
+        if (_readingState < 1)
+          _readingState = 1;
+
+        _activeStatementIndex++;
+
+        fieldCount = stmt._sql.ColumnCount(stmt);
+
+        // If the statement is not a select statement or we're not retrieving schema only, then perform the initial step
+        if ((_commandBehavior & CommandBehavior.SchemaOnly) == 0 || fieldCount == 0)
+        {
+          if (stmt._sql.Step(stmt))
+          {
+            _readingState = -1;
+          }
+          else if (fieldCount == 0) // No rows returned, if fieldCount is zero, skip to the next statement
+          {
+            if (_rowsAffected == -1) _rowsAffected = 0;
+            _rowsAffected += stmt._sql.Changes;
+            stmt._sql.Reset(stmt);
+            continue; // Skip this command and move to the next, it was not a row-returning resultset
+          }
+          else // No rows, fieldCount is non-zero so stop here
+          {
+            _readingState = 1; // This command returned columns but no rows, so return true, but HasRows = false and Read() returns false
+          }
+        }
+
+        // Ahh, we found a row-returning resultset eligible to be returned!
+        _activeStatement = stmt;
+        _fieldCount = fieldCount;
+        _fieldTypeArray = null;
+
+        if ((_commandBehavior & CommandBehavior.KeyInfo) != 0)
+          LoadKeyInfo();
+
+        return true;
+      }
+    }
+
+    /// <summary>
+    /// Retrieves the SqliteType for a given column, and caches it to avoid repetetive interop calls.
+    /// </summary>
+    /// <param name="i">The index of the column to retrieve</param>
+    /// <returns>A SqliteType structure</returns>
+    private SqliteType GetSqliteType(int i)
+    {
+      if (_fieldTypeArray == null) _fieldTypeArray = new SqliteType[VisibleFieldCount];
+
+      if (_fieldTypeArray[i].Affinity == TypeAffinity.Uninitialized || _fieldTypeArray[i].Affinity == TypeAffinity.Null)
+        _fieldTypeArray[i].Type = SqliteConvert.TypeNameToDbType(_activeStatement._sql.ColumnType(_activeStatement, i, out _fieldTypeArray[i].Affinity));
+      return _fieldTypeArray[i];
+    }
+
+    /// <summary>
+    /// Reads the next row from the resultset
+    /// </summary>
+    /// <returns>True if a new row was successfully loaded and is ready for processing</returns>
+    public override bool Read()
+    {
+      CheckClosed();
+
+      if (_readingState == -1) // First step was already done at the NextResult() level, so don't step again, just return true.
+      {
+        _readingState = 0;
+        return true;
+      }
+      else if (_readingState == 0) // Actively reading rows
+      {
+        if (_activeStatement._sql.Step(_activeStatement) == true)
+        {
+#if MONO_SUPPORT_KEYREADER
+          if (_keyInfo != null)
+            _keyInfo.Reset();
+#endif
+	  
+          return true;
+        }
+
+        _readingState = 1; // Finished reading rows
+      }
+
+      return false;
+    }
+
+    /// <summary>
+    /// Retrieve the count of records affected by an update/insert command.  Only valid once the data reader is closed!
+    /// </summary>
+    public override int RecordsAffected
+    {
+      get { return _rowsAffected; }
+    }
+
+    /// <summary>
+    /// Indexer to retrieve data from a column given its name
+    /// </summary>
+    /// <param name="name">The name of the column to retrieve data for</param>
+    /// <returns>The value contained in the column</returns>
+    public override object this[string name]
+    {
+      get { return GetValue(GetOrdinal(name)); }
+    }
+
+    /// <summary>
+    /// Indexer to retrieve data from a column given its i
+    /// </summary>
+    /// <param name="i">The index of the column to retrieve</param>
+    /// <returns>The value contained in the column</returns>
+    public override object this[int i]
+    {
+      get { return GetValue(i); }
+    }
+
+    private void LoadKeyInfo()
+    {
+#if MONO_SUPPORT_KEYREADER
+      if (_keyInfo != null)
+        _keyInfo.Dispose();
+
+      _keyInfo = new SqliteKeyReader(_command.Connection, this, _activeStatement);
+#endif
+    }
+  }
+}
+#endif

Added: trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteEnlistment.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteEnlistment.cs	Wed Feb  4 04:24:49 2009
@@ -0,0 +1,127 @@
+//
+// Mono.Data.Sqlite.SQLiteEnlistment.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
+#if !PLATFORM_COMPACTFRAMEWORK
+namespace Mono.Data.Sqlite
+{
+  using System;
+  using System.Data;
+  using System.Data.Common;
+  using System.Transactions;
+
+  internal class SqliteEnlistment : IEnlistmentNotification
+  {
+    internal SqliteTransaction _transaction;
+    internal Transaction _scope;
+    internal bool _disposeConnection;
+
+    internal SqliteEnlistment(SqliteConnection cnn, Transaction scope)
+    {
+      _transaction = cnn.BeginTransaction();
+      _scope = scope;
+      _disposeConnection = false;
+
+      _scope.EnlistVolatile(this, System.Transactions.EnlistmentOptions.None);
+    }
+
+    private void Cleanup(SqliteConnection cnn)
+    {
+      if (_disposeConnection)
+        cnn.Dispose();
+
+      _transaction = null;
+      _scope = null;
+    }
+
+    #region IEnlistmentNotification Members
+
+    public void Commit(Enlistment enlistment)
+    {
+      SqliteConnection cnn = _transaction.Connection;
+      cnn._enlistment = null;
+
+      try
+      {
+        _transaction.IsValid(true);
+        _transaction.Connection._transactionLevel = 1;
+        _transaction.Commit();
+
+        enlistment.Done();
+      }
+      finally
+      {
+        Cleanup(cnn);
+      }
+    }
+
+    public void InDoubt(Enlistment enlistment)
+    {
+      enlistment.Done();
+    }
+
+    public void Prepare(PreparingEnlistment preparingEnlistment)
+    {
+      if (_transaction.IsValid(false) == false)
+        preparingEnlistment.ForceRollback();
+      else
+        preparingEnlistment.Prepared();
+    }
+
+    public void Rollback(Enlistment enlistment)
+    {
+      SqliteConnection cnn = _transaction.Connection;
+      cnn._enlistment = null;
+
+      try
+      {
+        _transaction.Rollback();
+        enlistment.Done();
+      }
+      finally
+      {
+        Cleanup(cnn);
+      }
+    }
+
+    #endregion
+  }
+}
+#endif // !PLATFORM_COMPACT_FRAMEWORK
+#endif

Added: trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteException.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteException.cs	Wed Feb  4 04:24:49 2009
@@ -0,0 +1,293 @@
+//
+// Mono.Data.Sqlite.SQLiteException.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.Collections.Generic;
+  using System.Text;
+  using System.Data.Common;
+
+#if !PLATFORM_COMPACTFRAMEWORK
+  using System.Runtime.Serialization;
+#endif
+
+  /// <summary>
+  /// Sqlite exception class.
+  /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+  [Serializable]
+  public class SqliteException : DbException
+#else
+  public class SqliteException : Exception
+#endif
+  {
+    private SqliteErrorCode _errorCode;
+
+#if !PLATFORM_COMPACTFRAMEWORK
+    private SqliteException(SerializationInfo info, StreamingContext context)
+      : base(info, context)
+    {
+    }
+#endif
+
+    /// <summary>
+    /// Public constructor for generating a Sqlite error given the base error code
+    /// </summary>
+    /// <param name="errorCode">The Sqlite error code to report</param>
+    /// <param name="extendedInformation">Extra text to go along with the error message text</param>
+    public SqliteException(int errorCode, string extendedInformation)
+      : base(GetStockErrorMessage(errorCode, extendedInformation))
+    {
+      _errorCode = (SqliteErrorCode)errorCode;
+    }
+
+    /// <summary>
+    /// Various public constructors that just pass along to the base Exception
+    /// </summary>
+    /// <param name="message">Passed verbatim to Exception</param>
+    public SqliteException(string message)
+      : base(message)
+    {
+    }
+
+    /// <summary>
+    /// Various public constructors that just pass along to the base Exception
+    /// </summary>
+    public SqliteException()
+    {
+    }
+
+    /// <summary>
+    /// Various public constructors that just pass along to the base Exception
+    /// <param name="message">Passed to Exception</param>
+    /// <param name="innerException">Passed to Exception</param>
+    /// </summary>
+    public SqliteException(string message, Exception innerException)
+      : base(message, innerException)
+    {
+    }
+
+    /// <summary>
+    /// Retrieves the underlying Sqlite error code for this exception
+    /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+    public new SqliteErrorCode ErrorCode
+#else
+    public SqliteErrorCode ErrorCode
+#endif
+    {
+      get { return _errorCode; }
+    }
+
+    /// <summary>
+    /// Initializes the exception class with the Sqlite error code.
+    /// </summary>
+    /// <param name="errorCode">The Sqlite error code</param>
+    /// <param name="errorMessage">A detailed error message</param>
+    /// <returns>An error message string</returns>
+    private static string GetStockErrorMessage(int errorCode, string errorMessage)
+    {
+      if (errorMessage == null) errorMessage = "";
+
+      if (errorMessage.Length > 0)
+        errorMessage = "\r\n" + errorMessage;
+
+      if (errorCode < 0 || errorCode >= _errorMessages.Length)
+        errorCode = 1;
+
+      return _errorMessages[errorCode] + errorMessage;
+    }
+
+    private static string[] _errorMessages = {
+      "Sqlite OK",
+      "Sqlite error",
+      "An internal logic error in Sqlite",
+      "Access permission denied",
+      "Callback routine requested an abort",
+      "The database file is locked",
+      "A table in the database is locked",
+      "malloc() failed",
+      "Attempt to write a read-only database",
+      "Operation terminated by sqlite3_interrupt()",
+      "Some kind of disk I/O error occurred",
+      "The database disk image is malformed",
+      "Table or record not found",
+      "Insertion failed because the database is full",
+      "Unable to open the database file",
+      "Database lock protocol error",
+      "Database is empty",
+      "The database schema changed",
+      "Too much data for one row of a table",
+      "Abort due to constraint violation",
+      "Data type mismatch",
+      "Library used incorrectly",
+      "Uses OS features not supported on host",
+      "Authorization denied",
+      "Auxiliary database format error",
+      "2nd parameter to sqlite3_bind() out of range",
+      "File opened that is not a database file",
+    };
+  }
+
+  /// <summary>
+  /// Sqlite error codes
+  /// </summary>
+  public enum SqliteErrorCode
+  {
+    /// <summary>
+    /// Success
+    /// </summary>
+    Ok = 0,
+    /// <summary>
+    /// SQL error or missing database
+    /// </summary>
+    Error,
+    /// <summary>
+    /// Internal logic error in Sqlite
+    /// </summary>
+    Internal,
+    /// <summary>
+    /// Access permission denied
+    /// </summary>
+    Perm,
+    /// <summary>
+    /// Callback routine requested an abort
+    /// </summary>
+    Abort,
+    /// <summary>
+    /// The database file is locked
+    /// </summary>
+    Busy,
+    /// <summary>
+    /// A table in the database is locked
+    /// </summary>
+    Locked,
+    /// <summary>
+    /// malloc() failed
+    /// </summary>
+    NoMem,
+    /// <summary>
+    /// Attempt to write a read-only database
+    /// </summary>
+    ReadOnly,
+    /// <summary>
+    /// Operation terminated by sqlite3_interrupt()
+    /// </summary>
+    Interrupt,
+    /// <summary>
+    /// Some kind of disk I/O error occurred
+    /// </summary>
+    IOErr,
+    /// <summary>
+    /// The database disk image is malformed
+    /// </summary>
+    Corrupt,
+    /// <summary>
+    /// Table or record not found
+    /// </summary>
+    NotFound,
+    /// <summary>
+    /// Insertion failed because database is full
+    /// </summary>
+    Full,
+    /// <summary>
+    /// Unable to open the database file
+    /// </summary>
+    CantOpen,
+    /// <summary>
+    /// Database lock protocol error
+    /// </summary>
+    Protocol,
+    /// <summary>
+    /// Database is empty
+    /// </summary>
+    Empty,
+    /// <summary>
+    /// The database schema changed
+    /// </summary>
+    Schema,
+    /// <summary>
+    /// Too much data for one row of a table
+    /// </summary>
+    TooBig,
+    /// <summary>
+    /// Abort due to constraint violation
+    /// </summary>
+    Constraint,
+    /// <summary>
+    /// Data type mismatch
+    /// </summary>
+    Mismatch,
+    /// <summary>
+    /// Library used incorrectly
+    /// </summary>
+    Misuse,
+    /// <summary>
+    /// Uses OS features not supported on host
+    /// </summary>
+    NOLFS,
+    /// <summary>
+    /// Authorization denied
+    /// </summary>
+    Auth,
+    /// <summary>
+    /// Auxiliary database format error
+    /// </summary>
+    Format,
+    /// <summary>
+    /// 2nd parameter to sqlite3_bind out of range
+    /// </summary>
+    Range,
+    /// <summary>
+    /// File opened that is not a database file
+    /// </summary>
+    NotADatabase,
+    /// <summary>
+    /// sqlite3_step() has another row ready
+    /// </summary>
+    Row = 100,
+    /// <summary>
+    /// sqlite3_step() has finished executing
+    /// </summary>
+    Done = 101,
+  }
+}
+#endif

Added: trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteFactory.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteFactory.cs	Wed Feb  4 04:24:49 2009
@@ -0,0 +1,113 @@
+//
+// Mono.Data.Sqlite.SQLiteFactory.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.Common;
+
+#if !PLATFORM_COMPACTFRAMEWORK
+  /// <summary>
+  /// Sqlite implementation of DbProviderFactory.
+  /// </summary>
+  public sealed class SqliteFactory : DbProviderFactory
+  {
+    /// <summary>
+    /// Static instance member which returns an instanced SqliteFactory class.
+    /// </summary>
+    public static readonly SqliteFactory Instance = new SqliteFactory();
+
+    /// <summary>
+    /// Returns a new SqliteCommand object.
+    /// </summary>
+    /// <returns>A SqliteCommand object.</returns>
+    public override DbCommand CreateCommand()
+    {
+      return new SqliteCommand();
+    }
+
+    /// <summary>
+    /// Returns a new SqliteCommandBuilder object.
+    /// </summary>
+    /// <returns>A SqliteCommandBuilder object.</returns>
+    public override DbCommandBuilder CreateCommandBuilder()
+    {
+      return new SqliteCommandBuilder();
+    }
+
+    /// <summary>
+    /// Creates a new SqliteConnection.
+    /// </summary>
+    /// <returns>A SqliteConnection object.</returns>
+    public override DbConnection CreateConnection()
+    {
+      return new SqliteConnection();
+    }
+
+    /// <summary>
+    /// Creates a new SqliteConnectionStringBuilder.
+    /// </summary>
+    /// <returns>A SqliteConnectionStringBuilder object.</returns>
+    public override DbConnectionStringBuilder CreateConnectionStringBuilder()
+    {
+      return new SqliteConnectionStringBuilder();
+    }
+
+    /// <summary>
+    /// Creates a new SqliteDataAdapter.
+    /// </summary>
+    /// <returns>A SqliteDataAdapter object.</returns>
+    public override DbDataAdapter CreateDataAdapter()
+    {
+      return new SqliteDataAdapter();
+    }
+
+    /// <summary>
+    /// Creates a new SqliteParameter.
+    /// </summary>
+    /// <returns>A SqliteParameter object.</returns>
+    public override DbParameter CreateParameter()
+    {
+      return new SqliteParameter();
+    }
+  }
+#endif
+}
+#endif

Added: trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteFunction.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteFunction.cs	Wed Feb  4 04:24:49 2009
@@ -0,0 +1,557 @@
+//
+// Mono.Data.Sqlite.SQLiteFunction.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.Collections;
+  using System.Collections.Generic;
+  using System.Runtime.InteropServices;
+  using System.Globalization;
+
+  /// <summary>
+  /// The type of user-defined function to declare
+  /// </summary>
+  public enum FunctionType
+  {
+    /// <summary>
+    /// Scalar functions are designed to be called and return a result immediately.  Examples include ABS(), Upper(), Lower(), etc.
+    /// </summary>
+    Scalar = 0,
+    /// <summary>
+    /// Aggregate functions are designed to accumulate data until the end of a call and then return a result gleaned from the accumulated data.
+    /// Examples include SUM(), COUNT(), AVG(), etc.
+    /// </summary>
+    Aggregate = 1,
+    /// <summary>
+    /// Collation sequences are used to sort textual data in a custom manner, and appear in an ORDER BY clause.  Typically text in an ORDER BY is
+    /// sorted using a straight case-insensitive comparison function.  Custom collating sequences can be used to alter the behavior of text sorting
+    /// in a user-defined manner.
+    /// </summary>
+    Collation = 2,
+  }
+
+  /// <summary>
+  /// An internal callback delegate declaration.
+  /// </summary>
+  /// <param name="context">Raw context pointer for the user function</param>
+  /// <param name="nArgs">Count of arguments to the function</param>
+  /// <param name="argsptr">A pointer to the array of argument pointers</param>
+  internal delegate void SqliteCallback(IntPtr context, int nArgs, IntPtr argsptr);
+  /// <summary>
+  /// An internal callback delegate declaration.
+  /// </summary>
+  /// <param name="context">Raw context pointer for the user function</param>
+  internal delegate void SqliteFinalCallback(IntPtr context);
+  /// <summary>
+  /// Internal callback delegate for implementing collation sequences
+  /// </summary>
+  /// <param name="len1">Length of the string pv1</param>
+  /// <param name="pv1">Pointer to the first string to compare</param>
+  /// <param name="len2">Length of the string pv2</param>
+  /// <param name="pv2">Pointer to the second string to compare</param>
+  /// <returns>Returns -1 if the first string is less than the second.  0 if they are equal, or 1 if the first string is greater
+  /// than the second.</returns>
+  internal delegate int SqliteCollation(int len1, IntPtr pv1, int len2, IntPtr pv2);
+
+  /// <summary>
+  /// This abstract class is designed to handle user-defined functions easily.  An instance of the derived class is made for each
+  /// connection to the database.
+  /// </summary>
+  /// <remarks>
+  /// Although there is one instance of a class derived from SqliteFunction per database connection, the derived class has no access
+  /// to the underlying connection.  This is necessary to deter implementers from thinking it would be a good idea to make database
+  /// calls during processing.
+  /// 
+  /// It is important to distinguish between a per-connection instance, and a per-SQL statement context.  One instance of this class
+  /// services all SQL statements being stepped through on that connection, and there can be many.  One should never store per-statement
+  /// information in member variables of user-defined function classes.
+  /// 
+  /// For aggregate functions, always create and store your per-statement data in the contextData object on the 1st step.  This data will
+  /// be automatically freed for you (and Dispose() called if the item supports IDisposable) when the statement completes.
+  /// </remarks>
+  public abstract class SqliteFunction : IDisposable
+  {
+    /// <summary>
+    /// The base connection this function is attached to
+    /// </summary>
+    private SqliteBase              _base;
+    /// <summary>
+    /// Internal array used to keep track of aggregate function context data
+    /// </summary>
+    private Dictionary<long, object> _contextDataList;
+
+    /// <summary>
+    /// Holds a reference to the callback function for user functions
+    /// </summary>
+    private SqliteCallback  _InvokeFunc;
+    /// <summary>
+    /// Holds a reference to the callbakc function for stepping in an aggregate function
+    /// </summary>
+    private SqliteCallback  _StepFunc;
+    /// <summary>
+    /// Holds a reference to the callback function for finalizing an aggregate function
+    /// </summary>
+    private SqliteFinalCallback  _FinalFunc;
+    /// <summary>
+    /// Holds a reference to the callback function for collation sequences
+    /// </summary>
+    private SqliteCollation _CompareFunc;
+
+    /// <summary>
+    /// This static list contains all the user-defined functions declared using the proper attributes.
+    /// </summary>
+    private static List<SqliteFunctionAttribute> _registeredFunctions = new List<SqliteFunctionAttribute>();
+
+    /// <summary>
+    /// Internal constructor, initializes the function's internal variables.
+    /// </summary>
+    protected SqliteFunction()
+    {
+      _contextDataList = new Dictionary<long, object>();
+    }
+
+    /// <summary>
+    /// Returns a reference to the underlying connection's SqliteConvert class, which can be used to convert
+    /// strings and DateTime's into the current connection's encoding schema.
+    /// </summary>
+    public SqliteConvert SqliteConvert
+    {
+      get
+      {
+        return _base;
+      }
+    }
+
+    /// <summary>
+    /// Scalar functions override this method to do their magic.
+    /// </summary>
+    /// <remarks>
+    /// Parameters passed to functions have only an affinity for a certain data type, there is no underlying schema available
+    /// to force them into a certain type.  Therefore the only types you will ever see as parameters are
+    /// DBNull.Value, Int64, Double, String or byte[] array.
+    /// </remarks>
+    /// <param name="args">The arguments for the command to process</param>
+    /// <returns>You may return most simple types as a return value, null or DBNull.Value to return null, DateTime, or
+    /// you may return an Exception-derived class if you wish to return an error to Sqlite.  Do not actually throw the error,
+    /// just return it!</returns>
+    public virtual object Invoke(object[] args)
+    {
+      return null;
+    }
+
+    /// <summary>
+    /// Aggregate functions override this method to do their magic.
+    /// </summary>
+    /// <remarks>
+    /// Typically you'll be updating whatever you've placed in the contextData field and returning as quickly as possible.
+    /// </remarks>
+    /// <param name="args">The arguments for the command to process</param>
+    /// <param name="stepNumber">The 1-based step number.  This is incrememted each time the step method is called.</param>
+    /// <param name="contextData">A placeholder for implementers to store contextual data pertaining to the current context.</param>
+    public virtual void Step(object[] args, int stepNumber, ref object contextData)
+    {
+    }
+
+    /// <summary>
+    /// Aggregate functions override this method to finish their aggregate processing.
+    /// </summary>
+    /// <remarks>
+    /// If you implemented your aggregate function properly,
+    /// you've been recording and keeping track of your data in the contextData object provided, and now at this stage you should have
+    /// all the information you need in there to figure out what to return.
+    /// NOTE:  It is possible to arrive here without receiving a previous call to Step(), in which case the contextData will
+    /// be null.  This can happen when no rows were returned.  You can either return null, or 0 or some other custom return value
+    /// if that is the case.
+    /// </remarks>
+    /// <param name="contextData">Your own assigned contextData, provided for you so you can return your final results.</param>
+    /// <returns>You may return most simple types as a return value, null or DBNull.Value to return null, DateTime, or
+    /// you may return an Exception-derived class if you wish to return an error to Sqlite.  Do not actually throw the error,
+    /// just return it!
+    /// </returns>
+    public virtual object Final(object contextData)
+    {
+      return null;
+    }
+
+    /// <summary>
+    /// User-defined collation sequences override this method to provide a custom string sorting algorithm.
+    /// </summary>
+    /// <param name="param1">The first string to compare</param>
+    /// <param name="param2">The second strnig to compare</param>
+    /// <returns>1 if param1 is greater than param2, 0 if they are equal, or -1 if param1 is less than param2</returns>
+    public virtual int Compare(string param1, string param2)
+    {
+      return 0;
+    }
+
+    /// <summary>
+    /// Converts an IntPtr array of context arguments to an object array containing the resolved parameters the pointers point to.
+    /// </summary>
+    /// <remarks>
+    /// Parameters passed to functions have only an affinity for a certain data type, there is no underlying schema available
+    /// to force them into a certain type.  Therefore the only types you will ever see as parameters are
+    /// DBNull.Value, Int64, Double, String or byte[] array.
+    /// </remarks>
+    /// <param name="nArgs">The number of arguments</param>
+    /// <param name="argsptr">A pointer to the array of arguments</param>
+    /// <returns>An object array of the arguments once they've been converted to .NET values</returns>
+    internal object[] ConvertParams(int nArgs, IntPtr argsptr)
+    {
+      object[] parms = new object[nArgs];
+#if !PLATFORM_COMPACTFRAMEWORK
+      IntPtr[] argint = new IntPtr[nArgs];
+#else
+      int[] argint = new int[nArgs];
+#endif
+      Marshal.Copy(argsptr, argint, 0, nArgs);
+
+      for (int n = 0; n < nArgs; n++)
+      {
+        switch (_base.GetParamValueType((IntPtr)argint[n]))
+        {
+          case TypeAffinity.Null:
+            parms[n] = DBNull.Value;
+            break;
+          case TypeAffinity.Int64:
+            parms[n] = _base.GetParamValueInt64((IntPtr)argint[n]);
+            break;
+          case TypeAffinity.Double:
+            parms[n] = _base.GetParamValueDouble((IntPtr)argint[n]);
+            break;
+          case TypeAffinity.Text:
+            parms[n] = _base.GetParamValueText((IntPtr)argint[n]);
+            break;
+          case TypeAffinity.Blob:
+            {
+              int x;
+              byte[] blob;
+
+              x = (int)_base.GetParamValueBytes((IntPtr)argint[n], 0, null, 0, 0);
+              blob = new byte[x];
+              _base.GetParamValueBytes((IntPtr)argint[n], 0, blob, 0, x);
+              parms[n] = blob;
+            }
+            break;
+          case TypeAffinity.DateTime: // Never happens here but what the heck, maybe it will one day.
+            parms[n] = _base.ToDateTime(_base.GetParamValueText((IntPtr)argint[n]));
+            break;
+        }
+      }
+      return parms;
+    }
+
+    /// <summary>
+    /// Takes the return value from Invoke() and Final() and figures out how to return it to Sqlite's context.
+    /// </summary>
+    /// <param name="context">The context the return value applies to</param>
+    /// <param name="returnValue">The parameter to return to Sqlite</param>
+    void SetReturnValue(IntPtr context, object returnValue)
+    {
+      if (returnValue == null || returnValue == DBNull.Value)
+      {
+        _base.ReturnNull(context);
+        return;
+      }
+
+      Type t = returnValue.GetType();
+      if (t == typeof(DateTime))
+      {
+        _base.ReturnText(context, _base.ToString((DateTime)returnValue));
+        return;
+      }
+      else
+      {
+        Exception r = returnValue as Exception;
+
+        if (r != null)
+        {
+          _base.ReturnError(context, r.Message);
+          return;
+        }
+      }
+
+      switch (SqliteConvert.TypeToAffinity(t))
+      {
+        case TypeAffinity.Null:
+          _base.ReturnNull(context);
+          return;
+        case TypeAffinity.Int64:
+          _base.ReturnInt64(context, Convert.ToInt64(returnValue, CultureInfo.CurrentCulture));
+          return;
+        case TypeAffinity.Double:
+          _base.ReturnDouble(context, Convert.ToDouble(returnValue, CultureInfo.CurrentCulture));
+          return;
+        case TypeAffinity.Text:
+          _base.ReturnText(context, returnValue.ToString());
+          return;
+        case TypeAffinity.Blob:
+          _base.ReturnBlob(context, (byte[])returnValue);
+          return;
+      }
+    }
+
+    /// <summary>
+    /// Internal scalar callback function, which wraps the raw context pointer and calls the virtual Invoke() method.
+    /// </summary>
+    /// <param name="context">A raw context pointer</param>
+    /// <param name="nArgs">Number of arguments passed in</param>
+    /// <param name="argsptr">A pointer to the array of arguments</param>
+    internal void ScalarCallback(IntPtr context, int nArgs, IntPtr argsptr)
+    {
+      SetReturnValue(context, Invoke(ConvertParams(nArgs, argsptr)));
+    }
+
+    /// <summary>
+    /// Internal collation sequence function, which wraps up the raw string pointers and executes the Compare() virtual function.
+    /// </summary>
+    /// <param name="len1">Length of the string pv1</param>
+    /// <param name="ptr1">Pointer to the first string to compare</param>
+    /// <param name="len2">Length of the string pv2</param>
+    /// <param name="ptr2">Pointer to the second string to compare</param>
+    /// <returns>Returns -1 if the first string is less than the second.  0 if they are equal, or 1 if the first string is greater
+    /// than the second.</returns>
+    internal int CompareCallback(int len1, IntPtr ptr1, int len2, IntPtr ptr2)
+    {
+      return Compare(_base.ToString(ptr1), _base.ToString(ptr2));
+    }
+
+    /// <summary>
+    /// The internal aggregate Step function callback, which wraps the raw context pointer and calls the virtual Step() method.
+    /// </summary>
+    /// <remarks>
+    /// This function takes care of doing the lookups and getting the important information put together to call the Step() function.
+    /// That includes pulling out the user's contextData and updating it after the call is made.  We use a sorted list for this so
+    /// binary searches can be done to find the data.
+    /// </remarks>
+    /// <param name="context">A raw context pointer</param>
+    /// <param name="nArgs">Number of arguments passed in</param>
+    /// <param name="argsptr">A pointer to the array of arguments</param>
+    internal void StepCallback(IntPtr context, int nArgs, IntPtr argsptr)
+    {
+      int n = _base.AggregateCount(context);
+      long nAux;
+      object obj = null;
+
+      nAux = (long)_base.AggregateContext(context);
+      if (n > 1) obj = _contextDataList[nAux];
+
+      Step(ConvertParams(nArgs, argsptr), n, ref obj);
+      _contextDataList[nAux] = obj;      
+    }
+
+    /// <summary>
+    /// An internal aggregate Final function callback, which wraps the context pointer and calls the virtual Final() method.
+    /// </summary>
+    /// <param name="context">A raw context pointer</param>
+    internal void FinalCallback(IntPtr context)
+    {
+      long n = (long)_base.AggregateContext(context);
+      object obj = null;
+
+      if (_contextDataList.ContainsKey(n))
+      {
+        obj = _contextDataList[n];
+        _contextDataList.Remove(n);
+      }
+
+      SetReturnValue(context, Final(obj));
+
+      IDisposable disp = obj as IDisposable;
+      if (disp != null) disp.Dispose();
+    }
+
+    /// <summary>
+    /// Placeholder for a user-defined disposal routine
+    /// </summary>
+    /// <param name="disposing">True if the object is being disposed explicitly</param>
+    protected virtual void Dispose(bool disposing)
+    {
+    }
+
+    /// <summary>
+    /// Disposes of any active contextData variables that were not automatically cleaned up.  Sometimes this can happen if
+    /// someone closes the connection while a DataReader is open.
+    /// </summary>
+    public void Dispose()
+    {
+      Dispose(true);
+
+      IDisposable disp;
+
+      foreach (KeyValuePair<long, object> kv in _contextDataList)
+      {
+        disp = kv.Value as IDisposable;
+        if (disp != null)
+          disp.Dispose();
+      }
+      _contextDataList.Clear();
+
+      _InvokeFunc = null;
+      _StepFunc = null;
+      _FinalFunc = null;
+      _CompareFunc = null;
+      _base = null;
+      _contextDataList = null;
+
+      GC.SuppressFinalize(this);
+    }
+
+#if !PLATFORM_COMPACTFRAMEWORK
+    /// <summary>
+    /// Using reflection, enumerate all assemblies in the current appdomain looking for classes that
+    /// have a SqliteFunctionAttribute attribute, and registering them accordingly.
+    /// </summary>
+    static SqliteFunction()
+    {
+      SqliteFunctionAttribute at;
+      System.Reflection.Assembly[] arAssemblies = System.AppDomain.CurrentDomain.GetAssemblies();
+      int w = arAssemblies.Length;
+      System.Reflection.AssemblyName sqlite = System.Reflection.Assembly.GetCallingAssembly().GetName();
+
+      for (int n = 0; n < w; n++)
+      {
+        Type[] arTypes;
+        bool found = false;
+        System.Reflection.AssemblyName[] references;
+        try
+        {
+          // Inspect only assemblies that reference SQLite
+          references = arAssemblies[n].GetReferencedAssemblies();
+          int t = references.Length;
+          for (int z = 0; z < t; z++)
+          {
+            if (references[z].Name == sqlite.Name)
+            {
+              found = true;
+              break;
+            }
+          }
+          
+          if (found == false)
+            continue;
+
+          arTypes = arAssemblies[n].GetTypes();
+        }
+        catch (System.Reflection.ReflectionTypeLoadException e)
+        {
+          arTypes = e.Types;
+        }
+
+        int v = arTypes.Length;
+        for (int x = 0; x < v; x++)
+        {
+          if (arTypes[x] == null) continue;
+
+          object[] arAtt = arTypes[x].GetCustomAttributes(typeof(SqliteFunctionAttribute), false);
+          int u = arAtt.Length;
+          for (int y = 0; y < u; y++)
+          {
+            at = arAtt[y] as SqliteFunctionAttribute;
+            if (at != null)
+            {
+              at._instanceType = arTypes[x];
+              _registeredFunctions.Add(at);
+            }
+          }
+        }
+      }
+    }
+#else
+    /// <summary>
+    /// Manual method of registering a function.  The type must still have the SqliteFunctionAttributes in order to work
+    /// properly, but this is a workaround for the Compact Framework where enumerating assemblies is not currently supported.
+    /// </summary>
+    /// <param name="typ">The type of the function to register</param>
+    public static void RegisterFunction(Type typ)
+    {
+      object[] arAtt = typ.GetCustomAttributes(typeof(SqliteFunctionAttribute), false);
+      int u = arAtt.Length;
+      SqliteFunctionAttribute at;
+
+      for (int y = 0; y < u; y++)
+      {
+        at = arAtt[y] as SqliteFunctionAttribute;
+        if (at != null)
+        {
+          at._instanceType = typ;
+          _registeredFunctions.Add(at);
+        }
+      }
+    }
+#endif
+
+    /// <summary>
+    /// Called by SqliteBase derived classes, this function binds all user-defined functions to a connection.
+    /// It is done this way so that all user-defined functions will access the database using the same encoding scheme
+    /// as the connection (UTF-8 or UTF-16).
+    /// </summary>
+    /// <param name="sqlbase">The base object on which the functions are to bind</param>
+    /// <returns>Returns an array of functions which the connection object should retain until the connection is closed.</returns>
+    internal static SqliteFunction[] BindFunctions(SqliteBase sqlbase)
+    {
+      SqliteFunction f;
+      List<SqliteFunction> lFunctions = new List<SqliteFunction>();
+
+      foreach (SqliteFunctionAttribute pr in _registeredFunctions)
+      {
+        f = (SqliteFunction)Activator.CreateInstance(pr._instanceType);
+        f._base = sqlbase;
+        f._InvokeFunc = (pr.FuncType == FunctionType.Scalar) ? new SqliteCallback(f.ScalarCallback) : null;
+        f._StepFunc = (pr.FuncType == FunctionType.Aggregate) ? new SqliteCallback(f.StepCallback) : null;
+        f._FinalFunc = (pr.FuncType == FunctionType.Aggregate) ? new SqliteFinalCallback(f.FinalCallback) : null;
+        f._CompareFunc = (pr.FuncType == FunctionType.Collation) ? new SqliteCollation(f.CompareCallback) : null;
+
+        if (pr.FuncType != FunctionType.Collation)
+          sqlbase.CreateFunction(pr.Name, pr.Arguments, f._InvokeFunc, f._StepFunc, f._FinalFunc);
+        else
+          sqlbase.CreateCollation(pr.Name, f._CompareFunc);
+        lFunctions.Add(f);
+      }
+
+      SqliteFunction[] arFunctions = new SqliteFunction[lFunctions.Count];
+      lFunctions.CopyTo(arFunctions, 0);
+
+      return arFunctions;
+
+    }
+  }
+}
+#endif

Added: trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteFunctionAttribute.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteFunctionAttribute.cs	Wed Feb  4 04:24:49 2009
@@ -0,0 +1,96 @@
+//
+// Mono.Data.Sqlite.SQLiteFunctionAttribute.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.Runtime.InteropServices;
+
+  /// <summary>
+  /// A simple custom attribute to enable us to easily find user-defined functions in
+  /// the loaded assemblies and initialize them in Sqlite as connections are made.
+  /// </summary>
+  [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
+  public class SqliteFunctionAttribute : Attribute
+  {
+    private string       _name;
+    private int          _arguments;
+    private FunctionType _functionType;
+    internal Type        _instanceType;
+
+    /// <summary>
+    /// Default constructor, initializes the internal variables for the function.
+    /// </summary>
+    public SqliteFunctionAttribute()
+    {
+      Name = "";
+      Arguments = -1;
+      FuncType = FunctionType.Scalar;
+    }
+
+    /// <summary>
+    /// The function's name as it will be used in Sqlite command text.
+    /// </summary>
+    public string Name
+    {
+      get { return _name; }
+      set { _name = value; }
+    }
+
+    /// <summary>
+    /// The number of arguments this function expects.  -1 if the number of arguments is variable.
+    /// </summary>
+    public int Arguments
+    {
+      get { return _arguments; }
+      set { _arguments = value; }
+    }
+
+    /// <summary>
+    /// The type of function this implementation will be.
+    /// </summary>
+    public FunctionType FuncType
+    {
+      get { return _functionType; }
+      set { _functionType = value; }
+    }
+  }
+}
+#endif

Added: trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteMetaDataCollectionNames.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteMetaDataCollectionNames.cs	Wed Feb  4 04:24:49 2009
@@ -0,0 +1,84 @@
+//
+// Mono.Data.Sqlite.SQLiteMetaDataCollectionNames.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;
+
+  /// <summary>
+  /// MetaDataCollections specific to Sqlite
+  /// </summary>
+  public static class SqliteMetaDataCollectionNames
+  {
+    /// <summary>
+    /// Returns a list of databases attached to the connection
+    /// </summary>
+    public static readonly string Catalogs = "Catalogs";
+    /// <summary>
+    /// Returns column information for the specified table
+    /// </summary>
+    public static readonly string Columns = "Columns";
+    /// <summary>
+    /// Returns index information for the optionally-specified table
+    /// </summary>
+    public static readonly string Indexes = "Indexes";
+    /// <summary>
+    /// Returns base columns for the given index
+    /// </summary>
+    public static readonly string IndexColumns = "IndexColumns";
+    /// <summary>
+    /// Returns the tables in the given catalog
+    /// </summary>
+    public static readonly string Tables = "Tables";
+    /// <summary>
+    /// Returns user-defined views in the given catalog
+    /// </summary>
+    public static readonly string Views = "Views";
+    /// <summary>
+    /// Returns underlying column information on the given view
+    /// </summary>
+    public static readonly string ViewColumns = "ViewColumns";
+    /// <summary>
+    /// Returns foreign key information for the given catalog
+    /// </summary>
+    public static readonly string ForeignKeys = "ForeignKeys";
+  }
+}
+#endif

Added: trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteParameter.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteParameter.cs	Wed Feb  4 04:24:49 2009
@@ -0,0 +1,481 @@
+//
+// Mono.Data.Sqlite.SQLiteParameter.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.Data.Common;
+  using System.ComponentModel;
+
+  /// <summary>
+  /// Sqlite implementation of DbParameter.
+  /// </summary>
+  public sealed class SqliteParameter : DbParameter, ICloneable
+  {
+    /// <summary>
+    /// The data type of the parameter
+    /// </summary>
+    internal int            _dbType;
+    /// <summary>
+    /// The version information for mapping the parameter
+    /// </summary>
+    private DataRowVersion _rowVersion;
+    /// <summary>
+    /// The value of the data in the parameter
+    /// </summary>
+    private Object         _objValue;
+    /// <summary>
+    /// The source column for the parameter
+    /// </summary>
+    private string         _sourceColumn;
+    /// <summary>
+    /// The column name
+    /// </summary>
+    private string         _parameterName;
+    /// <summary>
+    /// The data size, unused by Sqlite
+    /// </summary>
+    private int            _dataSize;
+
+    private bool           _nullable;
+    private bool           _nullMapping;
+
+    /// <summary>
+    /// Default constructor
+    /// </summary>
+    public SqliteParameter() 
+      : this(null, (DbType)(-1), 0, null, DataRowVersion.Current)
+    {
+    }
+
+    /// <summary>
+    /// Constructs a named parameter given the specified parameter name
+    /// </summary>
+    /// <param name="parameterName">The parameter name</param>
+    public SqliteParameter(string parameterName)
+      : this(parameterName, (DbType)(-1), 0, null, DataRowVersion.Current)
+    {
+    }
+
+    /// <summary>
+    /// Constructs a named parameter given the specified parameter name and initial value
+    /// </summary>
+    /// <param name="parameterName">The parameter name</param>
+    /// <param name="value">The initial value of the parameter</param>
+    public SqliteParameter(string parameterName, object value)
+      : this(parameterName, (DbType)(-1), 0, null, DataRowVersion.Current)
+    {
+      Value = value;
+    }
+
+    /// <summary>
+    /// Constructs a named parameter of the specified type
+    /// </summary>
+    /// <param name="parameterName">The parameter name</param>
+    /// <param name="dbType">The datatype of the parameter</param>
+    public SqliteParameter(string parameterName, DbType dbType)
+      : this(parameterName, dbType, 0, null, DataRowVersion.Current)
+    {
+    }
+
+    /// <summary>
+    /// Constructs a named parameter of the specified type and source column reference
+    /// </summary>
+    /// <param name="parameterName">The parameter name</param>
+    /// <param name="dbType">The data type</param>
+    /// <param name="sourceColumn">The source column</param>
+    public SqliteParameter(string parameterName, DbType dbType, string sourceColumn)
+      : this(parameterName, dbType, 0, sourceColumn, DataRowVersion.Current)
+    {
+    }
+
+    /// <summary>
+    /// Constructs a named parameter of the specified type, source column and row version
+    /// </summary>
+    /// <param name="parameterName">The parameter name</param>
+    /// <param name="dbType">The data type</param>
+    /// <param name="sourceColumn">The source column</param>
+    /// <param name="rowVersion">The row version information</param>
+    public SqliteParameter(string parameterName, DbType dbType, string sourceColumn, DataRowVersion rowVersion)
+      : this(parameterName, dbType, 0, sourceColumn, rowVersion)
+    {
+    }
+
+    /// <summary>
+    /// Constructs an unnamed parameter of the specified data type
+    /// </summary>
+    /// <param name="dbType">The datatype of the parameter</param>
+    public SqliteParameter(DbType dbType)
+      : this(null, dbType, 0, null, DataRowVersion.Current)
+    {
+    }
+
+    /// <summary>
+    /// Constructs an unnamed parameter of the specified data type and sets the initial value
+    /// </summary>
+    /// <param name="dbType">The datatype of the parameter</param>
+    /// <param name="value">The initial value of the parameter</param>
+    public SqliteParameter(DbType dbType, object value)
+      : this(null, dbType, 0, null, DataRowVersion.Current)
+    {
+      Value = value;
+    }
+
+    /// <summary>
+    /// Constructs an unnamed parameter of the specified data type and source column
+    /// </summary>
+    /// <param name="dbType">The datatype of the parameter</param>
+    /// <param name="sourceColumn">The source column</param>
+    public SqliteParameter(DbType dbType, string sourceColumn)
+      : this(null, dbType, 0, sourceColumn, DataRowVersion.Current)
+    {
+    }
+
+    /// <summary>
+    /// Constructs an unnamed parameter of the specified data type, source column and row version
+    /// </summary>
+    /// <param name="dbType">The data type</param>
+    /// <param name="sourceColumn">The source column</param>
+    /// <param name="rowVersion">The row version information</param>
+    public SqliteParameter(DbType dbType, string sourceColumn, DataRowVersion rowVersion)
+      : this(null, dbType, 0, sourceColumn, rowVersion)
+    {
+    }
+
+    /// <summary>
+    /// Constructs a named parameter of the specified type and size
+    /// </summary>
+    /// <param name="parameterName">The parameter name</param>
+    /// <param name="parameterType">The data type</param>
+    /// <param name="parameterSize">The size of the parameter</param>
+    public SqliteParameter(string parameterName, DbType parameterType, int parameterSize)
+      : this(parameterName, parameterType, parameterSize, null, DataRowVersion.Current)
+    {
+    }
+
+    /// <summary>
+    /// Constructs a named parameter of the specified type, size and source column
+    /// </summary>
+    /// <param name="parameterName">The name of the parameter</param>
+    /// <param name="parameterType">The data type</param>
+    /// <param name="parameterSize">The size of the parameter</param>
+    /// <param name="sourceColumn">The source column</param>
+    public SqliteParameter(string parameterName, DbType parameterType, int parameterSize, string sourceColumn)
+      : this(parameterName, parameterType, parameterSize, sourceColumn, DataRowVersion.Current)
+    {
+    }
+
+    /// <summary>
+    /// Constructs a named parameter of the specified type, size, source column and row version
+    /// </summary>
+    /// <param name="parameterName">The name of the parameter</param>
+    /// <param name="parameterType">The data type</param>
+    /// <param name="parameterSize">The size of the parameter</param>
+    /// <param name="sourceColumn">The source column</param>
+    /// <param name="rowVersion">The row version information</param>
+    public SqliteParameter(string parameterName, DbType parameterType, int parameterSize, string sourceColumn, DataRowVersion rowVersion)      
+    {
+      _parameterName = parameterName;
+      _dbType = (int)parameterType;
+      _sourceColumn = sourceColumn;
+      _rowVersion = rowVersion;
+      _objValue = null;
+      _dataSize = parameterSize;
+      _nullMapping = false;
+      _nullable = true;
+    }
+
+    private SqliteParameter(SqliteParameter source)
+      : this(source.ParameterName, (DbType)source._dbType, 0, source.Direction, source.IsNullable, 0, 0, source.SourceColumn, source.SourceVersion, source.Value)
+    {
+      _nullMapping = source._nullMapping;
+    }
+
+    /// <summary>
+    /// Constructs a named parameter of the specified type, size, source column and row version
+    /// </summary>
+    /// <param name="parameterName">The name of the parameter</param>
+    /// <param name="parameterType">The data type</param>
+    /// <param name="parameterSize">The size of the parameter</param>
+    /// <param name="direction">Only input parameters are supported in Sqlite</param>
+    /// <param name="isNullable">Ignored</param>
+    /// <param name="precision">Ignored</param>
+    /// <param name="scale">Ignored</param>
+    /// <param name="sourceColumn">The source column</param>
+    /// <param name="rowVersion">The row version information</param>
+    /// <param name="value">The initial value to assign the parameter</param>   
+#if !PLATFORM_COMPACTFRAMEWORK
+    [EditorBrowsable(EditorBrowsableState.Advanced)]
+#endif
+    public SqliteParameter(string parameterName, DbType parameterType, int parameterSize, ParameterDirection direction, bool isNullable, byte precision, byte scale, string sourceColumn, DataRowVersion rowVersion, object value)
+      : this(parameterName, parameterType, parameterSize, sourceColumn, rowVersion)
+    {
+      Direction = direction;
+      IsNullable = isNullable;
+      Value = value;
+    }
+
+    /// <summary>
+    /// Constructs a named parameter, yet another flavor
+    /// </summary>
+    /// <param name="parameterName">The name of the parameter</param>
+    /// <param name="parameterType">The data type</param>
+    /// <param name="parameterSize">The size of the parameter</param>
+    /// <param name="direction">Only input parameters are supported in Sqlite</param>
+    /// <param name="precision">Ignored</param>
+    /// <param name="scale">Ignored</param>
+    /// <param name="sourceColumn">The source column</param>
+    /// <param name="rowVersion">The row version information</param>
+    /// <param name="sourceColumnNullMapping">Whether or not this parameter is for comparing NULL's</param>
+    /// <param name="value">The intial value to assign the parameter</param>
+#if !PLATFORM_COMPACTFRAMEWORK
+    [EditorBrowsable(EditorBrowsableState.Advanced)]
+#endif
+    public SqliteParameter(string parameterName, DbType parameterType, int parameterSize, ParameterDirection direction, byte precision, byte scale, string sourceColumn, DataRowVersion rowVersion, bool sourceColumnNullMapping, object value)
+      : this(parameterName, parameterType, parameterSize, sourceColumn, rowVersion)
+    {
+      Direction = direction;
+      SourceColumnNullMapping = sourceColumnNullMapping;
+      Value = value;
+    }
+
+    /// <summary>
+    /// Constructs an unnamed parameter of the specified type and size
+    /// </summary>
+    /// <param name="parameterType">The data type</param>
+    /// <param name="parameterSize">The size of the parameter</param>
+    public SqliteParameter(DbType parameterType, int parameterSize)
+      : this(null, parameterType, parameterSize, null, DataRowVersion.Current)
+    {
+    }
+
+    /// <summary>
+    /// Constructs an unnamed parameter of the specified type, size, and source column
+    /// </summary>
+    /// <param name="parameterType">The data type</param>
+    /// <param name="parameterSize">The size of the parameter</param>
+    /// <param name="sourceColumn">The source column</param>
+    public SqliteParameter(DbType parameterType, int parameterSize, string sourceColumn)
+      : this(null, parameterType, parameterSize, sourceColumn, DataRowVersion.Current)
+    {
+    }
+
+    /// <summary>
+    /// Constructs an unnamed parameter of the specified type, size, source column and row version
+    /// </summary>
+    /// <param name="parameterType">The data type</param>
+    /// <param name="parameterSize">The size of the parameter</param>
+    /// <param name="sourceColumn">The source column</param>
+    /// <param name="rowVersion">The row version information</param>
+    public SqliteParameter(DbType parameterType, int parameterSize, string sourceColumn, DataRowVersion rowVersion)
+      : this(null, parameterType, parameterSize, sourceColumn, rowVersion)
+    {
+    }
+
+    /// <summary>
+    /// Whether or not the parameter can contain a null value
+    /// </summary>
+    public override bool IsNullable
+    {
+      get
+      {
+        return _nullable;
+      }
+      set 
+      {
+        _nullable = value;
+      }
+    }
+
+    /// <summary>
+    /// Returns the datatype of the parameter
+    /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+    [DbProviderSpecificTypeProperty(true)]
+    [RefreshProperties(RefreshProperties.All)]
+#endif
+    public override DbType DbType
+    {
+      get
+      {
+        if (_dbType == -1) return DbType.String; // Unassigned default value is String
+        return (DbType)_dbType;
+      }
+      set
+      {
+        _dbType = (int)value;
+      }
+    }
+
+    /// <summary>
+    /// Supports only input parameters
+    /// </summary>
+    public override ParameterDirection Direction
+    {
+      get
+      {
+        return ParameterDirection.Input;
+      }
+      set
+      {
+        if (value != ParameterDirection.Input)
+          throw new NotSupportedException();
+      }
+    }
+
+    /// <summary>
+    /// Returns the parameter name
+    /// </summary>
+    public override string ParameterName
+    {
+      get
+      {
+        return _parameterName;
+      }
+      set
+      {
+        _parameterName = value;
+      }
+    }
+
+    /// <summary>
+    /// Not implemented
+    /// </summary>
+    public override void ResetDbType()
+    {
+    }
+
+    /// <summary>
+    /// Returns the size of the parameter
+    /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+    [DefaultValue((int)0)]
+#endif
+    public override int Size
+    {
+      get
+      {
+        return _dataSize;
+      }
+      set
+      {
+        _dataSize = value;
+      }
+    }
+
+    /// <summary>
+    /// Gets/sets the source column
+    /// </summary>
+    public override string SourceColumn
+    {
+      get
+      {
+        return _sourceColumn;
+      }
+      set
+      {
+        _sourceColumn = value;
+      }
+    }
+
+    /// <summary>
+    /// Used by DbCommandBuilder to determine the mapping for nullable fields
+    /// </summary>
+    public override bool SourceColumnNullMapping
+    {
+      get
+      {
+        return _nullMapping;
+      }
+      set
+      {
+        _nullMapping = value;
+      }
+    }
+
+    /// <summary>
+    /// Gets and sets the row version
+    /// </summary>
+    public override DataRowVersion SourceVersion
+    {
+      get
+      {
+        return _rowVersion;
+      }
+      set
+      {
+        _rowVersion = value;
+      }
+    }
+
+    /// <summary>
+    /// Gets and sets the parameter value.  If no datatype was specified, the datatype will assume the type from the value given.
+    /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+    [TypeConverter(typeof(StringConverter)), RefreshProperties(RefreshProperties.All)]
+#endif
+    public override object Value
+    {
+      get
+      {
+        return _objValue;
+      }
+      set
+      {
+        _objValue = value;
+        if (_dbType == -1 && _objValue != null && _objValue != DBNull.Value) // If the DbType has never been assigned, try to glean one from the value's datatype 
+          _dbType = (int)SqliteConvert.TypeToDbType(_objValue.GetType());
+      }
+    }
+
+    /// <summary>
+    /// Clones a parameter
+    /// </summary>
+    /// <returns>A new, unassociated SqliteParameter</returns>
+    public object Clone()
+    {
+      SqliteParameter newparam = new SqliteParameter(this);
+
+      return newparam;
+    }
+  }
+}
+#endif

Added: trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteParameterCollection.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteParameterCollection.cs	Wed Feb  4 04:24:49 2009
@@ -0,0 +1,507 @@
+//
+// Mono.Data.Sqlite.SQLiteParameterCollection.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.Data.Common;
+  using System.Collections.Generic;
+  using System.Globalization;
+  using System.ComponentModel;
+  using System.Reflection;
+
+  /// <summary>
+  /// Sqlite implementation of DbParameterCollection.
+  /// </summary>
+#if !PLATFORM_COMPACTFRAMEWORK
+  [Editor("Microsoft.VSDesigner.Data.Design.DBParametersEditor, Microsoft.VSDesigner, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Drawing.Design.UITypeEditor, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"), ListBindable(false)]
+#endif
+  public sealed class SqliteParameterCollection : DbParameterCollection
+  {
+    /// <summary>
+    /// The underlying command to which this collection belongs
+    /// </summary>
+    private SqliteCommand         _command;
+    /// <summary>
+    /// The internal array of parameters in this collection
+    /// </summary>
+    private List<SqliteParameter> _parameterList;
+    /// <summary>
+    /// Determines whether or not all parameters have been bound to their statement(s)
+    /// </summary>
+    private bool                  _unboundFlag;
+
+    /// <summary>
+    /// Initializes the collection
+    /// </summary>
+    /// <param name="cmd">The command to which the collection belongs</param>
+    internal SqliteParameterCollection(SqliteCommand cmd)
+    {
+      _command = cmd;
+      _parameterList = new List<SqliteParameter>();
+      _unboundFlag = true;
+    }
+
+    /// <summary>
+    /// Returns true
+    /// </summary>
+    public override bool IsSynchronized
+    {
+      get { return true; }
+    }
+
+    /// <summary>
+    /// Returns false
+    /// </summary>
+    public override bool IsFixedSize
+    {
+      get { return false; }
+    }
+
+    /// <summary>
+    /// Returns false
+    /// </summary>
+    public override bool IsReadOnly
+    {
+      get { return false; }
+    }
+
+    /// <summary>
+    /// Returns null
+    /// </summary>
+    public override object SyncRoot
+    {
+      get { return null; }
+    }
+
+    /// <summary>
+    /// Retrieves an enumerator for the collection
+    /// </summary>
+    /// <returns>An enumerator for the underlying array</returns>
+    public override System.Collections.IEnumerator GetEnumerator()
+    {
+      return _parameterList.GetEnumerator();
+    }
+
+    /// <summary>
+    /// Adds a parameter to the collection
+    /// </summary>
+    /// <param name="parameterName">The parameter name</param>
+    /// <param name="parameterType">The data type</param>
+    /// <param name="parameterSize">The size of the value</param>
+    /// <param name="sourceColumn">The source column</param>
+    /// <returns>A SqliteParameter object</returns>
+    public SqliteParameter Add(string parameterName, DbType parameterType, int parameterSize, string sourceColumn)
+    {
+      SqliteParameter param = new SqliteParameter(parameterName, parameterType, parameterSize, sourceColumn);
+      Add(param);
+
+      return param;
+    }
+
+    /// <summary>
+    /// Adds a parameter to the collection
+    /// </summary>
+    /// <param name="parameterName">The parameter name</param>
+    /// <param name="parameterType">The data type</param>
+    /// <param name="parameterSize">The size of the value</param>
+    /// <returns>A SqliteParameter object</returns>
+    public SqliteParameter Add(string parameterName, DbType parameterType, int parameterSize)
+    {
+      SqliteParameter param = new SqliteParameter(parameterName, parameterType, parameterSize);
+      Add(param);
+
+      return param;
+    }
+
+    /// <summary>
+    /// Adds a parameter to the collection
+    /// </summary>
+    /// <param name="parameterName">The parameter name</param>
+    /// <param name="parameterType">The data type</param>
+    /// <returns>A SqliteParameter object</returns>
+    public SqliteParameter Add(string parameterName, DbType parameterType)
+    {
+      SqliteParameter param = new SqliteParameter(parameterName, parameterType);
+      Add(param);
+
+      return param;
+    }
+
+    /// <summary>
+    /// Adds a parameter to the collection
+    /// </summary>
+    /// <param name="parameter">The parameter to add</param>
+    /// <returns>A zero-based index of where the parameter is located in the array</returns>
+    public int Add(SqliteParameter parameter)
+    {
+      int n = -1;
+
+      if (parameter.ParameterName != null)
+      {
+        n = IndexOf(parameter.ParameterName);
+      }
+
+      if (n == -1)
+      {
+        n = _parameterList.Count;
+        _parameterList.Add((SqliteParameter)parameter);
+      }
+
+      SetParameter(n, parameter);
+
+      return n;
+    }
+
+    /// <summary>
+    /// Adds a parameter to the collection
+    /// </summary>
+    /// <param name="value">The parameter to add</param>
+    /// <returns>A zero-based index of where the parameter is located in the array</returns>
+#if !PLATFORM_COMPACTFRAMEWORK
+    [EditorBrowsable(EditorBrowsableState.Never)]
+#endif
+    public override int Add(object value)
+    {
+      return Add((SqliteParameter)value);
+    }
+
+    /// <summary>
+    /// Adds a named/unnamed parameter and its value to the parameter collection.
+    /// </summary>
+    /// <param name="parameterName">Name of the parameter, or null to indicate an unnamed parameter</param>
+    /// <param name="value">The initial value of the parameter</param>
+    /// <returns>Returns the SqliteParameter object created during the call.</returns>
+    public SqliteParameter AddWithValue(string parameterName, object value)
+    {
+      SqliteParameter param = new SqliteParameter(parameterName, value);
+      Add(param);
+
+      return param;
+    }
+
+    /// <summary>
+    /// Adds an array of parameters to the collection
+    /// </summary>
+    /// <param name="values">The array of parameters to add</param>
+    public void AddRange(SqliteParameter[] values)
+    {
+      int x = values.Length;
+      for (int n = 0; n < x; n++)
+        Add(values[n]);
+    }
+
+    /// <summary>
+    /// Adds an array of parameters to the collection
+    /// </summary>
+    /// <param name="values">The array of parameters to add</param>
+    public override void AddRange(Array values)
+    {
+      int x = values.Length;
+      for (int n = 0; n < x; n++)
+        Add((SqliteParameter)(values.GetValue(n)));
+    }
+
+    /// <summary>
+    /// Clears the array and resets the collection
+    /// </summary>
+    public override void Clear()
+    {
+      _unboundFlag = true;
+      _parameterList.Clear();
+    }
+
+    /// <summary>
+    /// Determines if the named parameter exists in the collection
+    /// </summary>
+    /// <param name="parameterName">The name of the parameter to check</param>
+    /// <returns>True if the parameter is in the collection</returns>
+    public override bool Contains(string parameterName)
+    {
+      return (IndexOf(parameterName) != -1);
+    }
+
+    /// <summary>
+    /// Determines if the parameter exists in the collection
+    /// </summary>
+    /// <param name="value">The SqliteParameter to check</param>
+    /// <returns>True if the parameter is in the collection</returns>
+    public override bool Contains(object value)
+    {
+      return _parameterList.Contains((SqliteParameter)value);
+    }
+
+    /// <summary>
+    /// Not implemented
+    /// </summary>
+    /// <param name="array"></param>
+    /// <param name="index"></param>
+    public override void CopyTo(Array array, int index)
+    {
+      throw new NotImplementedException();
+    }
+
+    /// <summary>
+    /// Returns a count of parameters in the collection
+    /// </summary>
+    public override int Count
+    {
+      get { return _parameterList.Count; }
+    }
+
+    /// <summary>
+    /// Overloaded to specialize the return value of the default indexer
+    /// </summary>
+    /// <param name="parameterName">Name of the parameter to get/set</param>
+    /// <returns>The specified named Sqlite parameter</returns>
+    public new SqliteParameter this[string parameterName]
+    {
+      get
+      {
+        return (SqliteParameter)GetParameter(parameterName);
+      }
+      set
+      {
+        SetParameter(parameterName, value);
+      }
+    }
+
+    /// <summary>
+    /// Overloaded to specialize the return value of the default indexer
+    /// </summary>
+    /// <param name="index">The index of the parameter to get/set</param>
+    /// <returns>The specified Sqlite parameter</returns>
+    public new SqliteParameter this[int index]
+    {
+      get
+      {
+        return (SqliteParameter)GetParameter(index);
+      }
+      set
+      {
+        SetParameter(index, value);
+      }
+    }
+    /// <summary>
+    /// Retrieve a parameter by name from the collection
+    /// </summary>
+    /// <param name="parameterName">The name of the parameter to fetch</param>
+    /// <returns>A DbParameter object</returns>
+    protected override DbParameter GetParameter(string parameterName)
+    {
+      return GetParameter(IndexOf(parameterName));
+    }
+
+    /// <summary>
+    /// Retrieves a parameter by its index in the collection
+    /// </summary>
+    /// <param name="index">The index of the parameter to retrieve</param>
+    /// <returns>A DbParameter object</returns>
+    protected override DbParameter GetParameter(int index)
+    {
+      return _parameterList[index];
+    }
+
+    /// <summary>
+    /// Returns the index of a parameter given its name
+    /// </summary>
+    /// <param name="parameterName">The name of the parameter to find</param>
+    /// <returns>-1 if not found, otherwise a zero-based index of the parameter</returns>
+    public override int IndexOf(string parameterName)
+    {
+      int x = _parameterList.Count;
+      for (int n = 0; n < x; n++)
+      {
+        if (String.Compare(parameterName, _parameterList[n].ParameterName, true, CultureInfo.InvariantCulture) == 0)
+          return n;
+      }
+      return -1;
+    }
+
+    /// <summary>
+    /// Returns the index of a parameter
+    /// </summary>
+    /// <param name="value">The parameter to find</param>
+    /// <returns>-1 if not found, otherwise a zero-based index of the parameter</returns>
+    public override int IndexOf(object value)
+    {
+      return _parameterList.IndexOf((SqliteParameter)value);
+    }
+
+    /// <summary>
+    /// Inserts a parameter into the array at the specified location
+    /// </summary>
+    /// <param name="index">The zero-based index to insert the parameter at</param>
+    /// <param name="value">The parameter to insert</param>
+    public override void Insert(int index, object value)
+    {
+      _unboundFlag = true;
+      _parameterList.Insert(index, (SqliteParameter)value);
+    }
+
+    /// <summary>
+    /// Removes a parameter from the collection
+    /// </summary>
+    /// <param name="value">The parameter to remove</param>
+    public override void Remove(object value)
+    {
+      _unboundFlag = true;
+      _parameterList.Remove((SqliteParameter)value);
+    }
+
+    /// <summary>
+    /// Removes a parameter from the collection given its name
+    /// </summary>
+    /// <param name="parameterName">The name of the parameter to remove</param>
+    public override void RemoveAt(string parameterName)
+    {
+      RemoveAt(IndexOf(parameterName));
+    }
+
+    /// <summary>
+    /// Removes a parameter from the collection given its index
+    /// </summary>
+    /// <param name="index">The zero-based parameter index to remove</param>
+    public override void RemoveAt(int index)
+    {
+      _unboundFlag = true;
+      _parameterList.RemoveAt(index);
+    }
+
+    /// <summary>
+    /// Re-assign the named parameter to a new parameter object
+    /// </summary>
+    /// <param name="parameterName">The name of the parameter to replace</param>
+    /// <param name="value">The new parameter</param>
+    protected override void SetParameter(string parameterName, DbParameter value)
+    {
+      SetParameter(IndexOf(parameterName), value);
+    }
+
+    /// <summary>
+    /// Re-assign a parameter at the specified index
+    /// </summary>
+    /// <param name="index">The zero-based index of the parameter to replace</param>
+    /// <param name="value">The new parameter</param>
+    protected override void SetParameter(int index, DbParameter value)
+    {
+      _unboundFlag = true;
+      _parameterList[index] = (SqliteParameter)value;
+    }
+
+    /// <summary>
+    /// Un-binds all parameters from their statements
+    /// </summary>
+    internal void Unbind()
+    {
+      _unboundFlag = true;
+    }
+
+    /// <summary>
+    /// This function attempts to map all parameters in the collection to all statements in a Command.
+    /// Since named parameters may span multiple statements, this function makes sure all statements are bound
+    /// to the same named parameter.  Unnamed parameters are bound in sequence.
+    /// </summary>
+    internal void MapParameters(SqliteStatement activeStatement)
+    {
+      if (_unboundFlag == false || _parameterList.Count == 0 || _command._statementList == null) return;
+
+      int nUnnamed = 0;
+      string s;
+      int n;
+      int y = -1;
+      SqliteStatement stmt;
+
+      foreach(SqliteParameter p in _parameterList)
+      {
+        y ++;
+        s = p.ParameterName;
+        if (s == null)
+        {
+          s = String.Format(CultureInfo.InvariantCulture, ";{0}", nUnnamed);
+          nUnnamed++;
+        }
+
+        int x;
+        bool isMapped = false;
+
+        if (activeStatement == null)
+          x = _command._statementList.Count;
+        else
+          x = 1;
+
+        stmt = activeStatement;
+        for (n = 0; n < x; n++)
+        {
+          isMapped = false;
+          if (stmt == null) stmt = _command._statementList[n];
+          if (stmt._paramNames != null)
+          {
+            if (stmt.MapParameter(s, p) == true)
+              isMapped = true;
+          }
+          stmt = null;
+        }
+
+        // If the parameter has a name, but the SQL statement uses unnamed references, this can happen -- attempt to map
+        // the parameter by its index in the collection
+        if (isMapped == false)
+        {
+          s = String.Format(CultureInfo.InvariantCulture, ";{0}", y);
+
+          stmt = activeStatement;
+          for (n = 0; n < x; n++)
+          {
+            if (stmt == null) stmt = _command._statementList[n];
+            if (stmt._paramNames != null)
+            {
+              if (stmt.MapParameter(s, p) == true)
+                isMapped = true;
+            }
+            stmt = null;
+          }
+        }
+      }
+      if (activeStatement == null) _unboundFlag = false;
+    }
+  }
+}
+#endif

Added: trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteStatement.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteStatement.cs	Wed Feb  4 04:24:49 2009
@@ -0,0 +1,281 @@
+//
+// Mono.Data.Sqlite.SQLiteStatement.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.Collections.Generic;
+  using System.Globalization;
+
+  /// <summary>
+  /// Represents a single SQL statement in Sqlite.
+  /// </summary>
+  internal sealed class SqliteStatement : IDisposable
+  {
+    /// <summary>
+    /// The underlying Sqlite object this statement is bound to
+    /// </summary>
+    internal SqliteBase        _sql;
+    /// <summary>
+    /// The command text of this SQL statement
+    /// </summary>
+    internal string            _sqlStatement;
+    /// <summary>
+    /// The actual statement pointer
+    /// </summary>
+    internal IntPtr            _sqlite_stmt;
+    /// <summary>
+    /// An index from which unnamed parameters begin
+    /// </summary>
+    internal int               _unnamedParameters;
+    /// <summary>
+    /// Names of the parameters as Sqlite understands them to be
+    /// </summary>
+    internal string[]          _paramNames;
+    /// <summary>
+    /// Parameters for this statement
+    /// </summary>
+    internal SqliteParameter[] _paramValues;
+    /// <summary>
+    /// Command this statement belongs to (if any)
+    /// </summary>
+    internal SqliteCommand     _command;
+
+    private string[] _types;
+
+    /// <summary>
+    /// Initializes the statement and attempts to get all information about parameters in the statement
+    /// </summary>
+    /// <param name="sqlbase">The base Sqlite object</param>
+    /// <param name="stmt">The statement</param>
+    /// <param name="strCommand">The command text for this statement</param>
+    /// <param name="previous">The previous command in a multi-statement command</param>
+    internal SqliteStatement(SqliteBase sqlbase, IntPtr stmt, string strCommand, SqliteStatement previous)
+    {
+      _sql     = sqlbase;
+      _sqlite_stmt = stmt;
+      _sqlStatement  = strCommand;
+
+      // Determine parameters for this statement (if any) and prepare space for them.
+      int nCmdStart = 0;
+      int n = _sql.Bind_ParamCount(this);
+      int x;
+      string s;
+
+      if (n > 0)
+      {
+        if (previous != null)
+          nCmdStart = previous._unnamedParameters;
+
+        _paramNames = new string[n];
+        _paramValues = new SqliteParameter[n];
+
+        for (x = 0; x < n; x++)
+        {
+          s = _sql.Bind_ParamName(this, x + 1);
+          if (String.IsNullOrEmpty(s))
+          {
+            s = String.Format(CultureInfo.InvariantCulture, ";{0}", nCmdStart);
+            nCmdStart++;
+            _unnamedParameters++;
+          }
+          _paramNames[x] = s;
+          _paramValues[x] = null;
+        }
+      }
+    }
+
+    /// <summary>
+    /// Called by SqliteParameterCollection, this function determines if the specified parameter name belongs to
+    /// this statement, and if so, keeps a reference to the parameter so it can be bound later.
+    /// </summary>
+    /// <param name="s">The parameter name to map</param>
+    /// <param name="p">The parameter to assign it</param>
+    internal bool MapParameter(string s, SqliteParameter p)
+    {
+      if (_paramNames == null) return false;
+      
+      int startAt = 0;
+      if (s.Length > 0)
+      {
+        if (":$@;".IndexOf(s[0]) == -1)
+          startAt = 1;
+      }
+
+      int x = _paramNames.Length;
+      for (int n = 0; n < x; n++)
+      {
+        if (String.Compare(_paramNames[n], startAt, s, 0, Math.Max(_paramNames[n].Length - startAt, s.Length), true, CultureInfo.InvariantCulture) == 0)
+        {
+          _paramValues[n] = p;
+          return true;
+        }
+      }
+      return false;
+    }
+
+    #region IDisposable Members
+    /// <summary>
+    /// Disposes and finalizes the statement
+    /// </summary>
+    public void Dispose()
+    {
+      _sql.FinalizeStatement(this);
+      
+      _paramNames = null;
+      _paramValues = null;
+      _sql = null;
+      _sqlStatement = null;
+
+      GC.SuppressFinalize(this);
+    }
+    #endregion
+    
+    /// <summary>
+    ///  Bind all parameters, making sure the caller didn't miss any
+    /// </summary>
+    internal void BindParameters()
+    {
+      if (_paramNames == null) return;
+
+      int x = _paramNames.Length;
+      for (int n = 0; n < x; n++)
+      {
+        BindParameter(n + 1, _paramValues[n]);
+      }
+    }
+
+    /// <summary>
+    /// Perform the bind operation for an individual parameter
+    /// </summary>
+    /// <param name="index">The index of the parameter to bind</param>
+    /// <param name="param">The parameter we're binding</param>
+    private void BindParameter(int index, SqliteParameter param)
+    {
+      if (param == null)
+        throw new SqliteException((int)SqliteErrorCode.Error, "Insufficient parameters supplied to the command");
+
+      object obj = param.Value;
+      DbType objType = param.DbType;
+
+      if (Convert.IsDBNull(obj) || obj == null)
+      {
+        _sql.Bind_Null(this, index);
+        return;
+      }
+
+      if (objType == DbType.Object)
+        objType = SqliteConvert.TypeToDbType(obj.GetType());
+
+      switch (objType)
+      {
+        case DbType.Date:
+        case DbType.Time:
+        case DbType.DateTime:
+          _sql.Bind_DateTime(this, index, Convert.ToDateTime(obj, CultureInfo.CurrentCulture));
+          break;
+        case DbType.Int64:
+        case DbType.UInt64:
+          _sql.Bind_Int64(this, index, Convert.ToInt64(obj, CultureInfo.CurrentCulture));
+          break;
+        case DbType.Boolean:
+        case DbType.Int16:
+        case DbType.Int32:
+        case DbType.UInt16:
+        case DbType.UInt32:
+        case DbType.SByte:
+        case DbType.Byte:
+          _sql.Bind_Int32(this, index, Convert.ToInt32(obj, CultureInfo.CurrentCulture));
+          break;
+        case DbType.Single:
+        case DbType.Double:
+        case DbType.Currency:
+        case DbType.Decimal:
+          _sql.Bind_Double(this, index, Convert.ToDouble(obj, CultureInfo.CurrentCulture));
+          break;
+        case DbType.Binary:
+          _sql.Bind_Blob(this, index, (byte[])obj);
+          break;
+        case DbType.Guid:
+          if (_command.Connection._binaryGuid == true)
+            _sql.Bind_Blob(this, index, ((Guid)obj).ToByteArray());
+          else
+            _sql.Bind_Text(this, index, obj.ToString());
+
+          break;
+        default:
+          _sql.Bind_Text(this, index, obj.ToString());
+          break;
+      }
+    }
+
+    internal string[] TypeDefinitions
+    {
+      get { return _types; }
+    }
+
+    internal void SetTypes(string typedefs)
+    {
+      int pos = typedefs.IndexOf("TYPES", 0, StringComparison.OrdinalIgnoreCase);
+      if (pos == -1) throw new ArgumentOutOfRangeException();
+
+      string[] types = typedefs.Substring(pos + 6).Replace(" ", "").Replace(";", "").Replace("\"", "").Replace("[", "").Replace("]", "").Split(',', '\r', '\n', '\t');
+
+      int cols = 0;
+      int n;
+      for (n = 0; n < types.Length; n++)
+      {
+        if (String.IsNullOrEmpty(types[n]) == false)
+          cols++;
+      }
+
+      _types = new string[cols];
+
+      cols = 0;
+      for (n = 0; n < types.Length; n++)
+      {
+        if (String.IsNullOrEmpty(types[n]) == false)
+          _types[cols++] = types[n];
+      }
+    }
+  }
+}
+#endif

Added: trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteTransaction.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteTransaction.cs	Wed Feb  4 04:24:49 2009
@@ -0,0 +1,206 @@
+//
+// Mono.Data.Sqlite.SQLiteTransaction.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.Data.Common;
+
+  /// <summary>
+  /// Sqlite implementation of DbTransaction.
+  /// </summary>
+  public sealed class SqliteTransaction : DbTransaction
+  {
+    /// <summary>
+    /// The connection to which this transaction is bound
+    /// </summary>
+    internal SqliteConnection _cnn;
+    internal long _version; // Matches the version of the connection
+
+    /// <summary>
+    /// Constructs the transaction object, binding it to the supplied connection
+    /// </summary>
+    /// <param name="connection">The connection to open a transaction on</param>
+    /// <param name="deferredLock">TRUE to defer the writelock, or FALSE to lock immediately</param>
+    internal SqliteTransaction(SqliteConnection connection, bool deferredLock)
+    {
+      _cnn = connection;
+      _version = _cnn._version;
+
+      if (_cnn._transactionLevel++ == 0)
+      {
+        try
+        {
+          using (SqliteCommand cmd = _cnn.CreateCommand())
+          {
+            if (!deferredLock)
+              cmd.CommandText = "BEGIN IMMEDIATE";
+            else
+              cmd.CommandText = "BEGIN";
+
+            cmd.ExecuteNonQuery();
+          }
+        }
+        catch (SqliteException)
+        {
+          _cnn._transactionLevel--;
+          _cnn = null;
+          throw;
+        }
+      }
+    }
+
+    /// <summary>
+    /// Commits the current transaction.
+    /// </summary>
+    public override void Commit()
+    {
+      IsValid(true);
+
+      if (--_cnn._transactionLevel == 0)
+      {
+        try
+        {
+          using (SqliteCommand cmd = _cnn.CreateCommand())
+          {
+            cmd.CommandText = "COMMIT";
+            cmd.ExecuteNonQuery();
+          }
+        }
+        finally
+        {
+          _cnn = null;
+        }
+      }
+      else
+      {
+        _cnn = null;
+      }
+    }
+
+    /// <summary>
+    /// Returns the underlying connection to which this transaction applies.
+    /// </summary>
+    public new SqliteConnection Connection
+    {
+      get { return _cnn; }
+    }
+
+    /// <summary>
+    /// Forwards to the local Connection property
+    /// </summary>
+    protected override DbConnection DbConnection
+    {
+      get { return Connection; }
+    }
+
+    /// <summary>
+    /// Disposes the transaction.  If it is currently active, any changes are rolled back.
+    /// </summary>
+    protected override void Dispose(bool disposing)
+    {
+      if (IsValid(false))
+        Rollback();
+
+      _cnn = null;
+
+      base.Dispose(disposing);
+    }
+
+    /// <summary>
+    /// Gets the isolation level of the transaction.  Sqlite only supports Serializable transactions.
+    /// </summary>
+    public override IsolationLevel IsolationLevel
+    {
+      get { return IsolationLevel.Serializable; }
+    }
+
+    /// <summary>
+    /// Rolls back the active transaction.
+    /// </summary>
+    public override void Rollback()
+    {
+      IsValid(true);
+
+      try
+      {
+        using (SqliteCommand cmd = _cnn.CreateCommand())
+        {
+          cmd.CommandText = "ROLLBACK";
+          cmd.ExecuteNonQuery();
+        }
+        _cnn._transactionLevel = 0;
+      }
+      finally
+      {
+        _cnn = null;
+      }
+    }
+
+    internal bool IsValid(bool throwError)
+    {
+      if (_cnn == null)
+      {
+        if (throwError == true) throw new ArgumentNullException("No connection associated with this transaction");
+        else return false;
+      }
+
+      if (_cnn._transactionLevel == 0)
+      {
+        if (throwError == true) throw new SqliteException((int)SqliteErrorCode.Misuse, "No transaction is active on this connection");
+        else return false;
+      }
+      if (_cnn._version != _version)
+      {
+        if (throwError == true) throw new SqliteException((int)SqliteErrorCode.Misuse, "The connection was closed and re-opened, changes were rolled back");
+        else return false;
+      }
+      if (_cnn.State != ConnectionState.Open)
+      {
+        if (throwError == true) throw new SqliteException((int)SqliteErrorCode.Misuse, "Connection was closed");
+        else return false;
+      }
+
+      return true;
+    }
+  }
+}
+#endif

Added: trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SR.Designer.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SR.Designer.cs	Wed Feb  4 04:24:49 2009
@@ -0,0 +1,148 @@
+//
+// Mono.Data.Sqlite.SR.Designer.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.
+//
+
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:2.0.50727.42
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+#if NET_2_0
+namespace Mono.Data.Sqlite {
+    using System;
+    
+    
+    /// <summary>
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    /// </summary>
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    internal class SR {
+        
+        private static global::System.Resources.ResourceManager resourceMan;
+        
+        private static global::System.Globalization.CultureInfo resourceCulture;
+        
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal SR() {
+        }
+        
+        /// <summary>
+        ///   Returns the cached ResourceManager instance used by this class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.ReferenceEquals(resourceMan, null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SR", typeof(SR).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+        
+        /// <summary>
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; standalone=&quot;yes&quot;?&gt;
+        ///&lt;DocumentElement&gt;
+        ///  &lt;DataTypes&gt;
+        ///    &lt;TypeName&gt;smallint&lt;/TypeName&gt;
+        ///    &lt;ProviderDbType&gt;10&lt;/ProviderDbType&gt;
+        ///    &lt;ColumnSize&gt;5&lt;/ColumnSize&gt;
+        ///    &lt;DataType&gt;System.Int16&lt;/DataType&gt;
+        ///    &lt;CreateFormat&gt;smallint&lt;/CreateFormat&gt;
+        ///    &lt;IsAutoIncrementable&gt;false&lt;/IsAutoIncrementable&gt;
+        ///    &lt;IsCaseSensitive&gt;false&lt;/IsCaseSensitive&gt;
+        ///    &lt;IsFixedLength&gt;true&lt;/IsFixedLength&gt;
+        ///    &lt;IsFixedPrecisionScale&gt;true&lt;/IsFixedPrecisionScale&gt;
+        ///    &lt;IsLong&gt;false&lt;/IsLong&gt;
+        ///    &lt;IsNullable&gt;true&lt;/ [rest of string was truncated]&quot;;.
+        /// </summary>
+        internal static string DataTypes {
+            get {
+                return ResourceManager.GetString("DataTypes", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to ALL,ALTER,AND,AS,AUTOINCREMENT,BETWEEN,BY,CASE,CHECK,COLLATE,COMMIT,CONSTRAINT,CREATE,CROSS,DEFAULT,DEFERRABLE,DELETE,DISTINCT,DROP,ELSE,ESCAPE,EXCEPT,FOREIGN,FROM,FULL,GROUP,HAVING,IN,INDEX,INNER,INSERT,INTERSECT,INTO,IS,ISNULL,JOIN,LEFT,LIMIT,NATURAL,NOT,NOTNULL,NULL,ON,OR,ORDER,OUTER,PRIMARY,REFERENCES,RIGHT,ROLLBACK,SELECT,SET,TABLE,THEN,TO,TRANSACTION,UNION,UNIQUE,UPDATE,USING,VALUES,WHEN,WHERE.
+        /// </summary>
+        internal static string Keywords {
+            get {
+                return ResourceManager.GetString("Keywords", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
+        ///&lt;DocumentElement&gt;
+        ///  &lt;MetaDataCollections&gt;
+        ///    &lt;CollectionName&gt;MetaDataCollections&lt;/CollectionName&gt;
+        ///    &lt;NumberOfRestrictions&gt;0&lt;/NumberOfRestrictions&gt;
+        ///    &lt;NumberOfIdentifierParts&gt;0&lt;/NumberOfIdentifierParts&gt;
+        ///  &lt;/MetaDataCollections&gt;
+        ///  &lt;MetaDataCollections&gt;
+        ///    &lt;CollectionName&gt;DataSourceInformation&lt;/CollectionName&gt;
+        ///    &lt;NumberOfRestrictions&gt;0&lt;/NumberOfRestrictions&gt;
+        ///    &lt;NumberOfIdentifierParts&gt;0&lt;/NumberOfIdentifierParts&gt;
+        ///  &lt;/MetaDataCollections&gt;
+        ///  &lt;MetaDataC [rest of string was truncated]&quot;;.
+        /// </summary>
+        internal static string MetaDataCollections {
+            get {
+                return ResourceManager.GetString("MetaDataCollections", resourceCulture);
+            }
+        }
+    }
+}
+#endif

Added: trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SqliteDataSourceEnumerator.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SqliteDataSourceEnumerator.cs	Wed Feb  4 04:24:49 2009
@@ -0,0 +1,79 @@
+//
+// Mono.Data.Sqlite.SqliteDataSourceEnumerator.cs
+//
+// Author(s):
+//   Chris Toshok (toshok ximian com)
+//   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.
+//
+
+#if NET_2_0
+
+using System;
+using System.Data;
+using System.Data.Common;
+        
+namespace Mono.Data.Sqlite
+{
+        public class SqliteDataSourceEnumerator : DbDataSourceEnumerator
+	{		
+                public SqliteDataSourceEnumerator ()
+                {
+                }
+
+                public override DataTable GetDataSources ()
+                {
+			DataTable dt = new DataTable ();
+			DataColumn col;
+
+			col = new DataColumn ("ServerName", typeof (string));
+			dt.Columns.Add (col);
+			
+			col = new DataColumn ("InstanceName", typeof (string));
+			dt.Columns.Add (col);
+
+			col = new DataColumn ("IsClustered", typeof (bool));
+			dt.Columns.Add (col);
+			
+			col = new DataColumn ("Version", typeof (string));
+			dt.Columns.Add (col);
+			
+			col = new DataColumn ("FactoryName", typeof (string));
+			dt.Columns.Add (col);
+
+			DataRow dr = dt.NewRow ();
+			dr [0] = "Sqlite Embedded Database";
+			dr [1] = "Sqlite Default Instance";
+			dr [2] = false;
+			dr [3] = "?";
+			dr [4] = "Mono.Data.Sqlite.SqliteConnectionFactory";
+			dt.Rows.Add (dr);
+			
+			return dt;
+                }                
+        }
+}
+
+#endif

Added: trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/UnsafeNativeMethods.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/UnsafeNativeMethods.cs	Wed Feb  4 04:24:49 2009
@@ -0,0 +1,311 @@
+//
+// Mono.Data.Sqlite.UnsafeNativeMethods.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.Security;
+  using System.Runtime.InteropServices;
+
+#if !PLATFORM_COMPACTFRAMEWORK
+  [SuppressUnmanagedCodeSecurity]
+#endif
+  internal sealed class UnsafeNativeMethods
+  {
+    private const string SQLITE_DLL = "sqlite3";
+
+    private UnsafeNativeMethods()
+    {
+    }
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern void sqlite3_sleep(uint dwMilliseconds);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern IntPtr sqlite3_libversion();
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern void sqlite3_free(IntPtr p);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_open(byte[] utf8Filename, out IntPtr db);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern void sqlite3_interrupt(IntPtr db);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_close(IntPtr db);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_exec(IntPtr db, byte[] strSql, IntPtr pvCallback, IntPtr pvParam, out IntPtr errMsg, out int len);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern IntPtr sqlite3_errmsg(IntPtr db);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_changes(IntPtr db);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_busy_timeout(IntPtr db, int ms);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_prepare_v2(IntPtr db, IntPtr pSql, int nBytes, out IntPtr stmt, out IntPtr ptrRemain);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_prepare(IntPtr db, IntPtr pSql, int nBytes, out IntPtr stmt, out IntPtr ptrRemain);
+	  
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_bind_blob(IntPtr stmt, int index, Byte[] value, int nSize, IntPtr nTransient);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_bind_double(IntPtr stmt, int index, double value);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_bind_int(IntPtr stmt, int index, int value);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_bind_int64(IntPtr stmt, int index, long value);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_bind_null(IntPtr stmt, int index);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_bind_text(IntPtr stmt, int index, byte[] value, int nlen, IntPtr pvReserved);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_bind_parameter_count(IntPtr stmt);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern IntPtr sqlite3_bind_parameter_name(IntPtr stmt, int index);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_bind_parameter_index(IntPtr stmt, byte[] strName);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_column_count(IntPtr stmt);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern IntPtr sqlite3_column_name(IntPtr stmt, int index);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern IntPtr sqlite3_column_decltype(IntPtr stmt, int index);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_step(IntPtr stmt);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern double sqlite3_column_double(IntPtr stmt, int index);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_column_int(IntPtr stmt, int index);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern Int64 sqlite3_column_int64(IntPtr stmt, int index);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern IntPtr sqlite3_column_text(IntPtr stmt, int index);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern IntPtr sqlite3_column_blob(IntPtr stmt, int index);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_column_bytes(IntPtr stmt, int index);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern TypeAffinity sqlite3_column_type(IntPtr stmt, int index);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_finalize(IntPtr stmt);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_reset(IntPtr stmt);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_create_collation(IntPtr db, byte[] strName, int eTextRep, IntPtr ctx, SqliteCollation fcompare);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_create_function(IntPtr db, byte[] strName, int nArgs, int eTextRep, IntPtr app, SqliteCallback func, SqliteCallback fstep, SqliteFinalCallback ffinal);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_aggregate_count(IntPtr context);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern IntPtr sqlite3_value_blob(IntPtr p);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_value_bytes(IntPtr p);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern double sqlite3_value_double(IntPtr p);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_value_int(IntPtr p);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern Int64 sqlite3_value_int64(IntPtr p);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern IntPtr sqlite3_value_text(IntPtr p);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern TypeAffinity sqlite3_value_type(IntPtr p);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern void sqlite3_result_blob(IntPtr context, byte[] value, int nSize, IntPtr pvReserved);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern void sqlite3_result_double(IntPtr context, double value);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern void sqlite3_result_error(IntPtr context, byte[] strErr, int nLen);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern void sqlite3_result_int(IntPtr context, int value);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern void sqlite3_result_int64(IntPtr context, Int64 value);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern void sqlite3_result_null(IntPtr context);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern void sqlite3_result_text(IntPtr context, byte[] value, int nLen, IntPtr pvReserved);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern IntPtr sqlite3_aggregate_context(IntPtr context, int nBytes);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_table_column_metadata(IntPtr db, byte[] dbName, byte[] tblName, byte[] colName, out IntPtr ptrDataType, out IntPtr ptrCollSeq, out int notNull, out int primaryKey, out int autoInc);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern IntPtr sqlite3_column_database_name(IntPtr stmt, int index);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern IntPtr sqlite3_column_database_name16(IntPtr stmt, int index);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern IntPtr sqlite3_column_table_name(IntPtr stmt, int index);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern IntPtr sqlite3_column_table_name16(IntPtr stmt, int index);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern IntPtr sqlite3_column_origin_name(IntPtr stmt, int index);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern IntPtr sqlite3_column_origin_name16(IntPtr stmt, int index);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern IntPtr sqlite3_column_text16(IntPtr stmt, int index);
+
+    [DllImport(SQLITE_DLL, CharSet = CharSet.Unicode)]
+    internal static extern int sqlite3_open16(string utf16Filename, out IntPtr db);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern IntPtr sqlite3_errmsg16(IntPtr db);
+
+    [DllImport(SQLITE_DLL, CharSet = CharSet.Unicode)]
+    internal static extern int sqlite3_prepare16_v2(IntPtr db, IntPtr pSql, int sqlLen, out IntPtr stmt, out IntPtr ptrRemain);
+
+    [DllImport(SQLITE_DLL, CharSet = CharSet.Unicode)]
+    internal static extern int sqlite3_bind_text16(IntPtr stmt, int index, string value, int nlen, int nTransient);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern IntPtr sqlite3_column_name16(IntPtr stmt, int index);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern IntPtr sqlite3_column_decltype16(IntPtr stmt, int index, out int len);
+
+    [DllImport(SQLITE_DLL, CharSet = CharSet.Unicode)]
+    internal static extern int sqlite3_create_collation16(IntPtr db, string strName, int eTextRep, IntPtr ctx, SqliteCollation fcompare);
+
+    [DllImport(SQLITE_DLL, CharSet = CharSet.Unicode)]
+    internal static extern int sqlite3_create_function16(IntPtr db, string strName, int nArgs, int eTextRep, IntPtr app, SqliteCallback func, SqliteCallback funcstep, SqliteFinalCallback funcfinal);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern IntPtr sqlite3_value_text16(IntPtr p);
+
+    [DllImport(SQLITE_DLL, CharSet = CharSet.Unicode)]
+    internal static extern void sqlite3_result_error16(IntPtr context, string strName, int nLen);
+
+    [DllImport(SQLITE_DLL, CharSet = CharSet.Unicode)]
+    internal static extern void sqlite3_result_text16(IntPtr context, string strName, int nLen, IntPtr pvReserved);
+
+    [DllImport(SQLITE_DLL, CharSet = CharSet.Unicode, SetLastError = true)]
+    internal static extern int sqlite3_encryptfile(string fileName);
+
+    [DllImport(SQLITE_DLL, CharSet = CharSet.Unicode, SetLastError = true)]
+    internal static extern int sqlite3_decryptfile(string fileName);
+
+    [DllImport(SQLITE_DLL, CharSet = CharSet.Unicode, SetLastError = true)]
+    internal static extern int sqlite3_encryptedstatus(string fileName, out int fileStatus);
+
+    [DllImport(SQLITE_DLL, CharSet = CharSet.Unicode, SetLastError = true)]
+    internal static extern int sqlite3_compressfile(string fileName);
+
+    [DllImport(SQLITE_DLL, CharSet = CharSet.Unicode, SetLastError = true)]
+    internal static extern int sqlite3_decompressfile(string fileName);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_key(IntPtr db, byte[] key, int keylen);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_rekey(IntPtr db, byte[] key, int keylen);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern IntPtr sqlite3_update_hook(IntPtr db, SqliteUpdateCallback func);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern IntPtr sqlite3_commit_hook(IntPtr db, SqliteCommitCallback func);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern IntPtr sqlite3_rollback_hook(IntPtr db, SqliteRollbackCallback func);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_cursor_rowid(IntPtr stmt, int cursor, out long rowid);
+
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_table_cursor(IntPtr stmt, int db, int tableRootPage);
+    
+    [DllImport(SQLITE_DLL)]
+    internal static extern int sqlite3_last_insert_rowid(IntPtr db);
+  }
+}
+#endif

Added: trunk/banshee/src/Libraries/Mono.Data.Sqlite/bug-470042_mds-custom-functions_v2.patch
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Mono.Data.Sqlite/bug-470042_mds-custom-functions_v2.patch	Wed Feb  4 04:24:49 2009
@@ -0,0 +1,241 @@
+diff --git a/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLite3.cs b/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLite3.cs
+index 32c09bb..95f20f4 100644
+--- a/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLite3.cs
++++ b/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLite3.cs
+@@ -76,7 +76,6 @@ namespace Mono.Data.Sqlite
+       {
+         int n = UnsafeNativeMethods.sqlite3_close(_sql);
+         if (n > 0) throw new SqliteException(n, SqliteLastError());
+-        SqliteFunction.UnbindFunctions(this, _functionsArray);
+       }
+       _sql = IntPtr.Zero;
+     }
+@@ -511,32 +510,16 @@ namespace Mono.Data.Sqlite
+       return UnsafeNativeMethods.sqlite3_aggregate_count(context);
+     }
+ 
+-    internal override IntPtr CreateFunction(string strFunction, int nArgs, SqliteCallback func, SqliteCallback funcstep, SqliteCallback funcfinal)
++    internal override void CreateFunction(string strFunction, int nArgs, SqliteCallback func, SqliteCallback funcstep, SqliteFinalCallback funcfinal)
+     {
+-      IntPtr nCookie;
+-
+-      // FIXME: Cookie must be allocated in C# and passed as a parameter to the Sqlite function
+-      int n = UnsafeNativeMethods.sqlite3_create_function(_sql, ToUTF8(strFunction), nArgs, 1, func, funcstep, funcfinal, out nCookie);
++      int n = UnsafeNativeMethods.sqlite3_create_function(_sql, ToUTF8(strFunction), nArgs, 1, IntPtr.Zero, func, funcstep, funcfinal);
+       if (n > 0) throw new SqliteException(n, SqliteLastError());
+-
+-      return nCookie;
+     }
+ 
+-    internal override IntPtr CreateCollation(string strCollation, SqliteCollation func)
++    internal override void CreateCollation(string strCollation, SqliteCollation func)
+     {
+-      IntPtr nCookie;
+-
+-      // FIXME: Cookie must be allocated in C# and passed as a parameter to the Sqlite function
+-      int n = UnsafeNativeMethods.sqlite3_create_collation(_sql, ToUTF8(strCollation), 1, 0, func, out nCookie);
++      int n = UnsafeNativeMethods.sqlite3_create_collation(_sql, ToUTF8(strCollation), 1, IntPtr.Zero, func);
+       if (n > 0) throw new SqliteException(n, SqliteLastError());
+-
+-      return nCookie;
+-    }
+-
+-    internal override void FreeFunction(IntPtr nCookie)
+-    {
+-	    // FIXME: must be handled in C#, this function does not exist in the mainstream sqlite3
+-      UnsafeNativeMethods.sqlite3_function_free_callbackcookie(nCookie);
+     }
+ 
+     internal override long GetParamValueBytes(IntPtr p, int nDataOffset, byte[] bDest, int nStart, int nLength)
+diff --git a/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLite3_UTF16.cs b/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLite3_UTF16.cs
+index 3b259e5..d109c96 100644
+--- a/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLite3_UTF16.cs
++++ b/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLite3_UTF16.cs
+@@ -131,28 +131,16 @@ namespace Mono.Data.Sqlite
+       return ToString(UnsafeNativeMethods.sqlite3_column_table_name16(stmt._sqlite_stmt, index));
+     }
+ 
+-    internal override IntPtr CreateFunction(string strFunction, int nArgs, SqliteCallback func, SqliteCallback funcstep, SqliteCallback funcfinal)
++    internal override void CreateFunction(string strFunction, int nArgs, SqliteCallback func, SqliteCallback funcstep, SqliteFinalCallback funcfinal)
+     {
+-	    // FIXME: the function interface below is not supported in the mainstream version of sqlite. Need to rewrite the C# API to
+-	    // use the mainstream sqlite. The cookie needs to be allocated in C#
+-      IntPtr nCookie;
+-
+-      int n = UnsafeNativeMethods.sqlite3_create_function16(_sql, strFunction, nArgs, 4, func, funcstep, funcfinal, out nCookie);
++      int n = UnsafeNativeMethods.sqlite3_create_function16(_sql, strFunction, nArgs, 4, IntPtr.Zero, func, funcstep, funcfinal);
+       if (n > 0) throw new SqliteException(n, SqliteLastError());
+-
+-      return nCookie;
+     }
+ 
+-    internal override IntPtr CreateCollation(string strCollation, SqliteCollation func)
++    internal override void CreateCollation(string strCollation, SqliteCollation func)
+     {
+-	    // FIXME: the function interface below is not supported in the mainstream version of sqlite. Need to rewrite the C# API to
+-	    // use the mainstream sqlite. The cookie needs to be allocated in C#
+-      IntPtr nCookie;
+-
+-      int n = UnsafeNativeMethods.sqlite3_create_collation16(_sql, strCollation, 4, 0, func, out nCookie);
++      int n = UnsafeNativeMethods.sqlite3_create_collation16(_sql, strCollation, 4, IntPtr.Zero, func);
+       if (n > 0) throw new SqliteException(n, SqliteLastError());
+-
+-      return nCookie;
+     }
+ 
+     internal override string GetParamValueText(IntPtr ptr)
+diff --git a/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteBase.cs b/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteBase.cs
+index ea05065..42d3ad3 100644
+--- a/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteBase.cs
++++ b/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteBase.cs
+@@ -152,9 +152,8 @@ namespace Mono.Data.Sqlite
+     internal abstract DateTime GetDateTime(SqliteStatement stmt, int index);
+     internal abstract bool     IsNull(SqliteStatement stmt, int index);
+ 
+-    internal abstract IntPtr  CreateCollation(string strCollation, SqliteCollation func);
+-    internal abstract IntPtr  CreateFunction(string strFunction, int nArgs, SqliteCallback func, SqliteCallback funcstep, SqliteCallback funcfinal);
+-    internal abstract void FreeFunction(IntPtr cookie);
++    internal abstract void  CreateCollation(string strCollation, SqliteCollation func);
++    internal abstract void  CreateFunction(string strFunction, int nArgs, SqliteCallback func, SqliteCallback funcstep, SqliteFinalCallback funcfinal);
+ 
+     internal abstract int AggregateCount(IntPtr context);
+     internal abstract IntPtr AggregateContext(IntPtr context);
+diff --git a/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteFunction.cs b/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteFunction.cs
+index 67b21a9..5f3a5a6 100644
+--- a/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteFunction.cs
++++ b/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/SQLiteFunction.cs
+@@ -76,6 +76,11 @@ namespace Mono.Data.Sqlite
+   /// <param name="argsptr">A pointer to the array of argument pointers</param>
+   internal delegate void SqliteCallback(IntPtr context, int nArgs, IntPtr argsptr);
+   /// <summary>
++  /// An internal callback delegate declaration.
++  /// </summary>
++  /// <param name="context">Raw context pointer for the user function</param>
++  internal delegate void SqliteFinalCallback(IntPtr context);
++  /// <summary>
+   /// Internal callback delegate for implementing collation sequences
+   /// </summary>
+   /// <param name="len1">Length of the string pv1</param>
+@@ -109,10 +114,6 @@ namespace Mono.Data.Sqlite
+     /// </summary>
+     private SqliteBase              _base;
+     /// <summary>
+-    /// Used internally to keep track of memory allocated for aggregate functions
+-    /// </summary>
+-    private IntPtr                     _interopCookie;
+-    /// <summary>
+     /// Internal array used to keep track of aggregate function context data
+     /// </summary>
+     private Dictionary<long, object> _contextDataList;
+@@ -128,7 +129,7 @@ namespace Mono.Data.Sqlite
+     /// <summary>
+     /// Holds a reference to the callback function for finalizing an aggregate function
+     /// </summary>
+-    private SqliteCallback  _FinalFunc;
++    private SqliteFinalCallback  _FinalFunc;
+     /// <summary>
+     /// Holds a reference to the callback function for collation sequences
+     /// </summary>
+@@ -380,9 +381,7 @@ namespace Mono.Data.Sqlite
+     /// An internal aggregate Final function callback, which wraps the context pointer and calls the virtual Final() method.
+     /// </summary>
+     /// <param name="context">A raw context pointer</param>
+-    /// <param name="nArgs">Not used, always zero</param>
+-    /// <param name="argsptr">Not used, always zero</param>
+-    internal void FinalCallback(IntPtr context, int nArgs, IntPtr argsptr)
++    internal void FinalCallback(IntPtr context)
+     {
+       long n = (long)_base.AggregateContext(context);
+       object obj = null;
+@@ -524,10 +523,6 @@ namespace Mono.Data.Sqlite
+     /// It is done this way so that all user-defined functions will access the database using the same encoding scheme
+     /// as the connection (UTF-8 or UTF-16).
+     /// </summary>
+-    /// <remarks>
+-    /// The wrapper functions that interop with Sqlite will create a unique cooke value, which internally is a pointer to
+-    /// all the wrapped callback functions.  The interop function uses it to map CDecl callbacks to StdCall callbacks.
+-    /// </remarks>
+     /// <param name="sqlbase">The base object on which the functions are to bind</param>
+     /// <returns>Returns an array of functions which the connection object should retain until the connection is closed.</returns>
+     internal static SqliteFunction[] BindFunctions(SqliteBase sqlbase)
+@@ -541,15 +536,13 @@ namespace Mono.Data.Sqlite
+         f._base = sqlbase;
+         f._InvokeFunc = (pr.FuncType == FunctionType.Scalar) ? new SqliteCallback(f.ScalarCallback) : null;
+         f._StepFunc = (pr.FuncType == FunctionType.Aggregate) ? new SqliteCallback(f.StepCallback) : null;
+-        f._FinalFunc = (pr.FuncType == FunctionType.Aggregate) ? new SqliteCallback(f.FinalCallback) : null;
++        f._FinalFunc = (pr.FuncType == FunctionType.Aggregate) ? new SqliteFinalCallback(f.FinalCallback) : null;
+         f._CompareFunc = (pr.FuncType == FunctionType.Collation) ? new SqliteCollation(f.CompareCallback) : null;
+ 
+         if (pr.FuncType != FunctionType.Collation)
+-          f._interopCookie = sqlbase.CreateFunction(pr.Name, pr.Arguments, f._InvokeFunc, f._StepFunc, f._FinalFunc);
++          sqlbase.CreateFunction(pr.Name, pr.Arguments, f._InvokeFunc, f._StepFunc, f._FinalFunc);
+         else
+-          f._interopCookie = sqlbase.CreateCollation(pr.Name, f._CompareFunc);
+-
+-
++          sqlbase.CreateCollation(pr.Name, f._CompareFunc);
+         lFunctions.Add(f);
+       }
+ 
+@@ -557,28 +550,7 @@ namespace Mono.Data.Sqlite
+       lFunctions.CopyTo(arFunctions, 0);
+ 
+       return arFunctions;
+-    }
+ 
+-    /// <summary>
+-    /// Issued after the base connection is closed, this function cleans up all user-defined functions and disposes of them.
+-    /// </summary>
+-    /// <remarks>
+-    /// Cleaning up here is done mainly because of the interop wrapper.  It allocated memory to hold a reference to all the
+-    /// delegates, and now must free that memory.
+-    /// Freeing is done after the connection is closed to ensure no callbacks get hit after we've freed the cookie.
+-    /// </remarks>
+-    /// <param name="sqlbase">The base Sqlite connection object</param>
+-    /// <param name="ar">An array of user-defined functions for this object</param>
+-    internal static void UnbindFunctions(SqliteBase sqlbase, SqliteFunction[] ar)
+-    {
+-      if (ar == null) return;
+-
+-      int x = ar.Length;
+-      for (int n = 0; n < x; n++)
+-      {
+-        sqlbase.FreeFunction(ar[n]._interopCookie);
+-        ar[n].Dispose();
+-      }
+     }
+   }
+ }
+diff --git a/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/UnsafeNativeMethods.cs b/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/UnsafeNativeMethods.cs
+index 51907f9..3ff2498 100644
+--- a/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/UnsafeNativeMethods.cs
++++ b/src/Libraries/Mono.Data.Sqlite/Mono.Data.Sqlite/UnsafeNativeMethods.cs
+@@ -158,13 +158,10 @@ namespace Mono.Data.Sqlite
+     internal static extern int sqlite3_reset(IntPtr stmt);
+ 
+     [DllImport(SQLITE_DLL)]
+-    internal static extern int sqlite3_create_collation(IntPtr db, byte[] strName, int nType, int nArgs, SqliteCollation func, out IntPtr nCookie);
++    internal static extern int sqlite3_create_collation(IntPtr db, byte[] strName, int eTextRep, IntPtr ctx, SqliteCollation fcompare);
+ 
+     [DllImport(SQLITE_DLL)]
+-    internal static extern int sqlite3_create_function(IntPtr db, byte[] strName, int nArgs, int nType, SqliteCallback func, SqliteCallback fstep, SqliteCallback ffinal, out IntPtr nCookie);
+-
+-    [DllImport(SQLITE_DLL)]
+-    internal static extern void sqlite3_function_free_callbackcookie(IntPtr nCookie);
++    internal static extern int sqlite3_create_function(IntPtr db, byte[] strName, int nArgs, int eTextRep, IntPtr app, SqliteCallback func, SqliteCallback fstep, SqliteFinalCallback ffinal);
+ 
+     [DllImport(SQLITE_DLL)]
+     internal static extern int sqlite3_aggregate_count(IntPtr context);
+@@ -257,10 +254,10 @@ namespace Mono.Data.Sqlite
+     internal static extern IntPtr sqlite3_column_decltype16(IntPtr stmt, int index, out int len);
+ 
+     [DllImport(SQLITE_DLL, CharSet = CharSet.Unicode)]
+-    internal static extern int sqlite3_create_collation16(IntPtr db, string strName, int nType, int nArgs, SqliteCollation func, out IntPtr nCookie);
++    internal static extern int sqlite3_create_collation16(IntPtr db, string strName, int eTextRep, IntPtr ctx, SqliteCollation fcompare);
+ 
+     [DllImport(SQLITE_DLL, CharSet = CharSet.Unicode)]
+-    internal static extern int sqlite3_create_function16(IntPtr db, string strName, int nArgs, int nType, SqliteCallback func, SqliteCallback funcstep, SqliteCallback funcfinal, out IntPtr nCookie);
++    internal static extern int sqlite3_create_function16(IntPtr db, string strName, int nArgs, int eTextRep, IntPtr app, SqliteCallback func, SqliteCallback funcstep, SqliteFinalCallback funcfinal);
+ 
+     [DllImport(SQLITE_DLL)]
+     internal static extern IntPtr sqlite3_value_text16(IntPtr p);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]