SQL Server with Mr. Denny:

SQL Server stored procedures

Jul 10 2008   11:00AM GMT

My Experience with putting a CRL Procedure into SQL



Posted by: mrdenny
SQL Server 2005, Microsoft.SqlServer.Server, CREATE PROCEDURE, CREATE ASSEMBLY, C#, SQL CLR Procedure, Encryption, SQL Server stored procedures, T/SQL

A little while ago I came upon a situation where I needed to put a CRL procedure into SQL Server 2005.  Now I’ve been using SQL Server 2005 since the day it went RTM, and this is the first occasion that I’ve needed to put a CLR procedure into SQL.  Could I have done what I needed to without a CRL procedure?  Yeah probably, but the .NET code was written, and had been working.

My code is written in C# as that’s what the .NET guys here use.  There is one method within the C# class called HashPassword.  It takes a text string and makes a SHA1 Hash of it which we then store.  We had to make a couple of changes to the C# code to make it work within SQL Server.

The original code looked like this.

using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;
 

namespace Rapid.Database.Security{
public class User
     {
     public static void HashPassword(String password, out String hash)
          {
          SHA1 sha1 = new SHA1CryptoServiceProvider();hash = 
          BitConverter.ToString(sha1.ComputeHash(UnicodeEncoding.Default.GetBytes(password.ToLower()))).Replace(“-”, “”);

          }
     }
}

The changed C# code looks like this.

using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using Microsoft.SqlServer.Server;

namespace Rapid.Database.Security

{
public class User
     {

     [SqlProcedure(Name=“HashPassword”)]
     public static void HashPassword(String password, out String hash)
          {
          SHA1 sha1 = new SHA1CryptoServiceProvider();hash = 
          BitConverter.ToString(sha1.ComputeHash(UnicodeEncoding.Default.GetBytes(password.ToLower()))).Replace(“-”, “”);

          }
     }
}

Once these changes are made and the DLL recompiled we can attach the DLL to the SQL Server database as an assembly.  This is done with the CREATE ASSEMBLY command.  I have to use the EXTERNAL_ACCESS flag instead of the SAFE flag because my dll requires the use of the System.IO assembly which can’t be run as SAFE under SQL Server 2005.

CREATE ASSEMBLY [Rapid.Database.Security]AUTHORIZATION [dbo]
FROM ‘D:\Rapid.Database.Security.dll’
WITH PERMISSION_SET = EXTERNAL_ACCESS
GO

We can now create our procedure which needs to have one input and one output parameter to match the number of parameters within the C# procedure.  This is done with the CREATE PROCEDURE command just like creating any normal procedure.

CREATE PROCEDURE [dbo].[HashPassword]
@Password [nvarchar](50),
@PasswordHash [nvarchar](50) OUTPUT
WITH EXECUTE AS CALLER
AS
EXTERNAL NAME [Rapid.Database.Security].[Rapid.Database.Security.User].[HashPassword]
GO

The three part name of the C# method are:

  1. Assembly name which SQL Server knows about (basically the name of the DLL without the file extension).
  2. The full name to the class, in our case the namespace then the class.  Our namespace is Rapid.Database.Security with the name of the class after that.
  3. The name of the method within the C# class.

Don’t forget to enable CLR within SQL Server using the sp_configure before trying to use the CLR procedure.

 At this point I am able to run the procedure and pass in text and get back the hash.

declare @PasswordHash varchar(50)
exec HashPassword @password=‘test’, @passwordHash=@PasswordHash OUTPUT
SELECT @PasswordHash

The value of this is: A94A8FE5CCB19BA61C4C0873D391E987982FBBD3

I hope that you find this useful. It took me and a .NET developer a couple of hours to get all this working correctly and loaded into the SQL Server correctly. I know that I’ll be referring back to this if I ever need to attach a CLR method into SQL again.

Do keep in mind that when we were doing this, we created this as a separate DLL for the SQL Server as to get the original DLL into the SQL Server, SQL wanted us to load up a bunch of other assemblies that some of the other methods required.

Denny

Apr 10 2008   8:00PM GMT

Back To Basics: Stored Procedures, the work horse of the database



Posted by: mrdenny
Back To Basics, SQL Server stored procedures, SQL

Stored procedures are extremely useful objects.  Not only do they store T/SQL scripts for later execution, but they also provide us with an extremely important security barrier between the user interface and the database.  The security barrier is used to prevent the users from needing SELECT, INSERT, UPDATE and/or DELETE rights directly to the database tables and views. 

This is done through what is called permissions chaining.  When a user has rights to execute a stored procedure they are given temporary rights to use the table objects within the procedures which are used by the table.

Creating stored procedures is very easy.  Take your Transact SQL code and put it below the CREATE PROCEDURE command, and end the batch.  Like all other database objects the name of the stored procedure must be unique within the schema (or owner for SQL 2000 and below).  As an example lets create a stored procedure which returns the names of all the tables in the current database.

CREATE PROCEDURE ShowTables AS
SELECT schema_name(schema_id), name
FROM sys.tables
GO

As you can see the basic syntax is very simple.  To run this stored procedure we simply run the stored procedure name.

exec ShowTables

You can add in input parameters to handle filtering, or which would need to be inserted into a table.  An input parameter is simply a variable which you set when you run the procedure.  You can access the value of the input parameter within the stored procedure as you would any other variable.  Let’s look at the same procedure but this time we want to filter the tables by the first letter.

CREATE PROCEDURE ShowTables
  @FilterChar NVARCHAR(2)
AS
SET @FilterChar = @FilterChar + ‘%’
SELECT schema_name(schema_id), name
FROM sys.tables
WHERE name LIKE @FilterChar
GO

In this example as you can see we take the input parameter, and add the % wild card, then use the variable to filter down the records to see only the records which start with the character we supply.  Running the stored procedure with an input parameter is just as easy.

exec ShowTables @FilterChar=N'C'

We can also use output parameters to get values back from the stored procedures.  Output parameters are used basically in the same way that input parameters are, however you add the OUTPUT keyword after the parameter.  Within the stored procedure simply set the output variable to the value you want it to return to the calling code.  This can be done anywhere within the stored procedure, as long as the variable still holds the value when the stored procedure has completed it’s execution the value will be returned to the calling code.  First lets look at the code to create the stored procedure.

 CREATE PROCEDURE ShowTables
  @FilterChar NVARCHAR(2),
  @RowCount INT OUTPUT
AS
SET @FilterChar = @FilterChar + ‘%’
SELECT schema_name(schema_id), name
FROM sys.tables
WHERE name LIKE @FilterChar

SET @RowCount = @@ROWCOUNT
GO

We run the stored procedure in much the same way we do with the input parameter.

DECLARE @RowCount INT
exec ShowTables @FilterChar=N’C', @RowCount=@RowCount OUTPUT
SELECT @RowCount
 

In this case we are simply returning the row count as a second record set, but you’ll get the basic idea.

As I wrote earlier you can add records to a table with the stored procedure.

CREATE PROCEDURE InsertTable
  @Id INT,
  @Value VARCHAR(20)
AS
INSERT INTO SomeTable
(Id, Value)
VALUE
(@Id, @Value)
GO

As you can see it’s a very basic method.  It’s a regular insert statement with the parameters passed to it.

I know that this was a bit longer than the other posts, but I hope that you found it worth while.

Denny