using System; using System.Collections; using System.Data.SqlTypes; using System.Text; using Microsoft.SqlServer.Server; using System.Threading; /// /// TVF for clr stored procedure with following definition: /// /// use master; /// -- Replace SQL_Server_logon with your SQL Server user credentials. /// GRANT EXTERNAL ACCESS ASSEMBLY TO [redmond\arvran]; ///-- Modify the following line to specify a different database. ///ALTER DATABASE master SET TRUSTWORTHY ON; ///-- ///RECONFIGURE; ///GO ///sp_configure 'clr enabled', 1; ///GO ///RECONFIGURE; ///GO ///sp_configure 'network packet size', 512; ///GO ///RECONFIGURE; ///GO ///-- Modify the next line to use the appropriate database. ///CREATE ASSEMBLY MyTVfs ///FROM 'D:\src\sqltoolsservice\test\TVFSample\bin\Release\TVFSample.dll' ///WITH PERMISSION_SET = EXTERNAL_ACCESS; ///GO ///CREATE FUNCTION StreamingTvf(@numRows int , @delayInMs int, @messageSize int= 4000) ///RETURNS TABLE ///(rowNumber int, msg nvarchar(max)) ///AS ///EXTERNAL NAME MyTVfs.TvfSample.TVF_Streaming; ///GO /// public class TvfSample { private struct ReturnValues { public int Value; public string Message; } private static void FillValues(object obj, out SqlInt32 theValue, out SqlChars message) { ReturnValues returnValues = (ReturnValues)obj; theValue = returnValues.Value; message = new SqlChars(returnValues.Message); } private static string RandomString(int size) { StringBuilder builder = new StringBuilder(); Random random = new Random(); for (int i = 0; i < size; i++) { char ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65))); builder.Append(ch); } return builder.ToString(); } [SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = true, IsPrecise = true, SystemDataAccess = SystemDataAccessKind.None, FillRowMethodName = "FillValues", TableDefinition = "IntValue INT, Message nvarchar(max) ")] public static IEnumerable TVF_Streaming(SqlInt32 maxValue, SqlInt32 delayInMilliseconds, SqlInt32 messageSize) { if (maxValue.IsNull) { yield break; // return no rows } // we do not need the Generic List of ReturnValues values = new ReturnValues(); // each row for (int index = 1; index <= maxValue.Value; index++) { values.Value = index; values.Message = RandomString((int)messageSize); yield return values; // return row per each iteration Thread.Sleep((int)delayInMilliseconds); } // we do not need to return everything at once } }