Sql Server 2005 CLR Native Methods
By Peter A. Bromberg, Ph.D.

Peter Bromberg


"Read the best books first, or you may not have a chance to read them at all.."
-- Thoreau

Sql Server 2005 BETA 1 "SQLEXPRESS" was released to the MSDN Subscriber community on July 1, 2004. One of the most interesting new features (and there are many) is the ability to host the CLR runtime and assemblies with code for functions, stored procedures and UDTs (User-Defined Types) written in C# or VB.NET, right inside SQL Server. Once you get the various syntax issues out of the way (there is an extreme lack of good documentation as of this writing in early July, 2004), a whole new world opens up to you as a developer.



Have some cool .NET code you've written that you'd like to make into a user - defined function callable from T-SQL? No problem - now you can, and that's just the beginning! In this article, we'll put together a C# class that gets a stock quote over the web from Yahoo Finance, compile it into a .NET Class library, and demonstrate how the function can be called with normal SQL Code - right from out of SQL Server 2005. But first, let's go over a few SQLEXPRESS issues:

SQL Server Express (2005)

Developers have been complaining that they cannot connect to SQL Server Express. That is because the default instance name in the various dialogs is not populated (or populated incorrectly). Enter ".\SQLEXPRESS" as the server name and you will be able to connect.

I would not recommend installing SQL Server Express alone, unless you do so with either one of the Web Developer Express versions, or with the full Visual Studio.NET 2005 Beta. This is because the only real way you can program against SQL Server Express (currently) is from within the VS.NET IDE - which now has vastly improved Data - related capabilities, including the ability to create and design databases from scratch.

The API's available to program against SQL Server Express are the same as those for SQL Server 2005, so that users have a seamless experience if they choose to move to other editions of SQL Server 2005. All of the new features in SQL Server 2005, such as common language runtime (CLR) integration, new data types such as VARCHAR(MAX) and XML, user-defined types, and user-defined aggregates are supported. Also, SQL Server Express databases can attach to SQL Server 2005, and applications programmed with a SQL Server Express instance will work equally well with a SQL Server 2005 instance. Replication and SQL Service Broker functionality is also available. There is also supposed to be a new "XM Enterprise Manager" like clone, but I have not seen it available yet.

The sa login: SQL requires a strong sa password for security reasons, and during GUI installs and silent SQL authentication mode installs, the user must provide a strong sa password. However, for silent Windows authentication installs, the sa password is not a requirement. The reason is that when using Windows authentication mode, the silent SQL Server Express setup provides a random strong sa password if the password is not specified by the user. The setup also disables the sa account in this case, so that you must explicitly enable sa at a later stage using T-SQL or the Express Manager tool if you wish to use it. This is done so that the ISVs do not have to provide the password when using windows authentication, so that the mass deployment scenarios are not blocked.

NOTE: You can enable mixed - mode authentication in the Registry by changing the LoginMode value from 1 to "2", here:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL.1\MSSQLServer

LoginMode =2

Of course, since you still don't know the strongly named "sa" password from when it was installed, you can still add a new user in SQLCMD and make them a sysadmin with:

SQLCMD -S.\SQLEXPRESS -E

sp_addLogin 'username', 'pass'
GO
sp_addsrvrolemember 'username', 'sysadmin'
GO

Don't forget to give yourself a gold star for remembering to stop and restart the SQLEXPRESS service to get that registry change to take.

NOTE: Your database / server access options at this point (until they release the new XM GUI tool) consist of working out of the VS.NET IDE, or using the provided SQLCMD command - line tool, which is extremely similar to OSQL. As a matter of fact, ALL of the SQL SERVER 2005 code you will see in the sample application below was tried out and brought up to "working condition" using the SQLCMD.EXE utility first. Also, Lloyd Sheen has developed a nice little QA clone for SQLEXPRESS that you can find out about on the SQLEXPRESS newsgroup. With Lloyd's permission, we are also hosting a copy of his latest zip file here.

