/******************************************************** * ADO.NET 2.0 Data Provider for SQLite Version 3.X * Written by Joe Mistachkin (joe@mistachkin.com) * * Released to the public domain, use at your own risk! ********************************************************/ using System.Collections; using System.Collections.Generic; using System.Globalization; #region Non-Generic Classes namespace System.Data.SQLite { #region SQLiteVirtualTableCursorEnumerator Class /// /// This class represents a virtual table cursor to be used with the /// class. It is not sealed and may /// be used as the base class for any user-defined virtual table cursor /// class that wraps an object instance. /// public class SQLiteVirtualTableCursorEnumerator : SQLiteVirtualTableCursor, IEnumerator /* NOT SEALED */ { #region Private Data /// /// The instance provided when this cursor /// was created. /// private IEnumerator enumerator; /////////////////////////////////////////////////////////////////////// /// /// This value will be non-zero if false has been returned from the /// method. /// private bool endOfEnumerator; #endregion /////////////////////////////////////////////////////////////////////// #region Public Constructors /// /// Constructs an instance of this class. /// /// /// The object instance associated /// with this object instance. /// /// /// The instance to expose as a virtual /// table cursor. /// public SQLiteVirtualTableCursorEnumerator( SQLiteVirtualTable table, IEnumerator enumerator ) : base(table) { this.enumerator = enumerator; this.endOfEnumerator = true; } #endregion /////////////////////////////////////////////////////////////////////// #region Public Members /// /// Advances to the next row of the virtual table cursor using the /// method of the /// object instance. /// /// /// Non-zero if the current row is valid; zero otherwise. If zero is /// returned, no further rows are available. /// public virtual bool MoveNext() { CheckDisposed(); CheckClosed(); if (enumerator == null) return false; endOfEnumerator = !enumerator.MoveNext(); if (!endOfEnumerator) NextRowIndex(); return !endOfEnumerator; } /////////////////////////////////////////////////////////////////////// /// /// Returns the value for the current row of the virtual table cursor /// using the property of the /// object instance. /// public virtual object Current { get { CheckDisposed(); CheckClosed(); if (enumerator == null) return null; return enumerator.Current; } } /////////////////////////////////////////////////////////////////////// /// /// Resets the virtual table cursor position, also invalidating the /// current row, using the method of /// the object instance. /// public virtual void Reset() { CheckDisposed(); CheckClosed(); if (enumerator == null) return; enumerator.Reset(); } /////////////////////////////////////////////////////////////////////// /// /// Returns non-zero if the end of the virtual table cursor has been /// seen (i.e. no more rows are available, including the current one). /// public virtual bool EndOfEnumerator { get { CheckDisposed(); CheckClosed(); return endOfEnumerator; } } /////////////////////////////////////////////////////////////////////// /// /// Returns non-zero if the virtual table cursor is open. /// public virtual bool IsOpen { get { CheckDisposed(); return (enumerator != null); } } /////////////////////////////////////////////////////////////////////// /// /// Closes the virtual table cursor. This method must not throw any /// exceptions. /// public virtual void Close() { // CheckDisposed(); // CheckClosed(); if (enumerator != null) enumerator = null; } /////////////////////////////////////////////////////////////////////// /// /// Throws an if the virtual /// table cursor has been closed. /// public virtual void CheckClosed() { CheckDisposed(); if (!IsOpen) { throw new InvalidOperationException( "virtual table cursor is closed"); } } #endregion /////////////////////////////////////////////////////////////////////// #region IDisposable "Pattern" Members private bool disposed; /// /// Throws an if this object /// instance has been disposed. /// private void CheckDisposed() /* throw */ { #if THROW_ON_DISPOSED if (disposed) { throw new ObjectDisposedException( typeof(SQLiteVirtualTableCursorEnumerator).Name); } #endif } /////////////////////////////////////////////////////////////////////// /// /// Disposes of this object instance. /// /// /// Non-zero if this method is being called from the /// method. Zero if this method is /// being called from the finalizer. /// protected override void Dispose(bool disposing) { try { if (!disposed) { //if (disposing) //{ // //////////////////////////////////// // // dispose managed resources here... // //////////////////////////////////// //} ////////////////////////////////////// // release unmanaged resources here... ////////////////////////////////////// Close(); } } finally { base.Dispose(disposing); // // NOTE: Everything should be fully disposed at this point. // disposed = true; } } #endregion } #endregion /////////////////////////////////////////////////////////////////////////// #region SQLiteModuleEnumerable Class /// /// This class implements a virtual table module that exposes an /// object instance as a read-only virtual /// table. It is not sealed and may be used as the base class for any /// user-defined virtual table class that wraps an /// object instance. The following short /// example shows it being used to treat an array of strings as a table /// data source: /// /// public static class Sample /// { /// public static void Main() /// { /// using (SQLiteConnection connection = new SQLiteConnection( /// "Data Source=:memory:;")) /// { /// connection.Open(); /// /// connection.CreateModule(new SQLiteModuleEnumerable( /// "sampleModule", new string[] { "one", "two", "three" })); /// /// using (SQLiteCommand command = connection.CreateCommand()) /// { /// command.CommandText = /// "CREATE VIRTUAL TABLE t1 USING sampleModule;"; /// /// command.ExecuteNonQuery(); /// } /// /// using (SQLiteCommand command = connection.CreateCommand()) /// { /// command.CommandText = "SELECT * FROM t1;"; /// /// using (SQLiteDataReader dataReader = command.ExecuteReader()) /// { /// while (dataReader.Read()) /// Console.WriteLine(dataReader[0].ToString()); /// } /// } /// /// connection.Close(); /// } /// } /// } /// /// public class SQLiteModuleEnumerable : SQLiteModuleCommon /* NOT SEALED */ { #region Private Data /// /// The instance containing the backing data /// for the virtual table. /// private IEnumerable enumerable; /////////////////////////////////////////////////////////////////////// /// /// Non-zero if different object instances with the same value should /// generate different row identifiers, where applicable. This has no /// effect on the .NET Compact Framework. /// private bool objectIdentity; #endregion /////////////////////////////////////////////////////////////////////// #region Public Constructors /// /// Constructs an instance of this class. /// /// /// The name of the module. This parameter cannot be null. /// /// /// The instance to expose as a virtual /// table. This parameter cannot be null. /// public SQLiteModuleEnumerable( string name, IEnumerable enumerable ) : this(name, enumerable, false) { // do nothing. } /////////////////////////////////////////////////////////////////////// /// /// Constructs an instance of this class. /// /// /// The name of the module. This parameter cannot be null. /// /// /// The instance to expose as a virtual /// table. This parameter cannot be null. /// /// /// Non-zero if different object instances with the same value should /// generate different row identifiers, where applicable. This /// parameter has no effect on the .NET Compact Framework. /// public SQLiteModuleEnumerable( string name, IEnumerable enumerable, bool objectIdentity ) : base(name) { if (enumerable == null) throw new ArgumentNullException("enumerable"); this.enumerable = enumerable; this.objectIdentity = objectIdentity; } #endregion /////////////////////////////////////////////////////////////////////// #region Protected Methods /// /// Sets the table error message to one that indicates the virtual /// table cursor has no current row. /// /// /// The object instance. /// /// /// The value of . /// protected virtual SQLiteErrorCode CursorEndOfEnumeratorError( SQLiteVirtualTableCursor cursor ) { SetCursorError(cursor, "already hit end of enumerator"); return SQLiteErrorCode.Error; } #endregion /////////////////////////////////////////////////////////////////////// #region ISQLiteManagedModule Members /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// public override SQLiteErrorCode Create( SQLiteConnection connection, IntPtr pClientData, string[] arguments, ref SQLiteVirtualTable table, ref string error ) { CheckDisposed(); if (DeclareTable( connection, GetSqlForDeclareTable(), ref error) == SQLiteErrorCode.Ok) { table = new SQLiteVirtualTable(arguments); return SQLiteErrorCode.Ok; } return SQLiteErrorCode.Error; } /////////////////////////////////////////////////////////////////////// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// public override SQLiteErrorCode Connect( SQLiteConnection connection, IntPtr pClientData, string[] arguments, ref SQLiteVirtualTable table, ref string error ) { CheckDisposed(); if (DeclareTable( connection, GetSqlForDeclareTable(), ref error) == SQLiteErrorCode.Ok) { table = new SQLiteVirtualTable(arguments); return SQLiteErrorCode.Ok; } return SQLiteErrorCode.Error; } /////////////////////////////////////////////////////////////////////// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// public override SQLiteErrorCode BestIndex( SQLiteVirtualTable table, SQLiteIndex index ) { CheckDisposed(); if (!table.BestIndex(index)) { SetTableError(table, String.Format(CultureInfo.CurrentCulture, "failed to select best index for virtual table \"{0}\"", table.TableName)); return SQLiteErrorCode.Error; } return SQLiteErrorCode.Ok; } /////////////////////////////////////////////////////////////////////// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// public override SQLiteErrorCode Disconnect( SQLiteVirtualTable table ) { CheckDisposed(); table.Dispose(); return SQLiteErrorCode.Ok; } /////////////////////////////////////////////////////////////////////// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// public override SQLiteErrorCode Destroy( SQLiteVirtualTable table ) { CheckDisposed(); table.Dispose(); return SQLiteErrorCode.Ok; } /////////////////////////////////////////////////////////////////////// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// public override SQLiteErrorCode Open( SQLiteVirtualTable table, ref SQLiteVirtualTableCursor cursor ) { CheckDisposed(); cursor = new SQLiteVirtualTableCursorEnumerator( table, enumerable.GetEnumerator()); return SQLiteErrorCode.Ok; } /////////////////////////////////////////////////////////////////////// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// public override SQLiteErrorCode Close( SQLiteVirtualTableCursor cursor ) { CheckDisposed(); SQLiteVirtualTableCursorEnumerator enumeratorCursor = cursor as SQLiteVirtualTableCursorEnumerator; if (enumeratorCursor == null) { return CursorTypeMismatchError(cursor, typeof(SQLiteVirtualTableCursorEnumerator)); } enumeratorCursor.Close(); return SQLiteErrorCode.Ok; } /////////////////////////////////////////////////////////////////////// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// public override SQLiteErrorCode Filter( SQLiteVirtualTableCursor cursor, int indexNumber, string indexString, SQLiteValue[] values ) { CheckDisposed(); SQLiteVirtualTableCursorEnumerator enumeratorCursor = cursor as SQLiteVirtualTableCursorEnumerator; if (enumeratorCursor == null) { return CursorTypeMismatchError(cursor, typeof(SQLiteVirtualTableCursorEnumerator)); } enumeratorCursor.Filter(indexNumber, indexString, values); enumeratorCursor.Reset(); /* NO RESULT */ enumeratorCursor.MoveNext(); /* IGNORED */ return SQLiteErrorCode.Ok; } /////////////////////////////////////////////////////////////////////// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// public override SQLiteErrorCode Next( SQLiteVirtualTableCursor cursor ) { CheckDisposed(); SQLiteVirtualTableCursorEnumerator enumeratorCursor = cursor as SQLiteVirtualTableCursorEnumerator; if (enumeratorCursor == null) { return CursorTypeMismatchError(cursor, typeof(SQLiteVirtualTableCursorEnumerator)); } if (enumeratorCursor.EndOfEnumerator) return CursorEndOfEnumeratorError(cursor); enumeratorCursor.MoveNext(); /* IGNORED */ return SQLiteErrorCode.Ok; } /////////////////////////////////////////////////////////////////////// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// public override bool Eof( SQLiteVirtualTableCursor cursor ) { CheckDisposed(); SQLiteVirtualTableCursorEnumerator enumeratorCursor = cursor as SQLiteVirtualTableCursorEnumerator; if (enumeratorCursor == null) { return ResultCodeToEofResult(CursorTypeMismatchError( cursor, typeof(SQLiteVirtualTableCursorEnumerator))); } return enumeratorCursor.EndOfEnumerator; } /////////////////////////////////////////////////////////////////////// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// public override SQLiteErrorCode Column( SQLiteVirtualTableCursor cursor, SQLiteContext context, int index ) { CheckDisposed(); SQLiteVirtualTableCursorEnumerator enumeratorCursor = cursor as SQLiteVirtualTableCursorEnumerator; if (enumeratorCursor == null) { return CursorTypeMismatchError(cursor, typeof(SQLiteVirtualTableCursorEnumerator)); } if (enumeratorCursor.EndOfEnumerator) return CursorEndOfEnumeratorError(cursor); object current = enumeratorCursor.Current; if (current != null) context.SetString(GetStringFromObject(cursor, current)); else context.SetNull(); return SQLiteErrorCode.Ok; } /////////////////////////////////////////////////////////////////////// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// public override SQLiteErrorCode RowId( SQLiteVirtualTableCursor cursor, ref long rowId ) { CheckDisposed(); SQLiteVirtualTableCursorEnumerator enumeratorCursor = cursor as SQLiteVirtualTableCursorEnumerator; if (enumeratorCursor == null) { return CursorTypeMismatchError(cursor, typeof(SQLiteVirtualTableCursorEnumerator)); } if (enumeratorCursor.EndOfEnumerator) return CursorEndOfEnumeratorError(cursor); object current = enumeratorCursor.Current; rowId = GetRowIdFromObject(cursor, current); return SQLiteErrorCode.Ok; } /////////////////////////////////////////////////////////////////////// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// public override SQLiteErrorCode Update( SQLiteVirtualTable table, SQLiteValue[] values, ref long rowId ) { CheckDisposed(); SetTableError(table, String.Format(CultureInfo.CurrentCulture, "virtual table \"{0}\" is read-only", table.TableName)); return SQLiteErrorCode.Error; } /////////////////////////////////////////////////////////////////////// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// public override SQLiteErrorCode Rename( SQLiteVirtualTable table, string newName ) { CheckDisposed(); if (!table.Rename(newName)) { SetTableError(table, String.Format(CultureInfo.CurrentCulture, "failed to rename virtual table from \"{0}\" to \"{1}\"", table.TableName, newName)); return SQLiteErrorCode.Error; } return SQLiteErrorCode.Ok; } #endregion /////////////////////////////////////////////////////////////////////// #region IDisposable "Pattern" Members private bool disposed; /// /// Throws an if this object /// instance has been disposed. /// private void CheckDisposed() /* throw */ { #if THROW_ON_DISPOSED if (disposed) { throw new ObjectDisposedException( typeof(SQLiteModuleEnumerable).Name); } #endif } /////////////////////////////////////////////////////////////////////// /// /// Disposes of this object instance. /// /// /// Non-zero if this method is being called from the /// method. Zero if this method is /// being called from the finalizer. /// protected override void Dispose(bool disposing) { try { if (!disposed) { //if (disposing) //{ // //////////////////////////////////// // // dispose managed resources here... // //////////////////////////////////// //} ////////////////////////////////////// // release unmanaged resources here... ////////////////////////////////////// } } finally { base.Dispose(disposing); // // NOTE: Everything should be fully disposed at this point. // disposed = true; } } #endregion } #endregion } #endregion /////////////////////////////////////////////////////////////////////////////// #region Generic Classes namespace System.Data.SQLite.Generic { #region SQLiteVirtualTableCursorEnumerator Class /// /// This class represents a virtual table cursor to be used with the /// class. It is not sealed and may /// be used as the base class for any user-defined virtual table cursor /// class that wraps an object instance. /// public class SQLiteVirtualTableCursorEnumerator : SQLiteVirtualTableCursorEnumerator, IEnumerator /* NOT SEALED */ { #region Private Data /// /// The instance provided when this /// cursor was created. /// private IEnumerator enumerator; #endregion /////////////////////////////////////////////////////////////////////// #region Public Constructors /// /// Constructs an instance of this class. /// /// /// The object instance associated /// with this object instance. /// /// /// The instance to expose as a virtual /// table cursor. /// public SQLiteVirtualTableCursorEnumerator( SQLiteVirtualTable table, IEnumerator enumerator ) : base(table, enumerator as IEnumerator) { this.enumerator = enumerator; } #endregion /////////////////////////////////////////////////////////////////////// #region Public Members /// /// Returns the value for the current row of the virtual table cursor /// using the property of the /// object instance. /// T IEnumerator.Current { get { CheckDisposed(); CheckClosed(); if (enumerator == null) return default(T); return enumerator.Current; } } /////////////////////////////////////////////////////////////////////// /// /// Closes the virtual table cursor. This method must not throw any /// exceptions. /// public override void Close() { // CheckDisposed(); // CheckClosed(); if (enumerator != null) enumerator = null; base.Close(); } #endregion /////////////////////////////////////////////////////////////////////// #region IDisposable "Pattern" Members private bool disposed; /// /// Throws an if this object /// instance has been disposed. /// private void CheckDisposed() /* throw */ { #if THROW_ON_DISPOSED if (disposed) { throw new ObjectDisposedException( typeof(SQLiteVirtualTableCursorEnumerator).Name); } #endif } /////////////////////////////////////////////////////////////////////// /// /// Disposes of this object instance. /// /// /// Non-zero if this method is being called from the /// method. Zero if this method is /// being called from the finalizer. /// protected override void Dispose(bool disposing) { try { if (!disposed) { //if (disposing) //{ // //////////////////////////////////// // // dispose managed resources here... // //////////////////////////////////// //} ////////////////////////////////////// // release unmanaged resources here... ////////////////////////////////////// Close(); } } finally { base.Dispose(disposing); // // NOTE: Everything should be fully disposed at this point. // disposed = true; } } #endregion } #endregion /////////////////////////////////////////////////////////////////////////// #region SQLiteModuleEnumerable Class /// /// This class implements a virtual table module that exposes an /// object instance as a read-only virtual /// table. It is not sealed and may be used as the base class for any /// user-defined virtual table class that wraps an /// object instance. /// public class SQLiteModuleEnumerable : SQLiteModuleEnumerable /* NOT SEALED */ { #region Private Data /// /// The instance containing the backing /// data for the virtual table. /// private IEnumerable enumerable; #endregion /////////////////////////////////////////////////////////////////////// #region Public Constructors /// /// Constructs an instance of this class. /// /// /// The name of the module. This parameter cannot be null. /// /// /// The instance to expose as a virtual /// table. This parameter cannot be null. /// public SQLiteModuleEnumerable( string name, IEnumerable enumerable ) : base(name, enumerable as IEnumerable) { this.enumerable = enumerable; } #endregion /////////////////////////////////////////////////////////////////////// #region ISQLiteManagedModule Members /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// public override SQLiteErrorCode Open( SQLiteVirtualTable table, ref SQLiteVirtualTableCursor cursor ) { CheckDisposed(); cursor = new SQLiteVirtualTableCursorEnumerator( table, enumerable.GetEnumerator()); return SQLiteErrorCode.Ok; } /////////////////////////////////////////////////////////////////////// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// /// /// See the method. /// public override SQLiteErrorCode Column( SQLiteVirtualTableCursor cursor, SQLiteContext context, int index ) { CheckDisposed(); SQLiteVirtualTableCursorEnumerator enumeratorCursor = cursor as SQLiteVirtualTableCursorEnumerator; if (enumeratorCursor == null) { return CursorTypeMismatchError(cursor, typeof(SQLiteVirtualTableCursorEnumerator)); } if (enumeratorCursor.EndOfEnumerator) return CursorEndOfEnumeratorError(cursor); T current = ((IEnumerator)enumeratorCursor).Current; if (current != null) context.SetString(GetStringFromObject(cursor, current)); else context.SetNull(); return SQLiteErrorCode.Ok; } #endregion /////////////////////////////////////////////////////////////////////// #region IDisposable "Pattern" Members private bool disposed; /// /// Throws an if this object /// instance has been disposed. /// private void CheckDisposed() /* throw */ { #if THROW_ON_DISPOSED if (disposed) { throw new ObjectDisposedException( typeof(SQLiteModuleEnumerable).Name); } #endif } /////////////////////////////////////////////////////////////////////// /// /// Disposes of this object instance. /// /// /// Non-zero if this method is being called from the /// method. Zero if this method is /// being called from the finalizer. /// protected override void Dispose(bool disposing) { try { if (!disposed) { //if (disposing) //{ // //////////////////////////////////// // // dispose managed resources here... // //////////////////////////////////// //} ////////////////////////////////////// // release unmanaged resources here... ////////////////////////////////////// } } finally { base.Dispose(disposing); // // NOTE: Everything should be fully disposed at this point. // disposed = true; } } #endregion } #endregion } #endregion