System.Data.SQLite
Check-in [d1cfa62cb0]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Experimental changes to support implementing a SQLiteFunction using a generic delegate.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | delegateFunction
Files: files | file ages | folders
SHA1: d1cfa62cb03d0b7a88935f7c69fe3a7908e4057b
User & Date: mistachkin 2015-08-04 22:54:35
Context
2015-08-05
00:55
Coding style enhancements. check-in: 0ebe466b2a user: mistachkin tags: delegateFunction
2015-08-04
22:54
Experimental changes to support implementing a SQLiteFunction using a generic delegate. check-in: d1cfa62cb0 user: mistachkin tags: delegateFunction
2015-07-30
18:30
Update release procedures wiki page. check-in: fc9062d656 user: mistachkin tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to System.Data.SQLite/SQLiteConnection.cs.

  1379   1379       ///////////////////////////////////////////////////////////////////////////////////////////////
  1380   1380   
  1381   1381       /// <summary>
  1382   1382       /// Attempts to bind the specified <see cref="SQLiteFunction" /> object
  1383   1383       /// instance to this connection.
  1384   1384       /// </summary>
  1385   1385       /// <param name="functionAttribute">
  1386         -    /// The <see cref="SQLiteFunctionAttribute"/> object instance containing
         1386  +    /// The <see cref="SQLiteFunctionAttribute" /> object instance containing
  1387   1387       /// the metadata for the function to be bound.
  1388   1388       /// </param>
  1389   1389       /// <param name="function">
  1390         -    /// The <see cref="SQLiteFunction"/> object instance that implements the
         1390  +    /// The <see cref="SQLiteFunction" /> object instance that implements the
  1391   1391       /// function to be bound.
  1392   1392       /// </param>
  1393   1393       public void BindFunction(
  1394   1394           SQLiteFunctionAttribute functionAttribute,
  1395   1395           SQLiteFunction function
  1396   1396           )
  1397   1397       {
................................................................................
  1399   1399   
  1400   1400           if (_sql == null)
  1401   1401               throw new InvalidOperationException(
  1402   1402                   "Database connection not valid for binding functions.");
  1403   1403   
  1404   1404           _sql.BindFunction(functionAttribute, function, _flags);
  1405   1405       }
         1406  +
         1407  +    ///////////////////////////////////////////////////////////////////////////////////////////////
         1408  +
         1409  +    /// <summary>
         1410  +    /// Attempts to bind the specified <see cref="SQLiteFunction" /> object
         1411  +    /// instance to this connection.
         1412  +    /// </summary>
         1413  +    /// <param name="functionAttribute">
         1414  +    /// The <see cref="SQLiteFunctionAttribute" /> object instance containing
         1415  +    /// the metadata for the function to be bound.
         1416  +    /// </param>
         1417  +    /// <param name="callback">
         1418  +    /// The <see cref="Delegate" /> object instance that implements the
         1419  +    /// function to be bound.
         1420  +    /// </param>
         1421  +    public void BindFunction(
         1422  +        SQLiteFunctionAttribute functionAttribute,
         1423  +        Delegate callback
         1424  +        )
         1425  +    {
         1426  +        CheckDisposed();
         1427  +
         1428  +        if (_sql == null)
         1429  +            throw new InvalidOperationException(
         1430  +                "Database connection not valid for binding functions.");
         1431  +
         1432  +        _sql.BindFunction(functionAttribute,
         1433  +            new SQLiteDelegateFunction(callback), _flags);
         1434  +    }
  1406   1435   
  1407   1436       ///////////////////////////////////////////////////////////////////////////////////////////////
  1408   1437   
  1409   1438       /// <summary>
  1410   1439       /// Attempts to unbind the specified <see cref="SQLiteFunction" /> object
  1411   1440       /// instance to this connection.
  1412   1441       /// </summary>

