?? sqlitefunction.cs
字號:
?/********************************************************
* 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!
********************************************************/
namespace System.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
{
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -