/********************************************************
* 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, HelperMethods.StringFormat(
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, HelperMethods.StringFormat(
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, HelperMethods.StringFormat(
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