Changes to System.Data.SQLite/SQLiteFunction.cs.

    63     63       /// </summary>
    64     64       private SQLiteCallback  _StepFunc;
    65     65       /// <summary>
    66     66       /// Holds a reference to the callback function for finalizing an aggregate function
    67     67       /// </summary>
    68     68       private SQLiteFinalCallback  _FinalFunc;
    69     69       /// <summary>
    70         -    /// Holds a reference to the callback function for collation sequences
           70  +    /// Holds a reference to the callback function for collating sequences
    71     71       /// </summary>
    72     72       private SQLiteCollation _CompareFunc;
    73     73   
    74     74       private SQLiteCollation _CompareFunc16;
    75     75   
    76     76       /// <summary>
    77     77       /// Current context of the current callback.  Only valid during a callback
................................................................................
   273    273       public virtual object Final(object contextData)
   274    274       {
   275    275         CheckDisposed();
   276    276         return null;
   277    277       }
   278    278   
   279    279       /// <summary>
   280         -    /// User-defined collation sequences override this method to provide a custom string sorting algorithm.
          280  +    /// User-defined collating sequences override this method to provide a custom string sorting algorithm.
   281    281       /// </summary>
   282    282       /// <param name="param1">The first string to compare</param>
   283    283       /// <param name="param2">The second strnig to compare</param>
   284    284       /// <returns>1 if param1 is greater than param2, 0 if they are equal, or -1 if param1 is less than param2</returns>
   285    285       public virtual int Compare(string param1, string param2)
   286    286       {
   287    287         CheckDisposed();
................................................................................
   426    426               {
   427    427                   // do nothing.
   428    428               }
   429    429           }
   430    430       }
   431    431   
   432    432       /// <summary>
   433         -    /// Internal collation sequence function, which wraps up the raw string pointers and executes the Compare() virtual function.
          433  +    /// Internal collating sequence function, which wraps up the raw string pointers and executes the Compare() virtual function.
   434    434       /// WARNING: Must not throw exceptions.
   435    435       /// </summary>
   436    436       /// <param name="ptr">Not used</param>
   437    437       /// <param name="len1">Length of the string pv1</param>
   438    438       /// <param name="ptr1">Pointer to the first string to compare</param>
   439    439       /// <param name="len2">Length of the string pv2</param>
   440    440       /// <param name="ptr2">Pointer to the second string to compare</param>
................................................................................
   473    473           if ((_base != null) && _base.IsOpen())
   474    474               _base.Cancel();
   475    475   
   476    476           return 0;
   477    477       }
   478    478   
   479    479       /// <summary>
   480         -    /// Internal collation sequence function, which wraps up the raw string pointers and executes the Compare() virtual function.
          480  +    /// Internal collating sequence function, which wraps up the raw string pointers and executes the Compare() virtual function.
   481    481       /// WARNING: Must not throw exceptions.
   482    482       /// </summary>
   483    483       /// <param name="ptr">Not used</param>
   484    484       /// <param name="len1">Length of the string pv1</param>
   485    485       /// <param name="ptr1">Pointer to the first string to compare</param>
   486    486       /// <param name="len2">Length of the string pv2</param>
   487    487       /// <param name="ptr2">Pointer to the second string to compare</param>
................................................................................
   724    724       /// <summary>
   725    725       /// Manual method of registering a function.  The type must still have the SQLiteFunctionAttributes in order to work
   726    726       /// properly, but this is a workaround for the Compact Framework where enumerating assemblies is not currently supported.
   727    727       /// </summary>
   728    728       /// <param name="typ">The type of the function to register</param>
   729    729       public static void RegisterFunction(Type typ)
   730    730       {
   731         -      object[] arAtt = typ.GetCustomAttributes(typeof(SQLiteFunctionAttribute), false);
   732         -      int u = arAtt.Length;
   733         -      SQLiteFunctionAttribute at;
   734         -
   735         -      for (int y = 0; y < u; y++)
   736         -      {
   737         -        at = arAtt[y] as SQLiteFunctionAttribute;
   738         -        if (at != null)
          731  +        object[] arAtt = typ.GetCustomAttributes(
          732  +            typeof(SQLiteFunctionAttribute), false);
          733  +
          734  +        for (int y = 0; y < arAtt.Length; y++)
          735  +        {
          736  +            SQLiteFunctionAttribute at = arAtt[y] as SQLiteFunctionAttribute;
          737  +
          738  +            if (at == null)
          739  +                continue;
          740  +
          741  +            RegisterFunction(
          742  +                at.Name, at.Arguments, at.FuncType, at.InstanceType,
          743  +                at.Callback);
          744  +        }
          745  +    }
          746  +
          747  +    /// <summary>
          748  +    /// Alternative method of registering a function.  This method
          749  +    /// does not require the specified type to be annotated with
          750  +    /// <see cref="SQLiteFunctionAttribute" />.
          751  +    /// </summary>
          752  +    /// <param name="name">
          753  +    /// The name of the function to register.
          754  +    /// </param>
          755  +    /// <param name="argumentCount">
          756  +    /// The number of arguments accepted by the function.
          757  +    /// </param>
          758  +    /// <param name="functionType">
          759  +    /// The type of SQLite function being resitered (e.g. scalar,
          760  +    /// aggregate, or collating sequence).
          761  +    /// </param>
          762  +    /// <param name="instanceType">
          763  +    /// The <see cref="Type" /> that actually implements the function.
          764  +    /// This will only be used if the <paramref name="callback" />
          765  +    /// parameter is null.
          766  +    /// </param>
          767  +    /// <param name="callback">
          768  +    /// The <see cref="Delegate" /> that implements the function.  If
          769  +    /// this is non-null, the <paramref name="instanceType" /> parameter
          770  +    /// will be ignored when the function is invoked.
          771  +    /// </param>
          772  +    public static void RegisterFunction(
          773  +        string name,
          774  +        int argumentCount,
          775  +        FunctionType functionType,
          776  +        Type instanceType,
          777  +        Delegate callback
          778  +        )
          779  +    {
          780  +        SQLiteFunctionAttribute at = new SQLiteFunctionAttribute(
          781  +            name, argumentCount, functionType);
          782  +
          783  +        at.InstanceType = instanceType;
          784  +        at.Callback = callback;
          785  +
          786  +        _registeredFunctions.Add(at, null);
          787  +    }
          788  +
          789  +    /// <summary>
          790  +    /// Creates a <see cref="SQLiteFunction" /> instance based on the specified
          791  +    /// <see cref="SQLiteFunctionAttribute" />.
          792  +    /// </summary>
          793  +    /// <param name="functionAttribute">
          794  +    /// The <see cref="SQLiteFunctionAttribute" /> containing the metadata about
          795  +    /// the function to create.
          796  +    /// </param>
          797  +    /// <param name="function">
          798  +    /// The created function -OR- null if the function could not be created.
          799  +    /// </param>
          800  +    /// <returns>
          801  +    /// Non-zero if the function was created; otherwise, zero.
          802  +    /// </returns>
          803  +    private static bool CreateFunction(
          804  +        SQLiteFunctionAttribute functionAttribute,
          805  +        out SQLiteFunction function
          806  +        )
          807  +    {
          808  +        if (functionAttribute == null)
          809  +        {
          810  +            function = null;
          811  +            return false;
          812  +        }
          813  +        else if (functionAttribute.Callback != null)
          814  +        {
          815  +            function = new SQLiteDelegateFunction(
          816  +                functionAttribute.Callback);
          817  +
          818  +            return true;
          819  +        }
          820  +        else if (functionAttribute.InstanceType != null)
   739    821           {
   740         -          at.InstanceType = typ;
   741         -          _registeredFunctions.Add(at, null);
          822  +            function = (SQLiteFunction)Activator.CreateInstance(
          823  +                functionAttribute.InstanceType);
          824  +
          825  +            return true;
   742    826           }
   743         -      }
          827  +        else
          828  +        {
          829  +            function = null;
          830  +            return false;
          831  +        }
   744    832       }
   745    833   
   746    834       /// <summary>
   747    835       /// Called by the SQLiteBase derived classes, this method binds all registered (known) user-defined functions to a connection.
   748    836       /// It is done this way so that all user-defined functions will access the database using the same encoding scheme
   749    837       /// as the connection (UTF-8 or UTF-16).
   750    838       /// </summary>
................................................................................
   767    855                   in _registeredFunctions)
   768    856           {
   769    857               SQLiteFunctionAttribute pr = pair.Key;
   770    858   
   771    859               if (pr == null)
   772    860                   continue;
   773    861   
   774         -            SQLiteFunction f = (SQLiteFunction)Activator.CreateInstance(
   775         -                pr.InstanceType);
          862  +            SQLiteFunction f;
   776    863   
   777         -            BindFunction(sqlbase, pr, f, flags);
   778         -            lFunctions[pr] = f;
          864  +            if (CreateFunction(pr, out f))
          865  +            {
          866  +                BindFunction(sqlbase, pr, f, flags);
          867  +                lFunctions[pr] = f;
          868  +            }
          869  +            else
          870  +            {
          871  +                lFunctions[pr] = null;
          872  +            }
   779    873           }
   780    874   
   781    875           return lFunctions;
   782    876       }
   783    877   
   784    878       /// <summary>
   785    879       /// Called by the SQLiteBase derived classes, this method unbinds all registered (known)
................................................................................
   857    951               }
   858    952           }
   859    953   
   860    954           return result;
   861    955       }
   862    956   
   863    957       /// <summary>
   864         -    /// This function binds a user-defined functions to a connection.
          958  +    /// This function binds a user-defined function to a connection.
   865    959       /// </summary>
   866    960       /// <param name="sqliteBase">
   867    961       /// The <see cref="SQLiteBase" /> object instance associated with the
   868    962       /// <see cref="SQLiteConnection" /> that the function should be bound to.
   869    963       /// </param>
   870    964       /// <param name="functionAttribute">
   871    965       /// The <see cref="SQLiteFunctionAttribute"/> object instance containing
................................................................................
   985   1079                   name, null, null, false) == SQLiteErrorCode.Ok;
   986   1080           }
   987   1081       }
   988   1082     }
   989   1083   
   990   1084   
   991   1085   
         1086  +  /////////////////////////////////////////////////////////////////////////////
         1087  +
         1088  +  /// <summary>
         1089  +  /// This class implements a SQLite function using a <see cref="Delegate" />.
         1090  +  /// All the virtual methods of the <see cref="SQLiteFunction" /> class are
         1091  +  /// implemented using calls to the <see cref="Delegate.DynamicInvoke" />
         1092  +  /// method.  The arguments are presented in the same order they appear in
         1093  +  /// the associated <see cref="SQLiteFunction" /> methods with one exception:
         1094  +  /// the first argument is the name of the virtual method being implemented.
         1095  +  /// </summary>
         1096  +  public class SQLiteDelegateFunction : SQLiteFunction
         1097  +  {
         1098  +      #region Private Constants
         1099  +      /// <summary>
         1100  +      /// This error message is used by the overridden virtual methods when the
         1101  +      /// callback has not been set.
         1102  +      /// </summary>
         1103  +      private const string NoCallbackError = "No callback is set.";
         1104  +
         1105  +      /////////////////////////////////////////////////////////////////////////
         1106  +
         1107  +      /// <summary>
         1108  +      /// This error message is used by the overridden <see cref="Compare" />
         1109  +      /// method when the result does not have a type of <see cref="Int32" />.
         1110  +      /// </summary>
         1111  +      private const string ResultInt32Error = "\"{0}\" result must be Int32.";
         1112  +      #endregion
         1113  +
         1114  +      /////////////////////////////////////////////////////////////////////////
         1115  +
         1116  +      #region Public Constructors
         1117  +      /// <summary>
         1118  +      /// Constructs an empty instance of this class.
         1119  +      /// </summary>
         1120  +      public SQLiteDelegateFunction()
         1121  +          : this(null)
         1122  +      {
         1123  +          // do nothing.
         1124  +      }
         1125  +
         1126  +      /////////////////////////////////////////////////////////////////////////
         1127  +
         1128  +      /// <summary>
         1129  +      /// Constructs an instance of this class using the specified
         1130  +      /// <see cref="Delegate" /> as the <see cref="SQLiteFunction" />
         1131  +      /// implementation.
         1132  +      /// </summary>
         1133  +      /// <param name="callback">
         1134  +      /// The <see cref="Delegate" /> to be used for all calls into the
         1135  +      /// virtual methods needed by the <see cref="SQLiteFunction" />
         1136  +      /// class.
         1137  +      /// </param>
         1138  +      public SQLiteDelegateFunction(
         1139  +          Delegate callback
         1140  +          )
         1141  +      {
         1142  +          this.callback = callback;
         1143  +      }
         1144  +      #endregion
         1145  +
         1146  +      /////////////////////////////////////////////////////////////////////////
         1147  +
         1148  +      #region Protected Methods
         1149  +      /// <summary>
         1150  +      /// Returns the list of arguments for the <see cref="Invoke" /> method,
         1151  +      /// as an <see cref="Array" /> of <see cref="Object" />.  The first
         1152  +      /// argument is always the literal string "Invoke".
         1153  +      /// </summary>
         1154  +      /// <param name="args">
         1155  +      /// The original arguments received by the <see cref="Invoke" /> method.
         1156  +      /// </param>
         1157  +      /// <returns>
         1158  +      /// The arguments to pass to the configured <see cref="Delegate" />.
         1159  +      /// </returns>
         1160  +      protected virtual object[] GetInvokeArgs(
         1161  +          object[] args
         1162  +          ) /* CANNOT RETURN NULL */
         1163  +      {
         1164  +          if (args == null)
         1165  +              return new object[] { "Invoke" };
         1166  +
         1167  +          object[] newArgs = new object[args.Length + 1];
         1168  +
         1169  +          newArgs[0] = "Invoke";
         1170  +
         1171  +          for (int index = 0; index < args.Length; index++)
         1172  +              newArgs[index + 1] = args[index];
         1173  +
         1174  +          return newArgs;
         1175  +      }
         1176  +
         1177  +      /////////////////////////////////////////////////////////////////////////
         1178  +
         1179  +      /// <summary>
         1180  +      /// Returns the list of arguments for the <see cref="Step" /> method,
         1181  +      /// as an <see cref="Array" /> of <see cref="Object" />.  The first
         1182  +      /// argument is always the literal string "Step".
         1183  +      /// </summary>
         1184  +      /// <param name="args">
         1185  +      /// The original arguments received by the <see cref="Step" /> method.
         1186  +      /// </param>
         1187  +      /// <param name="stepNumber">
         1188  +      /// The step number (one based).  This is incrememted each time the
         1189  +      /// <see cref="Step" /> method is called.
         1190  +      /// </param>
         1191  +      /// <param name="contextData">
         1192  +      /// A placeholder for implementers to store contextual data pertaining
         1193  +      /// to the current context.
         1194  +      /// </param>
         1195  +      /// <returns>
         1196  +      /// The arguments to pass to the configured <see cref="Delegate" />.
         1197  +      /// </returns>
         1198  +      protected virtual object[] GetStepArgs(
         1199  +          object[] args,
         1200  +          int stepNumber,
         1201  +          object contextData
         1202  +          ) /* CANNOT RETURN NULL */
         1203  +      {
         1204  +          int newLength = 3; /* "Step", stepNumber, contextData */
         1205  +
         1206  +          if (args != null)
         1207  +              newLength += args.Length;
         1208  +
         1209  +          object[] newArgs = new object[newLength];
         1210  +
         1211  +          newArgs[0] = "Step";
         1212  +
         1213  +          if (args != null)
         1214  +              for (int index = 0; index < args.Length; index++)
         1215  +                  newArgs[index + 1] = args[index];
         1216  +
         1217  +          newArgs[newLength - 2] = stepNumber;
         1218  +          newArgs[newLength - 1] = contextData;
         1219  +
         1220  +          return newArgs;
         1221  +      }
         1222  +
         1223  +      /////////////////////////////////////////////////////////////////////////
         1224  +
         1225  +      /// <summary>
         1226  +      /// Returns the list of arguments for the <see cref="Final" /> method,
         1227  +      /// as an <see cref="Array" /> of <see cref="Object" />.  The first
         1228  +      /// argument is always the literal string "Final".
         1229  +      /// </summary>
         1230  +      /// <param name="contextData">
         1231  +      /// A placeholder for implementers to store contextual data pertaining
         1232  +      /// to the current context.
         1233  +      /// </param>
         1234  +      /// <returns>
         1235  +      /// The arguments to pass to the configured <see cref="Delegate" />.
         1236  +      /// </returns>
         1237  +      protected virtual object[] GetFinalArgs(
         1238  +          object contextData
         1239  +          ) /* CANNOT RETURN NULL */
         1240  +      {
         1241  +          return new object[] { "Final", contextData };
         1242  +      }
         1243  +
         1244  +      /////////////////////////////////////////////////////////////////////////
         1245  +
         1246  +      /// <summary>
         1247  +      /// Returns the list of arguments for the <see cref="Compare" /> method,
         1248  +      /// as an <see cref="Array" /> of <see cref="Object" />.  The first
         1249  +      /// argument is always the literal string "Compare".
         1250  +      /// </summary>
         1251  +      /// <param name="param1">
         1252  +      /// The first string to compare.
         1253  +      /// </param>
         1254  +      /// <param name="param2">
         1255  +      /// The second strnig to compare.
         1256  +      /// </param>
         1257  +      /// <returns>
         1258  +      /// The arguments to pass to the configured <see cref="Delegate" />.
         1259  +      /// </returns>
         1260  +      protected virtual object[] GetCompareArgs(
         1261  +          string param1,
         1262  +          string param2
         1263  +          ) /* CANNOT RETURN NULL */
         1264  +      {
         1265  +          return new object[] { "Compare", param1, param2 };
         1266  +      }
         1267  +      #endregion
         1268  +
         1269  +      /////////////////////////////////////////////////////////////////////////
         1270  +
         1271  +      #region Public Properties
         1272  +      private Delegate callback;
         1273  +      /// <summary>
         1274  +      /// The <see cref="Delegate" /> to be used for all calls into the
         1275  +      /// virtual methods needed by the <see cref="SQLiteFunction" />
         1276  +      /// class.
         1277  +      /// </summary>
         1278  +      public virtual Delegate Callback
         1279  +      {
         1280  +          get { return callback; }
         1281  +          set { callback = value; }
         1282  +      }
         1283  +      #endregion
         1284  +
         1285  +      /////////////////////////////////////////////////////////////////////////
         1286  +
         1287  +      #region System.Data.SQLite.SQLiteFunction Overrides
         1288  +      /// <summary>
         1289  +      /// This virtual method is the implementation for scalar functions.
         1290  +      /// See the <see cref="SQLiteFunction.Invoke" /> method for more
         1291  +      /// details.
         1292  +      /// </summary>
         1293  +      /// <param name="args">
         1294  +      /// The arguments for the scalar function.  The first argument is always
         1295  +      /// the literal string "Invoke".  The remaining arguments, if any, are
         1296  +      /// passed exactly as they are received.
         1297  +      /// </param>
         1298  +      /// <returns>
         1299  +      /// The result of the scalar function.
         1300  +      /// </returns>
         1301  +      public override object Invoke(
         1302  +          object[] args /* in */
         1303  +          )
         1304  +      {
         1305  +          if (callback == null)
         1306  +              throw new InvalidOperationException(NoCallbackError);
         1307  +
         1308  +          return callback.DynamicInvoke(GetInvokeArgs(args)); /* throw */
         1309  +      }
         1310  +
         1311  +      /////////////////////////////////////////////////////////////////////////
         1312  +
         1313  +      /// <summary>
         1314  +      /// This virtual method is part of the implementation for aggregate
         1315  +      /// functions.  See the <see cref="SQLiteFunction.Step" /> method
         1316  +      /// for more details.
         1317  +      /// </summary>
         1318  +      /// <param name="args">
         1319  +      /// The arguments for the aggregate function.  The first argument is
         1320  +      /// always the literal string "Step".  The remaining arguments, if
         1321  +      /// any, are passed exactly as they are received.
         1322  +      /// </param>
         1323  +      /// <param name="stepNumber">
         1324  +      /// The step number (one based).  This is incrememted each time the
         1325  +      /// <see cref="Step" /> method is called.
         1326  +      /// </param>
         1327  +      /// <param name="contextData">
         1328  +      /// A placeholder for implementers to store contextual data pertaining
         1329  +      /// to the current context.
         1330  +      /// </param>
         1331  +      public override void Step(
         1332  +          object[] args,         /* in */
         1333  +          int stepNumber,        /* in */
         1334  +          ref object contextData /* in, out */
         1335  +          )
         1336  +      {
         1337  +          if (callback == null)
         1338  +              throw new InvalidOperationException(NoCallbackError);
         1339  +
         1340  +          object[] newArgs = GetStepArgs(args, stepNumber, contextData);
         1341  +
         1342  +          /* IGNORED */
         1343  +          callback.DynamicInvoke(newArgs); /* throw */
         1344  +
         1345  +          contextData = newArgs[newArgs.Length - 1]; /* out */
         1346  +      }
         1347  +
         1348  +      /////////////////////////////////////////////////////////////////////////
         1349  +
         1350  +      /// <summary>
         1351  +      /// This virtual method is part of the implementation for aggregate
         1352  +      /// functions.  See the <see cref="SQLiteFunction.Final" /> method
         1353  +      /// for more details.
         1354  +      /// </summary>
         1355  +      /// <param name="contextData">
         1356  +      /// A placeholder for implementers to store contextual data pertaining
         1357  +      /// to the current context.
         1358  +      /// </param>
         1359  +      /// <returns>
         1360  +      /// The result of the aggregate function.
         1361  +      /// </returns>
         1362  +      public override object Final(
         1363  +          object contextData /* in */
         1364  +          )
         1365  +      {
         1366  +          if (callback == null)
         1367  +              throw new InvalidOperationException(NoCallbackError);
         1368  +
         1369  +          return callback.DynamicInvoke(GetFinalArgs(contextData)); /* throw */
         1370  +      }
         1371  +
         1372  +      /////////////////////////////////////////////////////////////////////////
         1373  +
         1374  +      /// <summary>
         1375  +      /// This virtual method is part of the implementation for collating
         1376  +      /// sequences.  See the <see cref="SQLiteFunction.Compare" /> method
         1377  +      /// for more details.
         1378  +      /// </summary>
         1379  +      /// <param name="param1">
         1380  +      /// The first string to compare.
         1381  +      /// </param>
         1382  +      /// <param name="param2">
         1383  +      /// The second strnig to compare.
         1384  +      /// </param>
         1385  +      /// <returns>
         1386  +      /// A positive integer if the <paramref name="param1" /> parameter is
         1387  +      /// greater than the <paramref name="param2" /> parameter, a negative
         1388  +      /// integer if the <paramref name="param1" /> parameter is less than
         1389  +      /// the <paramref name="param2" /> parameter, or zero if they are
         1390  +      /// equal.
         1391  +      /// </returns>
         1392  +      public override int Compare(
         1393  +          string param1, /* in */
         1394  +          string param2  /* in */
         1395  +          )
         1396  +      {
         1397  +          if (callback == null)
         1398  +              throw new InvalidOperationException(NoCallbackError);
         1399  +
         1400  +          object[] newArgs = GetCompareArgs(param1, param2);
         1401  +          object result = callback.DynamicInvoke(newArgs); /* throw */
         1402  +
         1403  +          if (result is int)
         1404  +              return (int)result;
         1405  +
         1406  +          throw new InvalidOperationException(String.Format(
         1407  +              ResultInt32Error, newArgs[0]));
         1408  +      }
         1409  +      #endregion
         1410  +  }
         1411  +
         1412  +  /////////////////////////////////////////////////////////////////////////////
   992   1413   
   993   1414     /// <summary>
   994   1415     /// Extends SQLiteFunction and allows an inherited class to obtain the collating sequence associated with a function call.
   995   1416     /// </summary>
   996   1417     /// <remarks>
   997   1418     /// User-defined functions can call the GetCollationSequence() method in this class and use it to compare strings and char arrays.
   998   1419     /// </remarks>
