• Ok Barry here we go. I've tried to cover everything so it's readable for the wider audience - so apologies for the amount of detail:

    1. SQL Server expects an object that implements IEnumerable from the initial call to the static method named in the EXTERNAL NAME part of the CREATE FUNCTION statement. In this case, that's the StreamingHandcoded method.

    2. The StreamingHandcoded method passes the input parameter to a new instance of the nested Helper class. The constructor for the Helper class stores the passed parameter in a read-only member variable. If we had a streaming type as an input parameter (SqlChars or SqlBytes), we would store a reference to that in the same way.

    3. SQL Server calls the GetEnumerator() method on the IEnumerable interface of the Helper object we pass back in order to get the object that will allow it to iterate over the results. The IEnumerable interface specifies that the object passed back will implement the IEnumerator interface. In our case, the Helper class implements both IEnumerable and IEnumerator, so IEnumerable.GetEnumerator() just returns a reference to the same class via 'this'. This avoids the need to create separate classes to handle the two calls.

    4. Now that SQL Server has an object implementing IEnumerator, it can use the interface's Current property and MoveNext method to fetch results (the Reset method is also required by the interface, but SQL Server doesn't call it for TVFs). Current returns the data for the current row, MoveNext moves to the next row of the result set, and returns true until there are no more rows.

    5. The code to do the work required appears in the helper class. This is what makes this way of doing things 'lazy' - no work on the task in hand is done in the method called in step 1. The work is often coded in the MoveNext method, with Current just returning a simple reference to some member variable in the helper class. In this very simple example, the work consists of "++index < maxValue;" - incrementing the member variable and returning a boolean.

    6. SQL Server calls the Current property after every call to MoveNext that returns true. This returns an object (untyped) as defined by the interface. In our case, the returned object is an int (the index variable).

    7. SQL Server then passes this object to the FillRowMethodName specified in the SqlFunction attribute. In this case, that is the static FillRow(object i, out SqlInt32 Value) method on the outer class. That method simply casts the object back to an int, and uses that to construct a SqlInt32 which is returned via the out parameter.

    Paul