System.Data.SQLite
Check-in [3c25655a66]
Not logged in

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

Overview
Comment:Refactor SQLiteDelegateFunction constructor to accept two delegates, not one. Use early-bound delegates by default. Get tests passing.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | delegateFunction
Files: files | file ages | folders
SHA1: 3c25655a663df54c7bee64fcc2973c1b2c604ea0
User & Date: mistachkin 2015-08-15 03:48:55
Original Comment: Refactor SQLiteDelegateFunction constructor to accept two delegates, not one. Use late-bound delegates by default. Get tests passing.
Context
2015-08-15
04:04
Remove incorrect comments. check-in: b33115baa1 user: mistachkin tags: delegateFunction
03:48
Refactor SQLiteDelegateFunction constructor to accept two delegates, not one. Use early-bound delegates by default. Get tests passing. check-in: 3c25655a66 user: mistachkin tags: delegateFunction
2015-08-14
23:20
More work in progress fine-tuning the implementation. check-in: ef7ebd6469 user: mistachkin tags: delegateFunction
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

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

  1410   1410       /// Attempts to bind the specified <see cref="SQLiteFunction" /> object
  1411   1411       /// instance to this connection.
  1412   1412       /// </summary>
  1413   1413       /// <param name="functionAttribute">
  1414   1414       /// The <see cref="SQLiteFunctionAttribute" /> object instance containing
  1415   1415       /// the metadata for the function to be bound.
  1416   1416       /// </param>
  1417         -    /// <param name="callback">
  1418         -    /// The <see cref="Delegate" /> object instance that implements the
  1419         -    /// function to be bound.
         1417  +    /// <param name="callback1">
         1418  +    /// A <see cref="Delegate" /> object instance that helps implement the
         1419  +    /// function to be bound.  For aggregate functions, this corresponds to the
         1420  +    /// <see cref="SQLiteStepDelegate" /> callback.
         1421  +    /// </param>
         1422  +    /// <param name="callback2">
         1423  +    /// A <see cref="Delegate" /> object instance that helps implement the
         1424  +    /// function to be bound.  For aggregate functions, this corresponds to the
         1425  +    /// <see cref="SQLiteFinalDelegate" /> callback.  For other callback types,
         1426  +    /// it is not used and must be null.
  1420   1427       /// </param>
  1421   1428       public void BindFunction(
  1422   1429           SQLiteFunctionAttribute functionAttribute,
  1423         -        Delegate callback
         1430  +        Delegate callback1,
         1431  +        Delegate callback2
  1424   1432           )
  1425   1433       {
  1426   1434           CheckDisposed();
  1427   1435   
  1428   1436           if (_sql == null)
  1429   1437               throw new InvalidOperationException(
  1430   1438                   "Database connection not valid for binding functions.");
  1431   1439   
  1432   1440           _sql.BindFunction(functionAttribute,
  1433         -            new SQLiteDelegateFunction(callback), _flags);
         1441  +            new SQLiteDelegateFunction(callback1, callback2), _flags);
  1434   1442       }
  1435   1443   
  1436   1444       ///////////////////////////////////////////////////////////////////////////////////////////////
  1437   1445   
  1438   1446       /// <summary>
  1439   1447       /// Attempts to unbind the specified <see cref="SQLiteFunction" /> object
  1440   1448       /// instance to this connection.

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

   736    736               SQLiteFunctionAttribute at = arAtt[y] as SQLiteFunctionAttribute;
   737    737   
   738    738               if (at == null)
   739    739                   continue;
   740    740   
   741    741               RegisterFunction(
   742    742                   at.Name, at.Arguments, at.FuncType, at.InstanceType,
   743         -                at.Callback);
          743  +                at.Callback1, at.Callback2);
   744    744           }
   745    745       }
   746    746   
   747    747       /// <summary>
   748    748       /// Alternative method of registering a function.  This method
   749    749       /// does not require the specified type to be annotated with
   750    750       /// <see cref="SQLiteFunctionAttribute" />.
................................................................................
   757    757       /// </param>
   758    758       /// <param name="functionType">
   759    759       /// The type of SQLite function being resitered (e.g. scalar,
   760    760       /// aggregate, or collating sequence).
   761    761       /// </param>
   762    762       /// <param name="instanceType">
   763    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.
          764  +    /// This will only be used if the <paramref name="callback1" />
          765  +    /// and <paramref name="callback2" /> parameters are null.
   766    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.
          767  +    /// <param name="callback1">
          768  +    /// The <see cref="Delegate" /> to be used for all calls into the
          769  +    /// <see cref="SQLiteFunction.Invoke" />,
          770  +    /// <see cref="SQLiteFunction.Step" />,
          771  +    /// and <see cref="SQLiteFunction.Compare" /> virtual methods.
          772  +    /// </param>
          773  +    /// <param name="callback2">
          774  +    /// The <see cref="Delegate" /> to be used for all calls into the
          775  +    /// <see cref="SQLiteFunction.Final" /> virtual method.
   771    776       /// </param>
   772    777       public static void RegisterFunction(
   773    778           string name,
   774    779           int argumentCount,
   775    780           FunctionType functionType,
   776    781           Type instanceType,
   777         -        Delegate callback
          782  +        Delegate callback1,
          783  +        Delegate callback2
   778    784           )
   779    785       {
   780    786           SQLiteFunctionAttribute at = new SQLiteFunctionAttribute(
   781    787               name, argumentCount, functionType);
   782    788   
   783    789           at.InstanceType = instanceType;
   784         -        at.Callback = callback;
          790  +        at.Callback1 = callback1;
          791  +        at.Callback2 = callback2;
   785    792   
   786    793           _registeredFunctions.Add(at, null);
   787    794       }
   788    795   
   789    796       /// <summary>
   790    797       /// Creates a <see cref="SQLiteFunction" /> instance based on the specified
   791    798       /// <see cref="SQLiteFunctionAttribute" />.
................................................................................
   806    813           )
   807    814       {
   808    815           if (functionAttribute == null)
   809    816           {
   810    817               function = null;
   811    818               return false;
   812    819           }
   813         -        else if (functionAttribute.Callback != null)
          820  +        else if ((functionAttribute.Callback1 != null) ||
          821  +                (functionAttribute.Callback2 != null))
   814    822           {
   815    823               function = new SQLiteDelegateFunction(
   816         -                functionAttribute.Callback);
          824  +                functionAttribute.Callback1,
          825  +                functionAttribute.Callback2);
   817    826   
   818    827               return true;
   819    828           }
   820    829           else if (functionAttribute.InstanceType != null)
   821    830           {
   822    831               function = (SQLiteFunction)Activator.CreateInstance(
   823    832                   functionAttribute.InstanceType);
................................................................................
  1187   1196     /// the associated <see cref="SQLiteFunction" /> methods with one exception:
  1188   1197     /// the first argument is the name of the virtual method being implemented.
  1189   1198     /// </summary>
  1190   1199     public class SQLiteDelegateFunction : SQLiteFunction
  1191   1200     {
  1192   1201         #region Private Constants
  1193   1202         /// <summary>
  1194         -      /// This error message is used by the overridden virtual methods when the
  1195         -      /// callback has not been set.
         1203  +      /// This error message is used by the overridden virtual methods when
         1204  +      /// a required <see cref="Delegate" /> property (e.g.
         1205  +      /// <see cref="Callback1" /> or <see cref="Callback2" />) has not been
         1206  +      /// set.
  1196   1207         /// </summary>
  1197         -      private const string NoCallbackError = "No callback is set.";
         1208  +      private const string NoCallbackError = "No \"{0}\" callback is set.";
  1198   1209   
  1199   1210         /////////////////////////////////////////////////////////////////////////
  1200   1211   
  1201   1212         /// <summary>
  1202   1213         /// This error message is used by the overridden <see cref="Compare" />
  1203   1214         /// method when the result does not have a type of <see cref="Int32" />.
  1204   1215         /// </summary>
................................................................................
  1208   1219         /////////////////////////////////////////////////////////////////////////
  1209   1220   
  1210   1221         #region Public Constructors
  1211   1222         /// <summary>
  1212   1223         /// Constructs an empty instance of this class.
  1213   1224         /// </summary>
  1214   1225         public SQLiteDelegateFunction()
  1215         -          : this(null)
         1226  +          : this(null, null)
  1216   1227         {
  1217   1228             // do nothing.
  1218   1229         }
  1219   1230   
  1220   1231         /////////////////////////////////////////////////////////////////////////
  1221   1232   
  1222   1233         /// <summary>
  1223   1234         /// Constructs an instance of this class using the specified
  1224   1235         /// <see cref="Delegate" /> as the <see cref="SQLiteFunction" />
  1225   1236         /// implementation.
  1226   1237         /// </summary>
  1227         -      /// <param name="callback">
         1238  +      /// <param name="callback1">
         1239  +      /// The <see cref="Delegate" /> to be used for all calls into the
         1240  +      /// <see cref="Invoke" />, <see cref="Step" />, and
         1241  +      /// <see cref="Compare" /> virtual methods needed by the
         1242  +      /// <see cref="SQLiteFunction" /> base class.
         1243  +      /// </param>
         1244  +      /// <param name="callback2">
  1228   1245         /// The <see cref="Delegate" /> to be used for all calls into the
  1229         -      /// virtual methods needed by the <see cref="SQLiteFunction" />
  1230         -      /// class.
         1246  +      /// <see cref="Final" /> virtual methods needed by the
         1247  +      /// <see cref="SQLiteFunction" /> base class.
  1231   1248         /// </param>
  1232   1249         public SQLiteDelegateFunction(
  1233         -          Delegate callback
         1250  +          Delegate callback1,
         1251  +          Delegate callback2
  1234   1252             )
  1235   1253         {
  1236         -          this.callback = callback;
         1254  +          this.callback1 = callback1;
         1255  +          this.callback2 = callback2;
  1237   1256         }
  1238   1257         #endregion
  1239   1258   
  1240   1259         /////////////////////////////////////////////////////////////////////////
  1241   1260   
  1242   1261         #region Protected Methods
  1243   1262         /// <summary>
................................................................................
  1416   1435             return newArgs;
  1417   1436         }
  1418   1437         #endregion
  1419   1438   
  1420   1439         /////////////////////////////////////////////////////////////////////////
  1421   1440   
  1422   1441         #region Public Properties
  1423         -      private Delegate callback;
         1442  +      private Delegate callback1;
         1443  +      /// <summary>
         1444  +      /// The <see cref="Delegate" /> to be used for all calls into the
         1445  +      /// <see cref="Invoke" />, <see cref="Step" />, and
         1446  +      /// <see cref="Compare" /> virtual methods needed by the
         1447  +      /// <see cref="SQLiteFunction" /> base class.
         1448  +      /// </summary>
         1449  +      public virtual Delegate Callback1
         1450  +      {
         1451  +          get { return callback1; }
         1452  +          set { callback1 = value; }
         1453  +      }
         1454  +
         1455  +      /////////////////////////////////////////////////////////////////////////
         1456  +
         1457  +      private Delegate callback2;
  1424   1458         /// <summary>
  1425   1459         /// The <see cref="Delegate" /> to be used for all calls into the
  1426         -      /// virtual methods needed by the <see cref="SQLiteFunction" />
  1427         -      /// class.
         1460  +      /// <see cref="Final" /> virtual methods needed by the
         1461  +      /// <see cref="SQLiteFunction" /> base class.
  1428   1462         /// </summary>
  1429         -      public virtual Delegate Callback
         1463  +      public virtual Delegate Callback2
  1430   1464         {
  1431         -          get { return callback; }
  1432         -          set { callback = value; }
         1465  +          get { return callback2; }
         1466  +          set { callback2 = value; }
  1433   1467         }
  1434   1468         #endregion
  1435   1469   
  1436   1470         /////////////////////////////////////////////////////////////////////////
  1437   1471   
  1438   1472         #region System.Data.SQLite.SQLiteFunction Overrides
  1439   1473         /// <summary>
................................................................................
  1447   1481         /// <returns>
  1448   1482         /// The result of the scalar function.
  1449   1483         /// </returns>
  1450   1484         public override object Invoke(
  1451   1485             object[] args /* in */
  1452   1486             )
  1453   1487         {
  1454         -          if (callback == null)
  1455         -              throw new InvalidOperationException(NoCallbackError);
         1488  +          if (callback1 == null)
         1489  +          {
         1490  +              throw new InvalidOperationException(String.Format(
         1491  +                  NoCallbackError, "Invoke"));
         1492  +          }
  1456   1493   
  1457   1494             SQLiteInvokeDelegate invokeDelegate =
  1458         -              callback as SQLiteInvokeDelegate;
         1495  +              callback1 as SQLiteInvokeDelegate;
  1459   1496   
  1460   1497             if (invokeDelegate != null)
  1461   1498             {
  1462   1499                 return invokeDelegate.Invoke("Invoke", args); /* throw */
  1463   1500             }
  1464   1501             else
  1465   1502             {
  1466         -              return callback.DynamicInvoke(
         1503  +              return callback1.DynamicInvoke(
  1467   1504                     GetInvokeArgs(args, false)); /* throw */
  1468   1505             }
  1469   1506         }
  1470   1507   
  1471   1508         /////////////////////////////////////////////////////////////////////////
  1472   1509   
  1473   1510         /// <summary>
................................................................................
  1488   1525         /// </param>
  1489   1526         public override void Step(
  1490   1527             object[] args,         /* in */
  1491   1528             int stepNumber,        /* in */
  1492   1529             ref object contextData /* in, out */
  1493   1530             )
  1494   1531         {
  1495         -          if (callback == null)
  1496         -              throw new InvalidOperationException(NoCallbackError);
         1532  +          if (callback1 == null)
         1533  +          {
         1534  +              throw new InvalidOperationException(String.Format(
         1535  +                  NoCallbackError, "Step"));
         1536  +          }
  1497   1537   
  1498         -          SQLiteStepDelegate stepDelegate = callback as SQLiteStepDelegate;
         1538  +          SQLiteStepDelegate stepDelegate = callback1 as SQLiteStepDelegate;
  1499   1539   
  1500   1540             if (stepDelegate != null)
  1501   1541             {
  1502   1542                 stepDelegate.Invoke(
  1503   1543                     "Step", args, stepNumber, ref contextData); /* throw */
  1504   1544             }
  1505   1545             else
  1506   1546             {
  1507   1547                 object[] newArgs = GetStepArgs(
  1508   1548                     args, stepNumber, contextData, false);
  1509   1549   
  1510   1550                 /* IGNORED */
  1511         -              callback.DynamicInvoke(newArgs); /* throw */
         1551  +              callback1.DynamicInvoke(newArgs); /* throw */
  1512   1552   
  1513   1553                 UpdateStepArgs(newArgs, ref contextData, false);
  1514   1554             }
  1515   1555         }
  1516   1556   
  1517   1557         /////////////////////////////////////////////////////////////////////////
  1518   1558   
................................................................................
  1528   1568         /// <returns>
  1529   1569         /// The result of the aggregate function.
  1530   1570         /// </returns>
  1531   1571         public override object Final(
  1532   1572             object contextData /* in */
  1533   1573             )
  1534   1574         {
  1535         -          if (callback == null)
  1536         -              throw new InvalidOperationException(NoCallbackError);
         1575  +          if (callback2 == null)
         1576  +          {
         1577  +              throw new InvalidOperationException(String.Format(
         1578  +                  NoCallbackError, "Final"));
         1579  +          }
  1537   1580   
  1538         -          SQLiteFinalDelegate finalDelegate = callback as SQLiteFinalDelegate;
         1581  +          SQLiteFinalDelegate finalDelegate = callback2 as SQLiteFinalDelegate;
  1539   1582   
  1540   1583             if (finalDelegate != null)
  1541   1584             {
  1542         -              return finalDelegate.Invoke("Final", contextData);
         1585  +              return finalDelegate.Invoke("Final", contextData); /* throw */
  1543   1586             }
  1544   1587             else
  1545   1588             {
  1546         -              return callback.DynamicInvoke(GetFinalArgs(
  1547         -                  contextData, callback is SQLiteFinalDelegate)); /* throw */
         1589  +              return callback1.DynamicInvoke(GetFinalArgs(
         1590  +                  contextData, false)); /* throw */
  1548   1591             }
  1549   1592         }
  1550   1593   
  1551   1594         /////////////////////////////////////////////////////////////////////////
  1552   1595   
  1553   1596         /// <summary>
  1554   1597         /// This virtual method is part of the implementation for collating
................................................................................
  1569   1612         /// equal.
  1570   1613         /// </returns>
  1571   1614         public override int Compare(
  1572   1615             string param1, /* in */
  1573   1616             string param2  /* in */
  1574   1617             )
  1575   1618         {
  1576         -          if (callback == null)
  1577         -              throw new InvalidOperationException(NoCallbackError);
         1619  +          if (callback1 == null)
         1620  +          {
         1621  +              throw new InvalidOperationException(String.Format(
         1622  +                  NoCallbackError, "Compare"));
         1623  +          }
  1578   1624   
  1579   1625             SQLiteCompareDelegate compareDelegate =
  1580         -              callback as SQLiteCompareDelegate;
         1626  +              callback1 as SQLiteCompareDelegate;
  1581   1627   
  1582   1628             if (compareDelegate != null)
  1583   1629             {
  1584         -              return compareDelegate.Invoke("Compare", param1, param2);
         1630  +              return compareDelegate.Invoke(
         1631  +                  "Compare", param1, param2); /* throw */
  1585   1632             }
  1586   1633             else
  1587   1634             {
  1588         -              object result = callback.DynamicInvoke(GetCompareArgs(
         1635  +              object result = callback1.DynamicInvoke(GetCompareArgs(
  1589   1636                     param1, param2, false)); /* throw */
  1590   1637   
  1591   1638                 if (result is int)
  1592   1639                     return (int)result;
  1593   1640   
  1594   1641                 throw new InvalidOperationException(String.Format(
  1595   1642                     ResultInt32Error, "Compare"));

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

    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  +    private Delegate     _callback1;
           24  +    private Delegate     _callback2;
    24     25   
    25     26       /// <summary>
    26     27       /// Default constructor, initializes the internal variables for the function.
    27     28       /// </summary>
    28     29       public SQLiteFunctionAttribute()
    29     30           : this(String.Empty, -1, FunctionType.Scalar)
    30     31       {
................................................................................
    50     51           FunctionType functionType
    51     52           )
    52     53       {
    53     54           _name = name;
    54     55           _argumentCount = argumentCount;
    55     56           _functionType = functionType;
    56     57           _instanceType = null;
    57         -        _callback = null;
           58  +        _callback1 = null;
           59  +        _callback2 = null;
    58     60       }
    59     61   
    60     62       /// <summary>
    61     63       /// The function's name as it will be used in SQLite command text.
    62     64       /// </summary>
    63     65       public string Name
    64     66       {
................................................................................
    83     85         get { return _functionType; }
    84     86         set { _functionType = value; }
    85     87       }
    86     88   
    87     89       /// <summary>
    88     90       /// The <see cref="System.Type" /> object instance that describes the class
    89     91       /// 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.
           92  +    /// this property will not be used if either the <see cref="Callback1" /> or
           93  +    /// <see cref="Callback2" /> property values are set to non-null.
    92     94       /// </summary>
    93     95       internal Type InstanceType
    94     96       {
    95     97           get { return _instanceType; }
    96     98           set { _instanceType = value; }
    97     99       }
    98    100   
    99    101       /// <summary>
   100    102       /// The <see cref="Delegate" /> that refers to the implementation for the
   101    103       /// associated function.  If this property value is set to non-null, it will
   102    104       /// be used instead of the <see cref="InstanceType" /> property value.
   103    105       /// </summary>
   104         -    internal Delegate Callback
          106  +    internal Delegate Callback1
          107  +    {
          108  +        get { return _callback1; }
          109  +        set { _callback1 = value; }
          110  +    }
          111  +
          112  +    /// <summary>
          113  +    /// The <see cref="Delegate" /> that refers to the implementation for the
          114  +    /// associated function.  If this property value is set to non-null, it will
          115  +    /// be used instead of the <see cref="InstanceType" /> property value.
          116  +    /// </summary>
          117  +    internal Delegate Callback2
   105    118       {
   106         -        get { return _callback; }
   107         -        set { _callback = value; }
          119  +        get { return _callback2; }
          120  +        set { _callback2 = value; }
   108    121       }
   109    122     }
   110    123   }

Changes to Tests/basic.eagle.

  3598   3598   
  3599   3599       for {set index 0} {$index < $argumentCount} {incr index} {
  3600   3600         lappend result [appendArgs 'myFuncArg [expr {$index + 1}] ']
  3601   3601       }
  3602   3602   
  3603   3603       return $result
  3604   3604     }
         3605  +
         3606  +  proc getHashCode { value } {
         3607  +    if {[isObjectHandle $value]} then {
         3608  +      if {$value eq "null"} then {
         3609  +        return 0
         3610  +      } else {
         3611  +        return [object invoke $value GetHashCode]
         3612  +      }
         3613  +    } else {
         3614  +      if {[string length $value] == 0} then {
         3615  +        return 0
         3616  +      } else {
         3617  +        set string [object create String $value]
         3618  +
         3619  +        return [object invoke $string GetHashCode]
         3620  +      }
         3621  +    }
         3622  +  }
         3623  +
         3624  +  proc hashManagedArray { array } {
         3625  +    set data ""
         3626  +
         3627  +    if {[isObjectHandle $array] && $array ne "null"} then {
         3628  +      if {[object invoke $array GetType.IsArray]} then {
         3629  +        for {set index 0} {$index < [$array Length]} {incr index} {
         3630  +          set element [$array -create -alias GetValue $index]
         3631  +
         3632  +          if {[string length $element] > 0} then {
         3633  +            append data [$element ToString]
         3634  +          } else {
         3635  +            append data null
         3636  +          }
         3637  +        }
         3638  +      }
         3639  +    }
         3640  +
         3641  +    return [getHashCode [hash normal sha1 $data]]
         3642  +  }
  3605   3643   
  3606   3644     proc myFuncCallback { args } {
  3607   3645       if {[llength $args] == 0} then {
  3608   3646         error "no function arguments"
  3609   3647       }
  3610   3648   
  3611   3649       set name [lindex $args 0]
         3650  +
         3651  +    if {[isObjectHandle $name] && $name ne "null"} then {
         3652  +      set name [object invoke $name ToString]
         3653  +    }
  3612   3654   
  3613   3655       switch -exact -- $name {
  3614   3656         Invoke {
  3615         -        return $args
         3657  +        return [hashManagedArray [lindex $args end]]
  3616   3658         }
  3617   3659         Step {
  3618         -        set ctx [lindex $args 1]
         3660  +        set varName [lindex $args end]
  3619   3661   
  3620         -        if {[string length $ctx] == 0} then {
  3621         -          error "invalid aggregate context"
         3662  +        if {[string length $varName] == 0} then {
         3663  +          error "invalid aggregate context variable name"
         3664  +        }
         3665  +
         3666  +        upvar 1 $varName ctx
         3667  +
         3668  +        if {![info exists ctx] || [string length $ctx] == 0} then {
         3669  +          set ctx [pid]
  3622   3670           }
  3623   3671   
  3624         -        global aggregateData
         3672  +        set hashCtx [getHashCode $ctx]
         3673  +        set hashArgs [hashManagedArray [lindex $args end-2]]
  3625   3674   
  3626         -        if {[info exists aggregateData($ctx)]} then {
  3627         -          incr aggregateData($ctx)
         3675  +        if {[info exists ::aggregateData($hashCtx)]} then {
         3676  +          incr ::aggregateData($hashCtx) $hashArgs
  3628   3677           } else {
  3629         -          set aggregateData($ctx) 1
         3678  +          set ::aggregateData($hashCtx) $hashArgs
  3630   3679           }
  3631   3680         }
  3632   3681         Final {
  3633         -        set ctx [lindex $args 1]
         3682  +        set ctx [lindex $args end]
  3634   3683   
  3635   3684           if {[string length $ctx] == 0} then {
  3636   3685             error "invalid aggregate context"
  3637   3686           }
  3638   3687   
  3639         -        global aggregateData
         3688  +        set hashCtx [getHashCode $ctx]
  3640   3689   
  3641         -        if {[info exists aggregateData($ctx)]} then {
  3642         -          return $aggregateData($ctx)
         3690  +        if {[info exists ::aggregateData($hashCtx)]} then {
         3691  +          return $::aggregateData($hashCtx)
  3643   3692           } else {
  3644   3693             error "missing aggregate context data"
  3645   3694           }
  3646   3695         }
  3647   3696         Compare {
  3648         -        return [string compare -nocase [lindex $args 1] [lindex $args 2]]
         3697  +        lappend ::compareResults [object invoke -create \
         3698  +            Int32 Parse [string compare -nocase [lindex \
         3699  +            $args 1] [lindex $args 2]]]
         3700  +
         3701  +        return [lindex $::compareResults end]
  3649   3702         }
  3650   3703         default {
  3651   3704           error [appendArgs "unknown function callback \"" $name \"]
  3652   3705         }
  3653   3706       }
  3654   3707     }
         3708  +
         3709  +  proc myFuncInvokeCallback { param0 objs } {
         3710  +    return [myFuncCallback $param0 $objs]
         3711  +  }
         3712  +
         3713  +  proc myFuncStepCallback { param0 objs stepNumber contextDataVarName } {
         3714  +    upvar 1 $contextDataVarName $contextDataVarName
         3715  +    return [myFuncCallback $param0 $objs $stepNumber $contextDataVarName]
         3716  +  }
         3717  +
         3718  +  proc myFuncFinalCallback { param0 contextData } {
         3719  +    return [myFuncCallback $param0 $contextData ]
         3720  +  }
         3721  +
         3722  +  proc myFuncCompareCallback { param0 param1 param2 } {
         3723  +    return [myFuncCallback $param0 $param1 $param2]
         3724  +  }
  3655   3725   
  3656   3726     setupDb [set fileName data-1.74.db]
  3657   3727   } -body {
  3658         -  sql execute $db "CREATE TABLE t1(x INTEGER);"
         3728  +  sql execute $db "CREATE TABLE t1(x);"
  3659   3729     sql execute $db "INSERT INTO t1 (x) VALUES(1);"
  3660   3730     sql execute $db "INSERT INTO t1 (x) VALUES(2);"
  3661   3731     sql execute $db "INSERT INTO t1 (x) VALUES(3);"
  3662   3732     sql execute $db "INSERT INTO t1 (x) VALUES('A');"
  3663   3733     sql execute $db "INSERT INTO t1 (x) VALUES('a');"
  3664   3734     sql execute $db "INSERT INTO t1 (x) VALUES('M');"
  3665   3735     sql execute $db "INSERT INTO t1 (x) VALUES('m');"
................................................................................
  3669   3739     set connection [getDbConnection]
  3670   3740   
  3671   3741     for {set argumentCount 0} {$argumentCount < 3} {incr argumentCount} {
  3672   3742       set attribute(1,$argumentCount) [object create \
  3673   3743           System.Data.SQLite.SQLiteFunctionAttribute [appendArgs \
  3674   3744           myFunc1_74_1_ $argumentCount] $argumentCount Scalar]
  3675   3745   
  3676         -    $connection BindFunction $attribute(1,$argumentCount) myFuncCallback
         3746  +    $connection -marshalflags \
         3747  +        {-StrictMatchType +DynamicCallback ForceParameterType} \
         3748  +        -parametertypes [list System.Data.SQLite.SQLiteFunctionAttribute \
         3749  +            System.Data.SQLite.SQLiteInvokeDelegate Delegate] \
         3750  +        BindFunction $attribute(1,$argumentCount) \
         3751  +        myFuncInvokeCallback null
  3677   3752   
  3678   3753       set attribute(2,$argumentCount) [object create \
  3679   3754           System.Data.SQLite.SQLiteFunctionAttribute [appendArgs \
  3680   3755           myFunc1_74_2_ $argumentCount] $argumentCount Aggregate]
  3681   3756   
  3682         -    $connection BindFunction $attribute(2,$argumentCount) myFuncCallback
         3757  +    $connection -marshalflags \
         3758  +        {-StrictMatchType +DynamicCallback ForceParameterType} \
         3759  +        -parametertypes [list System.Data.SQLite.SQLiteFunctionAttribute \
         3760  +            System.Data.SQLite.SQLiteStepDelegate \
         3761  +            System.Data.SQLite.SQLiteFinalDelegate] \
         3762  +        BindFunction $attribute(2,$argumentCount) \
         3763  +        myFuncStepCallback myFuncFinalCallback
  3683   3764     }
  3684   3765   
  3685   3766     set attribute(3,0) [object create \
  3686         -      System.Data.SQLite.SQLiteFunctionAttribute myFunc1_74_3 0 Collation]
         3767  +      System.Data.SQLite.SQLiteFunctionAttribute myFunc1_74_3 0 \
         3768  +      Collation]
  3687   3769   
  3688         -  $connection BindFunction $attribute(3,0) myFuncCallback
         3770  +  $connection -marshalflags \
         3771  +      {-StrictMatchType +DynamicCallback ForceParameterType} \
         3772  +      -parametertypes [list System.Data.SQLite.SQLiteFunctionAttribute \
         3773  +          System.Data.SQLite.SQLiteCompareDelegate Delegate] \
         3774  +      BindFunction $attribute(3,0) \
         3775  +      myFuncCompareCallback null
  3689   3776   
  3690   3777     for {set argumentCount 0} {$argumentCount < 3} {incr argumentCount} {
  3691   3778       lappend result [catch {
  3692   3779         sql execute $db [appendArgs \
  3693   3780             "SELECT " myFunc1_74_1_ $argumentCount ( \
  3694   3781             [join [getMyFuncArgs $argumentCount] ,] )\;]
  3695   3782       } error] $error
................................................................................
  3698   3785         sql execute $db [appendArgs \
  3699   3786             "SELECT " myFunc1_74_2_ $argumentCount ( \
  3700   3787             [join [getMyFuncArgs $argumentCount] ,] )\;]
  3701   3788       } error] $error
  3702   3789     }
  3703   3790   
  3704   3791     lappend result [catch {
  3705         -    sql execute $db "SELECT x FROM t1 ORDER BY x COLLATE myFunc1_74_3;"
         3792  +    sql execute -execute reader -format list $db \
         3793  +        "SELECT x FROM t1 ORDER BY x COLLATE myFunc1_74_3;"
  3706   3794     } error] $error
  3707   3795   
  3708   3796     lappend result [$connection UnbindAllFunctions false]
  3709   3797   
  3710   3798     for {set argumentCount 0} {$argumentCount < 3} {incr argumentCount} {
  3711   3799       lappend result [catch {
  3712   3800         sql execute $db [appendArgs \
................................................................................
  3720   3808             "SELECT " myFunc1_74_2_ $argumentCount ( \
  3721   3809             [join [getMyFuncArgs $argumentCount] ,] )\;]
  3722   3810       } error] [expr {[string first [appendArgs \
  3723   3811           "no such function: myFunc1_74_2_" $argumentCount] $error] != -1}]
  3724   3812     }
  3725   3813   
  3726   3814     lappend result [catch {
  3727         -    sql execute $db "SELECT x FROM t1 ORDER BY x COLLATE myFunc1_74_3;"
         3815  +    sql execute -execute reader -format list $db \
         3816  +        "SELECT x FROM t1 ORDER BY x COLLATE myFunc1_74_3;"
  3728   3817     } error] [expr {[string first "no such collation sequence: myFunc1_74_3" \
  3729   3818         $error] != -1}]
  3730   3819   
         3820  +  lappend result [array size aggregateData]
         3821  +  lappend result [testArrayGet aggregateData]
         3822  +
  3731   3823     set result
  3732   3824   } -cleanup {
  3733   3825     cleanupDb $fileName
  3734   3826   
  3735   3827     freeDbConnection
  3736   3828   
  3737         -  catch {object removecallback myFuncCallback}
         3829  +  catch {object removecallback myFuncCompareCallback}
         3830  +  catch {object removecallback myFuncFinalCallback}
         3831  +  catch {object removecallback myFuncStepCallback}
         3832  +  catch {object removecallback myFuncInvokeCallback}
         3833  +
         3834  +  catch {
         3835  +    foreach compareResult $compareResults {
         3836  +      catch {object dispose $compareResult}
         3837  +    }
         3838  +  }
  3738   3839   
  3739         -  unset -nocomplain result error aggregateData argumentCount attribute \
  3740         -      connection db fileName
         3840  +  unset -nocomplain result error compareResult compareResults \
         3841  +      aggregateData argumentCount attribute connection db fileName
  3741   3842   
         3843  +  rename myFuncCompareCallback ""
         3844  +  rename myFuncFinalCallback ""
         3845  +  rename myFuncStepCallback ""
         3846  +  rename myFuncInvokeCallback ""
  3742   3847     rename myFuncCallback ""
         3848  +  rename hashManagedArray ""
         3849  +  rename getHashCode ""
  3743   3850     rename getMyFuncArgs ""
  3744   3851   } -constraints {eagle command.object monoBug28 command.sql compile.DATA SQLite\
  3745         -System.Data.SQLite} -result {}}
         3852  +System.Data.SQLite} -match regexp -result {^0 -1 0 -1 0 -1 0 -1 0 -1 0 -1 0 \{1\
         3853  +2 3 A a M m Z z\} True 1 True 1 True 1 True 1 True 1 True 1 True 1 True 1\
         3854  +\{(?:-)?\d+ (?:-)?\d+\}$}}
  3746   3855   
  3747   3856   ###############################################################################
  3748   3857   
  3749   3858   reportSQLiteResources $test_channel
  3750   3859   
  3751   3860   ###############################################################################
  3752   3861   
  3753   3862   runSQLiteTestFilesEpilogue
  3754   3863   runSQLiteTestEpilogue
  3755   3864   runTestEpilogue