Connection Strings

Typical Connection Strings look like:

Server=.\SQLEXPRESS;Integrated Security=True;Database=DIARY

or:

Server=PETER\SQLEXPRESS;User ID=peter;password=xyzabc;Database=DIARY;Persist Security Info=True

You can also use the "Add new Item" wizard in an Application and add a new blank database, which results in a connection
string like the following:

Data Source=.\SQLExpress;Integrated Security=True;AttachDBFilename=C:\VS2005\WindowsApplication1\WindowsApplication1\TESTING.mdf

This is a new behavior with SQL Server 2005- the ability to create and attach a database at runtime. The Database can be deployed along with the application, using typical XCOPY - style deployment. Within Visual Studio.NET, you can add tables, indexes, stored procedures and everything else - without ever leaving the comfy confines of the IDE.

Networking support for SQL Express

Only the shared memory on the local machine is accessible by default for SQL Server Express, although the user can explicitly turn on other supported protocols such as TCP/IP and Named Pipes. VIA and HTTP protocols are not supported in SQL Server Express. With only shared memory available by default, connections from a remote machine to SQL Server Express will fail unless the networking is turned on. To turn networking on, you can do one of the following:

Use SQL Computer Manager to enable relevant protocols and start SQL Browser.

Use DISABLENETWORKPROTOCOLS=0 in the setup command line, if you know in advance that networking support is needed (this is not an option with the integrated VS.NET 2005 install).

Use SMO-based scripting to enable the protocols.

Service Broker

Service Broker is basically an asynchronous programming framework for database applications.  This means (among many other things) that you can establish a reliable, asynchronous, bi-directional communications sessions between a client and server. Aside from the obvious benefits of a reliable connection - client able to run even if the network is temporarily unavailable, the asynchronous, bidirectional nature of the communications means that the client can queue up work as fast as the user can enter it for the server to process when it has processor cycles available and the server can send data to the client without the client requesting it, even if the client is not on line at the time. Service Broker must be running with, for example, the TCP library enabled, in order to access SQLExpress from another machine.

NOTE: As of late July, 2004 the SQLExpress Beta 2 version has since been posted. This incorporates some bug fixes and also allows Mixed Mode authentication to be set up during the install phase. If you have already installed the BETA1, follow the instructions very carefully when attempting to install BETA 2. Particularly, SQLEXPRESS, the SQL Native Client, the Tools, and also DOTNET Framework 2.0 must all be UNINSTALLED first. Then replace the Framework using the latest DOTNETFX.EXE installer, and finally install SQLEXPRESS, and you should have no trouble with the rest. Also, for MSDN Subscribers, the DEVELOPER (Full edition) version of SQL Server 2005 BETA 2 is now available at Subscriber Downloads.

Show Me the Code!