................................................................................
  1063   1484       Scalar = 0,
  1064   1485       /// <summary>
  1065   1486       /// Aggregate functions are designed to accumulate data until the end of a call and then return a result gleaned from the accumulated data.
  1066   1487       /// Examples include SUM(), COUNT(), AVG(), etc.
  1067   1488       /// </summary>
  1068   1489       Aggregate = 1,
  1069   1490       /// <summary>
  1070         -    /// 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
         1491  +    /// Collating 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
  1071   1492       /// sorted using a straight case-insensitive comparison function.  Custom collating sequences can be used to alter the behavior of text sorting
  1072   1493       /// in a user-defined manner.
  1073   1494       /// </summary>
  1074   1495       Collation = 2,
  1075   1496     }
  1076   1497   
  1077   1498     /// <summary>
................................................................................
  1089   1510     /// </summary>
  1090   1511     /// <param name="context">Raw context pointer for the user function</param>
  1091   1512   #if !PLATFORM_COMPACTFRAMEWORK
  1092   1513     [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
  1093   1514   #endif
  1094   1515     internal delegate void SQLiteFinalCallback(IntPtr context);
  1095   1516     /// <summary>
  1096         -  /// Internal callback delegate for implementing collation sequences
         1517  +  /// Internal callback delegate for implementing collating sequences
  1097   1518     /// </summary>
  1098   1519     /// <param name="puser">Not used</param>
  1099   1520     /// <param name="len1">Length of the string pv1</param>
  1100   1521     /// <param name="pv1">Pointer to the first string to compare</param>
  1101   1522     /// <param name="len2">Length of the string pv2</param>
  1102   1523     /// <param name="pv2">Pointer to the second string to compare</param>
  1103   1524     /// <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

Changes to System.Data.SQLite/SQLiteFunctionAttribute.cs.

     1      1   /********************************************************
     2      2    * ADO.NET 2.0 Data Provider for SQLite Version 3.X
     3      3    * Written by Robert Simpson (robert@blackcastlesoft.com)
     4         - * 
            4  + *
     5      5    * Released to the public domain, use at your own risk!
     6      6    ********************************************************/
     7      7   
     8      8   namespace System.Data.SQLite
     9      9   {
    10     10     using System;
    11     11   
................................................................................
    16     16     [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
    17     17     public sealed class SQLiteFunctionAttribute : Attribute
    18     18     {
    19     19       private string       _name;
    20     20       private int          _argumentCount;
    21     21       private FunctionType _functionType;
    22     22       private Type         _instanceType;
           23  +    private Delegate     _callback;
    23     24   
    24     25       /// <summary>
    25     26       /// Default constructor, initializes the internal variables for the function.
    26     27       /// </summary>
    27     28       public SQLiteFunctionAttribute()
    28     29           : this(String.Empty, -1, FunctionType.Scalar)
    29     30       {
................................................................................
    49     50           FunctionType functionType
    50     51           )
    51     52       {
    52     53           _name = name;
    53     54           _argumentCount = argumentCount;
    54     55           _functionType = functionType;
    55     56           _instanceType = null;
           57  +        _callback = null;
    56     58       }
    57     59   
    58     60       /// <summary>
    59     61       /// The function's name as it will be used in SQLite command text.
    60     62       /// </summary>
    61     63       public string Name
    62     64       {
................................................................................
    80     82       {
    81     83         get { return _functionType; }
    82     84         set { _functionType = value; }
    83     85       }
    84     86   
    85     87       /// <summary>
    86     88       /// The <see cref="System.Type" /> object instance that describes the class
    87         -    /// containing the implementation for the associated function.
           89  +    /// containing the implementation for the associated function.  The value of
           90  +    /// this property will not be used if the <see cref="Callback" /> property
           91  +    /// value is set to non-null.
    88     92       /// </summary>
    89     93       internal Type InstanceType
    90     94       {
    91     95           get { return _instanceType; }
    92     96           set { _instanceType = value; }
    93     97       }
           98  +
           99  +    /// <summary>
          100  +    /// The <see cref="Delegate" /> that refers to the implementation for the
          101  +    /// associated function.  If this property value is set to non-null, it will
          102  +    /// be used instead of the <see cref="InstanceType" /> property value.
          103  +    /// </summary>
          104  +    internal Delegate Callback
          105  +    {
          106  +        get { return _callback; }
          107  +        set { _callback = value; }
          108  +    }
    94    109     }
    95    110   }