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
- From: gburt svn gnome org
- To: svn-commits-list gnome org
- Subject: 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
- Date: Wed, 4 Feb 2009 04:24:50 +0000 (UTC)
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 <?xml version="1.0" standalone="yes"?>
+ ///<DocumentElement>
+ /// <DataTypes>
+ /// <TypeName>smallint</TypeName>
+ /// <ProviderDbType>10</ProviderDbType>
+ /// <ColumnSize>5</ColumnSize>
+ /// <DataType>System.Int16</DataType>
+ /// <CreateFormat>smallint</CreateFormat>
+ /// <IsAutoIncrementable>false</IsAutoIncrementable>
+ /// <IsCaseSensitive>false</IsCaseSensitive>
+ /// <IsFixedLength>true</IsFixedLength>
+ /// <IsFixedPrecisionScale>true</IsFixedPrecisionScale>
+ /// <IsLong>false</IsLong>
+ /// <IsNullable>true</ [rest of string was truncated]";.
+ /// </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 <?xml version="1.0" encoding="utf-8" ?>
+ ///<DocumentElement>
+ /// <MetaDataCollections>
+ /// <CollectionName>MetaDataCollections</CollectionName>
+ /// <NumberOfRestrictions>0</NumberOfRestrictions>
+ /// <NumberOfIdentifierParts>0</NumberOfIdentifierParts>
+ /// </MetaDataCollections>
+ /// <MetaDataCollections>
+ /// <CollectionName>DataSourceInformation</CollectionName>
+ /// <NumberOfRestrictions>0</NumberOfRestrictions>
+ /// <NumberOfIdentifierParts>0</NumberOfIdentifierParts>
+ /// </MetaDataCollections>
+ /// <MetaDataC [rest of string was truncated]";.
+ /// </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]