Merge pull request #2006 from steffen-kiess/posix-sockets-2
[mono.git] / mcs / class / Mono.Data.Sqlite / Mono.Data.Sqlite_2.0 / SQLiteFunction.cs
index 104f8ce7cc661549ce6051c13ba8bd8b1754bc41..6aefe804586af9c963af74e3a548331662b97c94 100644 (file)
-//
-// 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>
-  /// 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>
-    /// 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;
-
-    /// <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 SqliteCallback  _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>
-    /// <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)
-    {
-      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;
-
-      for (int n = 0; n < w; n++)
-      {
-        Type[] arTypes;
-        try
-        {
-          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>
-    /// <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)
-    {
-      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 SqliteCallback(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);
-        else
-          f._interopCookie = sqlbase.CreateCollation(pr.Name, f._CompareFunc);
-
-
-        lFunctions.Add(f);
-      }
-
-      SqliteFunction[] arFunctions = new SqliteFunction[lFunctions.Count];
-      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();
-      }
-    }
-  }
-}
-#endif
+/********************************************************\r
+ * ADO.NET 2.0 Data Provider for SQLite Version 3.X\r
+ * Written by Robert Simpson (robert@blackcastlesoft.com)\r
+ * \r
+ * Released to the public domain, use at your own risk!\r
+ ********************************************************/\r
+\r
+namespace Mono.Data.Sqlite\r
+{\r
+  using System;\r
+  using System.Collections;\r
+  using System.Collections.Generic;\r
+  using System.Runtime.InteropServices;\r
+  using System.Globalization;\r
+\r
+  /// <summary>\r
+  /// This abstract class is designed to handle user-defined functions easily.  An instance of the derived class is made for each\r
+  /// connection to the database.\r
+  /// </summary>\r
+  /// <remarks>\r
+  /// Although there is one instance of a class derived from SqliteFunction per database connection, the derived class has no access\r
+  /// to the underlying connection.  This is necessary to deter implementers from thinking it would be a good idea to make database\r
+  /// calls during processing.\r
+  /// \r
+  /// It is important to distinguish between a per-connection instance, and a per-SQL statement context.  One instance of this class\r
+  /// services all SQL statements being stepped through on that connection, and there can be many.  One should never store per-statement\r
+  /// information in member variables of user-defined function classes.\r
+  /// \r
+  /// For aggregate functions, always create and store your per-statement data in the contextData object on the 1st step.  This data will\r
+  /// be automatically freed for you (and Dispose() called if the item supports IDisposable) when the statement completes.\r
+  /// </remarks>\r
+  public abstract class SqliteFunction : IDisposable\r
+  {\r
+    private class AggregateData\r
+    {\r
+      internal int _count = 1;\r
+      internal object _data = null;\r
+    }\r
+\r
+    /// <summary>\r
+    /// The base connection this function is attached to\r
+    /// </summary>\r
+    internal SQLiteBase              _base;\r
+\r
+    /// <summary>\r
+    /// Internal array used to keep track of aggregate function context data\r
+    /// </summary>\r
+    private Dictionary<long, AggregateData> _contextDataList;\r
+\r
+    /// <summary>\r
+    /// Holds a reference to the callback function for user functions\r
+    /// </summary>\r
+    private SQLiteCallback  _InvokeFunc;\r
+    /// <summary>\r
+    /// Holds a reference to the callbakc function for stepping in an aggregate function\r
+    /// </summary>\r
+    private SQLiteCallback  _StepFunc;\r
+    /// <summary>\r
+    /// Holds a reference to the callback function for finalizing an aggregate function\r
+    /// </summary>\r
+    private SQLiteFinalCallback  _FinalFunc;\r
+    /// <summary>\r
+    /// Holds a reference to the callback function for collation sequences\r
+    /// </summary>\r
+    private SQLiteCollation _CompareFunc;\r
+\r
+    private SQLiteCollation _CompareFunc16;\r
+\r
+    /// <summary>\r
+    /// Current context of the current callback.  Only valid during a callback\r
+    /// </summary>\r
+    internal IntPtr _context;\r
+\r
+    /// <summary>\r
+    /// This static list contains all the user-defined functions declared using the proper attributes.\r
+    /// </summary>\r
+    private static List<SqliteFunctionAttribute> _registeredFunctions = new List<SqliteFunctionAttribute>();\r
+\r
+    /// <summary>\r
+    /// Internal constructor, initializes the function's internal variables.\r
+    /// </summary>\r
+    protected SqliteFunction()\r
+    {\r
+      _contextDataList = new Dictionary<long, AggregateData>();\r
+    }\r
+\r
+    /// <summary>\r
+    /// Returns a reference to the underlying connection's SqliteConvert class, which can be used to convert\r
+    /// strings and DateTime's into the current connection's encoding schema.\r
+    /// </summary>\r
+    public SqliteConvert SqliteConvert\r
+    {\r
+      get\r
+      {\r
+        return _base;\r
+      }\r
+    }\r
+\r
+    /// <summary>\r
+    /// Scalar functions override this method to do their magic.\r
+    /// </summary>\r
+    /// <remarks>\r
+    /// Parameters passed to functions have only an affinity for a certain data type, there is no underlying schema available\r
+    /// to force them into a certain type.  Therefore the only types you will ever see as parameters are\r
+    /// DBNull.Value, Int64, Double, String or byte[] array.\r
+    /// </remarks>\r
+    /// <param name="args">The arguments for the command to process</param>\r
+    /// <returns>You may return most simple types as a return value, null or DBNull.Value to return null, DateTime, or\r
+    /// you may return an Exception-derived class if you wish to return an error to SQLite.  Do not actually throw the error,\r
+    /// just return it!</returns>\r
+    public virtual object Invoke(object[] args)\r
+    {\r
+      return null;\r
+    }\r
+\r
+    /// <summary>\r
+    /// Aggregate functions override this method to do their magic.\r
+    /// </summary>\r
+    /// <remarks>\r
+    /// Typically you'll be updating whatever you've placed in the contextData field and returning as quickly as possible.\r
+    /// </remarks>\r
+    /// <param name="args">The arguments for the command to process</param>\r
+    /// <param name="stepNumber">The 1-based step number.  This is incrememted each time the step method is called.</param>\r
+    /// <param name="contextData">A placeholder for implementers to store contextual data pertaining to the current context.</param>\r
+    public virtual void Step(object[] args, int stepNumber, ref object contextData)\r
+    {\r
+    }\r
+\r
+    /// <summary>\r
+    /// Aggregate functions override this method to finish their aggregate processing.\r
+    /// </summary>\r
+    /// <remarks>\r
+    /// If you implemented your aggregate function properly,\r
+    /// you've been recording and keeping track of your data in the contextData object provided, and now at this stage you should have\r
+    /// all the information you need in there to figure out what to return.\r
+    /// NOTE:  It is possible to arrive here without receiving a previous call to Step(), in which case the contextData will\r
+    /// be null.  This can happen when no rows were returned.  You can either return null, or 0 or some other custom return value\r
+    /// if that is the case.\r
+    /// </remarks>\r
+    /// <param name="contextData">Your own assigned contextData, provided for you so you can return your final results.</param>\r
+    /// <returns>You may return most simple types as a return value, null or DBNull.Value to return null, DateTime, or\r
+    /// you may return an Exception-derived class if you wish to return an error to SQLite.  Do not actually throw the error,\r
+    /// just return it!\r
+    /// </returns>\r
+    public virtual object Final(object contextData)\r
+    {\r
+      return null;\r
+    }\r
+\r
+    /// <summary>\r
+    /// User-defined collation sequences override this method to provide a custom string sorting algorithm.\r
+    /// </summary>\r
+    /// <param name="param1">The first string to compare</param>\r
+    /// <param name="param2">The second strnig to compare</param>\r
+    /// <returns>1 if param1 is greater than param2, 0 if they are equal, or -1 if param1 is less than param2</returns>\r
+    public virtual int Compare(string param1, string param2)\r
+    {\r
+      return 0;\r
+    }\r
+\r
+    /// <summary>\r
+    /// Converts an IntPtr array of context arguments to an object array containing the resolved parameters the pointers point to.\r
+    /// </summary>\r
+    /// <remarks>\r
+    /// Parameters passed to functions have only an affinity for a certain data type, there is no underlying schema available\r
+    /// to force them into a certain type.  Therefore the only types you will ever see as parameters are\r
+    /// DBNull.Value, Int64, Double, String or byte[] array.\r
+    /// </remarks>\r
+    /// <param name="nArgs">The number of arguments</param>\r
+    /// <param name="argsptr">A pointer to the array of arguments</param>\r
+    /// <returns>An object array of the arguments once they've been converted to .NET values</returns>\r
+    internal object[] ConvertParams(int nArgs, IntPtr argsptr)\r
+    {\r
+      object[] parms = new object[nArgs];\r
+#if !PLATFORM_COMPACTFRAMEWORK\r
+      IntPtr[] argint = new IntPtr[nArgs];\r
+#else\r
+      int[] argint = new int[nArgs];\r
+#endif\r
+      Marshal.Copy(argsptr, argint, 0, nArgs);\r
+\r
+      for (int n = 0; n < nArgs; n++)\r
+      {\r
+        switch (_base.GetParamValueType((IntPtr)argint[n]))\r
+        {\r
+          case TypeAffinity.Null:\r
+            parms[n] = DBNull.Value;\r
+            break;\r
+          case TypeAffinity.Int64:\r
+            parms[n] = _base.GetParamValueInt64((IntPtr)argint[n]);\r
+            break;\r
+          case TypeAffinity.Double:\r
+            parms[n] = _base.GetParamValueDouble((IntPtr)argint[n]);\r
+            break;\r
+          case TypeAffinity.Text:\r
+            parms[n] = _base.GetParamValueText((IntPtr)argint[n]);\r
+            break;\r
+          case TypeAffinity.Blob:\r
+            {\r
+              int x;\r
+              byte[] blob;\r
+\r
+              x = (int)_base.GetParamValueBytes((IntPtr)argint[n], 0, null, 0, 0);\r
+              blob = new byte[x];\r
+              _base.GetParamValueBytes((IntPtr)argint[n], 0, blob, 0, x);\r
+              parms[n] = blob;\r
+            }\r
+            break;\r
+          case TypeAffinity.DateTime: // Never happens here but what the heck, maybe it will one day.\r
+            parms[n] = _base.ToDateTime(_base.GetParamValueText((IntPtr)argint[n]));\r
+            break;\r
+        }\r
+      }\r
+      return parms;\r
+    }\r
+\r
+    /// <summary>\r
+    /// Takes the return value from Invoke() and Final() and figures out how to return it to SQLite's context.\r
+    /// </summary>\r
+    /// <param name="context">The context the return value applies to</param>\r
+    /// <param name="returnValue">The parameter to return to SQLite</param>\r
+    void SetReturnValue(IntPtr context, object returnValue)\r
+    {\r
+      if (returnValue == null || returnValue == DBNull.Value)\r
+      {\r
+        _base.ReturnNull(context);\r
+        return;\r
+      }\r
+\r
+      Type t = returnValue.GetType();\r
+      if (t == typeof(DateTime))\r
+      {\r
+        _base.ReturnText(context, _base.ToString((DateTime)returnValue));\r
+        return;\r
+      }\r
+      else\r
+      {\r
+        Exception r = returnValue as Exception;\r
+\r
+        if (r != null)\r
+        {\r
+          _base.ReturnError(context, r.Message);\r
+          return;\r
+        }\r
+      }\r
+\r
+      switch (SqliteConvert.TypeToAffinity(t))\r
+      {\r
+        case TypeAffinity.Null:\r
+          _base.ReturnNull(context);\r
+          return;\r
+        case TypeAffinity.Int64:\r
+          _base.ReturnInt64(context, Convert.ToInt64(returnValue, CultureInfo.CurrentCulture));\r
+          return;\r
+        case TypeAffinity.Double:\r
+          _base.ReturnDouble(context, Convert.ToDouble(returnValue, CultureInfo.CurrentCulture));\r
+          return;\r
+        case TypeAffinity.Text:\r
+          _base.ReturnText(context, returnValue.ToString());\r
+          return;\r
+        case TypeAffinity.Blob:\r
+          _base.ReturnBlob(context, (byte[])returnValue);\r
+          return;\r
+      }\r
+    }\r
+\r
+    /// <summary>\r
+    /// Internal scalar callback function, which wraps the raw context pointer and calls the virtual Invoke() method.\r
+    /// </summary>\r
+    /// <param name="context">A raw context pointer</param>\r
+    /// <param name="nArgs">Number of arguments passed in</param>\r
+    /// <param name="argsptr">A pointer to the array of arguments</param>\r
+    internal void ScalarCallback(IntPtr context, int nArgs, IntPtr argsptr)\r
+    {\r
+      _context = context;\r
+      SetReturnValue(context, Invoke(ConvertParams(nArgs, argsptr)));\r
+    }\r
+\r
+    /// <summary>\r
+    /// Internal collation sequence function, which wraps up the raw string pointers and executes the Compare() virtual function.\r
+    /// </summary>\r
+    /// <param name="ptr">Not used</param>\r
+    /// <param name="len1">Length of the string pv1</param>\r
+    /// <param name="ptr1">Pointer to the first string to compare</param>\r
+    /// <param name="len2">Length of the string pv2</param>\r
+    /// <param name="ptr2">Pointer to the second string to compare</param>\r
+    /// <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\r
+    /// than the second.</returns>\r
+    internal int CompareCallback(IntPtr ptr, int len1, IntPtr ptr1, int len2, IntPtr ptr2)\r
+    {\r
+      return Compare(SqliteConvert.UTF8ToString(ptr1, len1), SqliteConvert.UTF8ToString(ptr2, len2));\r
+    }\r
+\r
+    internal int CompareCallback16(IntPtr ptr, int len1, IntPtr ptr1, int len2, IntPtr ptr2)\r
+    {\r
+      return Compare(SQLite3_UTF16.UTF16ToString(ptr1, len1), SQLite3_UTF16.UTF16ToString(ptr2, len2));\r
+    }\r
+\r
+    /// <summary>\r
+    /// The internal aggregate Step function callback, which wraps the raw context pointer and calls the virtual Step() method.\r
+    /// </summary>\r
+    /// <remarks>\r
+    /// This function takes care of doing the lookups and getting the important information put together to call the Step() function.\r
+    /// That includes pulling out the user's contextData and updating it after the call is made.  We use a sorted list for this so\r
+    /// binary searches can be done to find the data.\r
+    /// </remarks>\r
+    /// <param name="context">A raw context pointer</param>\r
+    /// <param name="nArgs">Number of arguments passed in</param>\r
+    /// <param name="argsptr">A pointer to the array of arguments</param>\r
+    internal void StepCallback(IntPtr context, int nArgs, IntPtr argsptr)\r
+    {\r
+      long nAux;\r
+      AggregateData data;\r
+\r
+      nAux = (long)_base.AggregateContext(context);\r
+      if (_contextDataList.TryGetValue(nAux, out data) == false)\r
+      {\r
+        data = new AggregateData();\r
+        _contextDataList[nAux] = data;\r
+      }\r
+\r
+      try\r
+      {\r
+        _context = context;\r
+        Step(ConvertParams(nArgs, argsptr), data._count, ref data._data);\r
+      }\r
+      finally\r
+      {\r
+        data._count++;\r
+      }\r
+    }\r
+\r
+    /// <summary>\r
+    /// An internal aggregate Final function callback, which wraps the context pointer and calls the virtual Final() method.\r
+    /// </summary>\r
+    /// <param name="context">A raw context pointer</param>\r
+    internal void FinalCallback(IntPtr context)\r
+    {\r
+      long n = (long)_base.AggregateContext(context);\r
+      object obj = null;\r
+\r
+      if (_contextDataList.ContainsKey(n))\r
+      {\r
+        obj = _contextDataList[n]._data;\r
+        _contextDataList.Remove(n);\r
+      }\r
+\r
+      _context = context;\r
+      SetReturnValue(context, Final(obj));\r
+\r
+      IDisposable disp = obj as IDisposable;\r
+      if (disp != null) disp.Dispose();\r
+    }\r
+\r
+    /// <summary>\r
+    /// Placeholder for a user-defined disposal routine\r
+    /// </summary>\r
+    /// <param name="disposing">True if the object is being disposed explicitly</param>\r
+    protected virtual void Dispose(bool disposing)\r
+    {\r
+      if (disposing)\r
+      {\r
+        IDisposable disp;\r
+\r
+        foreach (KeyValuePair<long, AggregateData> kv in _contextDataList)\r
+        {\r
+          disp = kv.Value._data as IDisposable;\r
+          if (disp != null)\r
+            disp.Dispose();\r
+        }\r
+        _contextDataList.Clear();\r
+\r
+        _InvokeFunc = null;\r
+        _StepFunc = null;\r
+        _FinalFunc = null;\r
+        _CompareFunc = null;\r
+        _base = null;\r
+        _contextDataList = null;\r
+      }\r
+    }\r
+\r
+    /// <summary>\r
+    /// Disposes of any active contextData variables that were not automatically cleaned up.  Sometimes this can happen if\r
+    /// someone closes the connection while a DataReader is open.\r
+    /// </summary>\r
+    public void Dispose()\r
+    {\r
+      Dispose(true);\r
+    }\r
+\r
+    /// <summary>\r
+    /// Using reflection, enumerate all assemblies in the current appdomain looking for classes that\r
+    /// have a SqliteFunctionAttribute attribute, and registering them accordingly.\r
+    /// </summary>\r
+#if !PLATFORM_COMPACTFRAMEWORK\r
+    [global::System.Security.Permissions.FileIOPermission(global::System.Security.Permissions.SecurityAction.Assert, AllFiles = global::System.Security.Permissions.FileIOPermissionAccess.PathDiscovery)]\r
+#endif\r
+    static SqliteFunction()\r
+    {\r
+      try\r
+      {\r
+#if !PLATFORM_COMPACTFRAMEWORK\r
+        SqliteFunctionAttribute at;\r
+        System.Reflection.Assembly[] arAssemblies = System.AppDomain.CurrentDomain.GetAssemblies();\r
+        int w = arAssemblies.Length;\r
+        System.Reflection.AssemblyName sqlite = System.Reflection.Assembly.GetCallingAssembly().GetName();\r
+\r
+        for (int n = 0; n < w; n++)\r
+        {\r
+          Type[] arTypes;\r
+          bool found = false;\r
+          System.Reflection.AssemblyName[] references;\r
+          try\r
+          {\r
+            // Inspect only assemblies that reference SQLite\r
+            references = arAssemblies[n].GetReferencedAssemblies();\r
+            int t = references.Length;\r
+            for (int z = 0; z < t; z++)\r
+            {\r
+              if (references[z].Name == sqlite.Name)\r
+              {\r
+                found = true;\r
+                break;\r
+              }\r
+            }\r
+\r
+            if (found == false)\r
+              continue;\r
+\r
+            arTypes = arAssemblies[n].GetTypes();\r
+          }\r
+          catch (global::System.Reflection.ReflectionTypeLoadException e)\r
+          {\r
+            arTypes = e.Types;\r
+          }\r
+\r
+          int v = arTypes.Length;\r
+          for (int x = 0; x < v; x++)\r
+          {\r
+            if (arTypes[x] == null) continue;\r
+\r
+            object[] arAtt = arTypes[x].GetCustomAttributes(typeof(SqliteFunctionAttribute), false);\r
+            int u = arAtt.Length;\r
+            for (int y = 0; y < u; y++)\r
+            {\r
+              at = arAtt[y] as SqliteFunctionAttribute;\r
+              if (at != null)\r
+              {\r
+                at._instanceType = arTypes[x];\r
+                _registeredFunctions.Add(at);\r
+              }\r
+            }\r
+          }\r
+        }\r
+#endif\r
+      }\r
+      catch // SQLite provider can continue without being able to find built-in functions\r
+      {\r
+      }\r
+    }\r
+    /// <summary>\r
+    /// Manual method of registering a function.  The type must still have the SqliteFunctionAttributes in order to work\r
+    /// properly, but this is a workaround for the Compact Framework where enumerating assemblies is not currently supported.\r
+    /// </summary>\r
+    /// <param name="typ">The type of the function to register</param>\r
+    public static void RegisterFunction(Type typ)\r
+    {\r
+      object[] arAtt = typ.GetCustomAttributes(typeof(SqliteFunctionAttribute), false);\r
+      int u = arAtt.Length;\r
+      SqliteFunctionAttribute at;\r
+\r
+      for (int y = 0; y < u; y++)\r
+      {\r
+        at = arAtt[y] as SqliteFunctionAttribute;\r
+        if (at != null)\r
+        {\r
+          at._instanceType = typ;\r
+          _registeredFunctions.Add(at);\r
+        }\r
+      }\r
+    }\r
+\r
+    /// <summary>\r
+    /// Called by SQLiteBase derived classes, this function binds all user-defined functions to a connection.\r
+    /// It is done this way so that all user-defined functions will access the database using the same encoding scheme\r
+    /// as the connection (UTF-8 or UTF-16).\r
+    /// </summary>\r
+    /// <remarks>\r
+    /// The wrapper functions that interop with SQLite will create a unique cookie value, which internally is a pointer to\r
+    /// all the wrapped callback functions.  The interop function uses it to map CDecl callbacks to StdCall callbacks.\r
+    /// </remarks>\r
+    /// <param name="sqlbase">The base object on which the functions are to bind</param>\r
+    /// <returns>Returns an array of functions which the connection object should retain until the connection is closed.</returns>\r
+    internal static SqliteFunction[] BindFunctions(SQLiteBase sqlbase)\r
+    {\r
+      SqliteFunction f;\r
+      List<SqliteFunction> lFunctions = new List<SqliteFunction>();\r
+\r
+      foreach (SqliteFunctionAttribute pr in _registeredFunctions)\r
+      {\r
+        f = (SqliteFunction)Activator.CreateInstance(pr._instanceType);\r
+        f._base = sqlbase;\r
+        f._InvokeFunc = (pr.FuncType == FunctionType.Scalar) ? new SQLiteCallback(f.ScalarCallback) : null;\r
+        f._StepFunc = (pr.FuncType == FunctionType.Aggregate) ? new SQLiteCallback(f.StepCallback) : null;\r
+        f._FinalFunc = (pr.FuncType == FunctionType.Aggregate) ? new SQLiteFinalCallback(f.FinalCallback) : null;\r
+        f._CompareFunc = (pr.FuncType == FunctionType.Collation) ? new SQLiteCollation(f.CompareCallback) : null;\r
+        f._CompareFunc16 = (pr.FuncType == FunctionType.Collation) ? new SQLiteCollation(f.CompareCallback16) : null;\r
+\r
+        if (pr.FuncType != FunctionType.Collation)\r
+          sqlbase.CreateFunction(pr.Name, pr.Arguments, (f is SqliteFunctionEx), f._InvokeFunc, f._StepFunc, f._FinalFunc);\r
+        else {\r
+#if MONOTOUCH\r
+          GCHandle handle = GCHandle.Alloc (f);\r
+          sqlbase.CreateCollation(pr.Name, collation_callback, collation_callback16, GCHandle.ToIntPtr (handle));\r
+#else\r
+          sqlbase.CreateCollation(pr.Name, f._CompareFunc, f._CompareFunc16, IntPtr.Zero);\r
+#endif\r
+        }\r
+\r
+\r
+        lFunctions.Add(f);\r
+      }\r
+\r
+      SqliteFunction[] arFunctions = new SqliteFunction[lFunctions.Count];\r
+      lFunctions.CopyTo(arFunctions, 0);\r
+\r
+      return arFunctions;\r
+    }\r
+\r
+#if MONOTOUCH\r
+    [MonoTouch.MonoPInvokeCallback (typeof (SQLiteCollation))]\r
+    internal static int collation_callback (IntPtr puser, int len1, IntPtr pv1, int len2, IntPtr pv2)\r
+    {\r
+      var handle = GCHandle.FromIntPtr (puser);\r
+      var func = (SqliteFunction) handle.Target;\r
+      return func._CompareFunc (IntPtr.Zero, len1, pv1, len2, pv2);\r
+    }\r
+\r
+    [MonoTouch.MonoPInvokeCallback (typeof (SQLiteCollation))]\r
+    internal static int collation_callback16 (IntPtr puser, int len1, IntPtr pv1, int len2, IntPtr pv2)\r
+    {\r
+      var handle = GCHandle.FromIntPtr (puser);\r
+      var func = (SqliteFunction) handle.Target;\r
+      return func._CompareFunc16 (IntPtr.Zero, len1, pv1, len2, pv2);\r
+    }\r
+#endif\r
+  }\r
+\r
+  /// <summary>\r
+  /// Extends SqliteFunction and allows an inherited class to obtain the collating sequence associated with a function call.\r
+  /// </summary>\r
+  /// <remarks>\r
+  /// User-defined functions can call the GetCollationSequence() method in this class and use it to compare strings and char arrays.\r
+  /// </remarks>\r
+  public class SqliteFunctionEx : SqliteFunction\r
+  {\r
+    /// <summary>\r
+    /// Obtains the collating sequence in effect for the given function.\r
+    /// </summary>\r
+    /// <returns></returns>\r
+    protected CollationSequence GetCollationSequence()\r
+    {\r
+      return _base.GetCollationSequence(this, _context);\r
+    }\r
+  }\r
+\r
+  /// <summary>\r
+  /// The type of user-defined function to declare\r
+  /// </summary>\r
+  public enum FunctionType\r
+  {\r
+    /// <summary>\r
+    /// Scalar functions are designed to be called and return a result immediately.  Examples include ABS(), Upper(), Lower(), etc.\r
+    /// </summary>\r
+    Scalar = 0,\r
+    /// <summary>\r
+    /// Aggregate functions are designed to accumulate data until the end of a call and then return a result gleaned from the accumulated data.\r
+    /// Examples include SUM(), COUNT(), AVG(), etc.\r
+    /// </summary>\r
+    Aggregate = 1,\r
+    /// <summary>\r
+    /// 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\r
+    /// sorted using a straight case-insensitive comparison function.  Custom collating sequences can be used to alter the behavior of text sorting\r
+    /// in a user-defined manner.\r
+    /// </summary>\r
+    Collation = 2,\r
+  }\r
+\r
+  /// <summary>\r
+  /// An internal callback delegate declaration.\r
+  /// </summary>\r
+  /// <param name="context">Raw context pointer for the user function</param>\r
+  /// <param name="nArgs">Count of arguments to the function</param>\r
+  /// <param name="argsptr">A pointer to the array of argument pointers</param>\r
+#if !PLATFORM_COMPACTFRAMEWORK\r
+  [UnmanagedFunctionPointer(CallingConvention.Cdecl)]\r
+#endif\r
+  internal delegate void SQLiteCallback(IntPtr context, int nArgs, IntPtr argsptr);\r
+  /// <summary>\r
+  /// An internal final callback delegate declaration.\r
+  /// </summary>\r
+  /// <param name="context">Raw context pointer for the user function</param>\r
+#if !PLATFORM_COMPACTFRAMEWORK\r
+  [UnmanagedFunctionPointer(CallingConvention.Cdecl)]\r
+#endif\r
+  internal delegate void SQLiteFinalCallback(IntPtr context);\r
+  /// <summary>\r
+  /// Internal callback delegate for implementing collation sequences\r
+  /// </summary>\r
+  /// <param name="puser">Not used</param>\r
+  /// <param name="len1">Length of the string pv1</param>\r
+  /// <param name="pv1">Pointer to the first string to compare</param>\r
+  /// <param name="len2">Length of the string pv2</param>\r
+  /// <param name="pv2">Pointer to the second string to compare</param>\r
+  /// <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\r
+  /// than the second.</returns>\r
+#if !PLATFORM_COMPACTFRAMEWORK\r
+  [UnmanagedFunctionPointer(CallingConvention.Cdecl)]\r
+#endif\r
+  internal delegate int SQLiteCollation(IntPtr puser, int len1, IntPtr pv1, int len2, IntPtr pv2);\r
+\r
+  /// <summary>\r
+  /// The type of collating sequence\r
+  /// </summary>\r
+  public enum CollationTypeEnum\r
+  {\r
+    /// <summary>\r
+    /// The built-in BINARY collating sequence\r
+    /// </summary>\r
+    Binary = 1,\r
+    /// <summary>\r
+    /// The built-in NOCASE collating sequence\r
+    /// </summary>\r
+    NoCase = 2,\r
+    /// <summary>\r
+    /// The built-in REVERSE collating sequence\r
+    /// </summary>\r
+    Reverse = 3,\r
+    /// <summary>\r
+    /// A custom user-defined collating sequence\r
+    /// </summary>\r
+    Custom = 0,\r
+  }\r
+\r
+  /// <summary>\r
+  /// The encoding type the collation sequence uses\r
+  /// </summary>\r
+  public enum CollationEncodingEnum\r
+  {\r
+    /// <summary>\r
+    /// The collation sequence is UTF8\r
+    /// </summary>\r
+    UTF8 = 1,\r
+    /// <summary>\r
+    /// The collation sequence is UTF16 little-endian\r
+    /// </summary>\r
+    UTF16LE = 2,\r
+    /// <summary>\r
+    /// The collation sequence is UTF16 big-endian\r
+    /// </summary>\r
+    UTF16BE = 3,\r
+  }\r
+\r
+  /// <summary>\r
+  /// A struct describing the collating sequence a function is executing in\r
+  /// </summary>\r
+  public struct CollationSequence\r
+  {\r
+    /// <summary>\r
+    /// The name of the collating sequence\r
+    /// </summary>\r
+    public string Name;\r
+    /// <summary>\r
+    /// The type of collating sequence\r
+    /// </summary>\r
+    public CollationTypeEnum Type;\r
+\r
+    /// <summary>\r
+    /// The text encoding of the collation sequence\r
+    /// </summary>\r
+    public CollationEncodingEnum Encoding;\r
+\r
+    /// <summary>\r
+    /// Context of the function that requested the collating sequence\r
+    /// </summary>\r
+    internal SqliteFunction _func;\r
+\r
+    /// <summary>\r
+    /// Calls the base collating sequence to compare two strings\r
+    /// </summary>\r
+    /// <param name="s1">The first string to compare</param>\r
+    /// <param name="s2">The second string to compare</param>\r
+    /// <returns>-1 if s1 is less than s2, 0 if s1 is equal to s2, and 1 if s1 is greater than s2</returns>\r
+    public int Compare(string s1, string s2)\r
+    {\r
+      return _func._base.ContextCollateCompare(Encoding, _func._context, s1, s2);\r
+    }\r
+\r
+    /// <summary>\r
+    /// Calls the base collating sequence to compare two character arrays\r
+    /// </summary>\r
+    /// <param name="c1">The first array to compare</param>\r
+    /// <param name="c2">The second array to compare</param>\r
+    /// <returns>-1 if c1 is less than c2, 0 if c1 is equal to c2, and 1 if c1 is greater than c2</returns>\r
+    public int Compare(char[] c1, char[] c2)\r
+    {\r
+      return _func._base.ContextCollateCompare(Encoding, _func._context, c1, c2);\r
+    }\r
+  }\r
+}\r