First, let's breeze through the class that gets the stock quote from Yahoo finance:

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Diagnostics;
using System.Data.Sql;
using System.Data.SqlServer;
namespace PAB.SqlExpress.Data
{   
    public class Stocks
    {
        public Stocks()
        {
        }        
        [SqlFunction(DataAccess = DataAccessKind.None)]
        public static string GetQuote(string symbol)
        {           
            string serverURL = 
@"http://finance.yahoo.com/d/quotes.csv?s=" + symbol + "&&f=st5l9c6p4b1a3&e=.csv"; HttpWebRequest webreq = (HttpWebRequest)WebRequest.Create(serverURL); webreq.MaximumAutomaticRedirections = 60; //Retrieve HttpWebResponse object from the Search server URL HttpWebResponse webresp = (HttpWebResponse)webreq.GetResponse(); StreamReader strm = new StreamReader(webresp.GetResponseStream(), Encoding.ASCII); string res = strm.ReadToEnd(); strm.Close(); string[] theQuote = res.Split(Convert.ToChar(",")); string tmpQuote = theQuote[2]; //last // remove any crap that yahoo puts in there tmpQuote = tmpQuote.Replace("<i>", "").Replace("</i>", ""); return tmpQuote; } } }

The above code should be self-explanatory to any developer advanced enough to be using Visual Studio.NET 2005. The only items of note are that we will need a reference to the sqlaccess assembly which resides (on my machine) at:

C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Binn

The other item is the attribute " [SqlFunction(DataAccess = DataAccessKind.None)]". There are other enumerations when your code actually does make Data Access, and you will see them in Intellisense.

We compile this assembly and we are ready to bring it into SQL Server 2005. Now I have a Windows Forms "Test Harness" application that does essentially two thing:

1) In the Form_Load handler, I clear out any existing references to my assembly and the SQL Function that calls it (there is some kludge exception-handling code in the downloadable solution that runs around it if they don't exist and generate SqlExceptions).

2) I set up the assembly reference and create the function. This all happens pretty fast, so for testing purposes it's fine to do this. In production, you would have more complex code. Here is the Form_Load handler code, verbatim (except for breaking some long lines for formatting purposes):

private void Form1_Load(object sender, EventArgs e)
        {
            SqlConnection Conn = 
new SqlConnection(@"Server=.\SQLEXPRESS;Integrated Security=True;Database=master"); SqlCommand cmd = new SqlCommand(); cmd.CommandType=CommandType.Text; cmd.Connection =Conn; Conn.Open(); // Clear our function and Assembly out first, if still there... cmd.CommandText = @"DROP FUNCTION GetQuote"; cmd.ExecuteNonQuery(); cmd.CommandText = @"DROP ASSEMBLY PABSqlExpress"; cmd.ExecuteNonQuery(); // be sure to change the file path to match your environment... cmd.CommandText =
@"CREATE ASSEMBLY PABSqlExpress FROM 'C:\VS2005\PAB.SqlExpress.Data\"; cmd.CommandText+=
@"PAB.SqlExpress.Data\bin\Debug\PAB.SqlExpress.dll' WITH PERMISSION_SET =UNSAFE"
; cmd.ExecuteNonQuery(); cmd.CommandText ="CREATE FUNCTION GetQuote( @symbol NVARCHAR )"; cmd.CommandText+=@"RETURNS NVARCHAR(10) AS EXTERNAL NAME"; cmd.CommandText+=@" [PABSqlExpress].[PAB.SqlExpress.Data.Stocks].GetQuote"; cmd.ExecuteNonQuery(); cmd.Dispose(); Conn.Close(); txtDisplay.Text = "Assembly and function Set up OK!"; }

Finally, in my Button_Click handler, after the user has entered a stock symbol:

 private void button1_Click(object sender, EventArgs e)
        {
            SqlConnection Conn = 
new
SqlConnection(@"Server=.\SQLEXPRESS;Integrated Security=True;Database=master"); SqlCommand cmd = new SqlCommand(); cmd.CommandType = CommandType.Text; cmd.Connection = Conn; Conn.Open(); string stockSymbol = this.txtSymbol.Text; cmd.CommandText = "SELECT dbo.GetQuote('" +stockSymbol + "')"; SqlDataReader rdr = cmd.ExecuteReader(); rdr.Read(); txtDisplay.Text = rdr.GetString(0); cmd.Dispose(); Conn.Close(); }

As can be seen above, we are calling a .NET method on a class in an assembly as if it were a T-SQL function inside SQL Server. In point of fact, that is precisely what it is! The result on my test form, looks like so:

I'm really looking forward to working with SQL Server 2005, thanks to the hard-working folks in Redmond.

download the Visual Studio 2005 Beta 1 Solution that accompanies this article


Peter Bromberg is a C# MVP, MCP, and .NET consultant who has worked in the banking and financial industry for 20 years. He has architected and developed web - based corporate distributed application solutions since 1995, and focuses exclusively on the .NET Platform.
Article Discussion: