Showing posts with label CodeProject. Show all posts
Showing posts with label CodeProject. Show all posts

Thursday 19 November 2015

Capturing and Analyzing deadlocks in SQL Server

No matter how perfect your code and how optimized the way you have written is, facing a situation of getting a deadlock is inevitable. And it would make the situation even more complex when you know that a deadlock had occurred but you have no clue which the victim and perpetrator was.

There are few ways to capture and analyze a deadlock. I will explain two ways in this post.

  1. Enabling trace flags to capture/log deadlock information into SQL Log
  2. Use SQL Profiler to capture a deadlock.

 

Enabling trace flags to capture/log deadlock information into SQL Log

This method will make sure that the deadlock details are logged in the SQL log file (not the transaction log). Even though the details which are captured via this method is textual  it gives you the option of inspecting the details at a later time.

First you need to enable the trace flags using the following syntax:

DBCC TRACEON (1222, 1204, -1)


 

Afterwards we will simulate a deadlock : (in reality you don’t need to do this if you are facing such issue)

First create two sample tables and insert few records which we will use to produce a deadlock.


-- Create a Sample Tables --

CREATE TABLE SampleDeadLock_1(
Item_Code INT
,Item_Desc VARCHAR(100)
,Qty INT
)

CREATE TABLE SampleDeadLock_2(
Item_Code INT
,Item_Desc VARCHAR(100)
,Qty INT
)

-- Insert couple of records to each table --

INSERT INTO dbo.SampleDeadLock_1(
Item_Code
,Item_Desc
,Qty
)
VALUES
(1,'CPU', 10)
,(2, '20 GB - Hard Disk', 20)

INSERT INTO dbo.SampleDeadLock_2(
Item_Code
,Item_Desc
,Qty
)
VALUES
(3,'Monitor', 15)
,(4, 'Keyboard & MOuse', 25)


 


Now open two query windows in SQL Server Management Studio (Window 1 & Window 2) and paste the following code to ‘Window 1’


BEGIN TRAN

UPDATE dbo.SampleDeadLock_1 SET Qty = 100 WHERE Item_Code = 1

WAITFOR DELAY '00:00:30'

UPDATE dbo.SampleDeadLock_2 SET Qty = 200 WHERE Item_Code = 3


And paste the following code to ‘Window 2’


BEGIN TRAN

WAITFOR DELAY '00:00:10'

UPDATE dbo.SampleDeadLock_2 SET Qty = 300 WHERE Item_Code = 3
UPDATE dbo.SampleDeadLock_1 SET Qty = 400 WHERE Item_Code = 1


 


Afterwards execute the code in Window 1 and immediately execute the code in Window 2. After few seconds (30+) you will see a deadlock error message in Window 1.


image


And when you checked on the ERRORLOG file, you will be able to find out the relevant details which relates to the deadlock. (I have highlighted the deadlock victim details in Red and the perpetrator details in blue)


image


 


Using SQL Profiler to capture a deadlock (Deadlock Graph)


One of the issues we have in the aforementioned method is that we need to look into lots of textual information in order to extract the details which is relevant for the deadlock. In this example it’s somewhat easier since we had chosen a simple situation. But things could get real hard during an actual situation where the processes are bit complex.


In such case (any case), we can use the SQL Profiler to detect the deadlock in a more user friendly manner.


** Please Note: Down-side of this method is you need to have the profiler running during the time that the deadlock had occurred. And this isn’t the best way if you need to troubleshoot in a Production Environment.


How ever for the sake of understanding we will see how we can achieve this.


Open the SQL Profiler and connect to the relevant SQL Server. And in the ‘Trace Properties’ window choose ‘TSQL_Locks’ as the template.


image


And in the ‘Event Selection’ tab, please choose the following options.



  • Deadlock graph
  • Lock:Deadlock
  • Lock:Deadlock Chain

image


Before click on running the profiler, Rollback the transaction which is running from the first example (The one which didn’t become the Deadlock Victim)


Start the profiler by clicking the ‘Run’ button. And once the profiler is running, execute the code on Query Window 1 and afterwards execute the code in Query Window 2.


Once the deadlock occurs the Profiler will display the relevant information in a graphical manner. This will contain all the relevant details which is required in order to troubleshoot the deadlock. And if you hover the cursor over the processes in the graph (shown in ellipses) a tooltip will be displayed along with the statement which has been executed, which caused the deadlock to occur.


image


I hope this will help you in order to troubleshoot a deadlock situation.

Monday 26 October 2015

Elevate permission on a SQL login having read only access to Execute Stored Procedures and to View Database Schemas

Due to an unavoidable situation, it was decided that all the write access to a particular server (SQL Server) was required to be removed immediately. And only few people should be able to access the server with full privileges. How ever this wasn’t sound very friendly to the developers, since they were using this server for various kinds of activities during their development and testing. Once the write access was removed we ran into various kinds of trouble since majority couldn’t view the contents of the database objects such as Stored Procedures, Views etc.

So a requirement came to allow them to access the schemas so that they can view the contents, also to execute the procedures (required when debugging a flow using Profiler) without allowing anyone to change or add any new database objects nor any data updates to existing tables directly.

The easiest workaround was to create a SQL user login with read permission and grant execution access to that login.

1.  Create a SQL Login.

image

 

2. Only keep the ‘public’ server role selected for this SQL Login.

image

 

2. Select ‘db_datareader’ role membership.

image

 

Afterwards if you connect to the SQL Server using the above created login, you can see that only read only operations are allowed. You will be able to see the tables, views (cannot see the underlying SQL Code). Stored procedures will be hidden

 

image

 

image

I have created the following stored procedure in my sample database (AdventureWorks) for testing purpose.

CREATE PROCEDURE ReadOnlyUserProc
AS 
BEGIN
    SELECT GETDATE() AS CurrentDate
END


And when the aforementioned procedure is executed as the ‘readonlyuser’ we will get the following error:



EXEC ReadOnlyUserProc

image


Now lets just provide the necessary access to this login so that it can be use to execute the procedures and to see the schemas of database objects. Use the following code to grant the execution access to the previously created user.



USE AdventureWorks
GO
 
GRANT EXECUTE TO readonlyuser
GO

 


And now when we execute the stored procedure we will get the desired result.



EXEC ReadOnlyUserProc

image


However still we are unable to see the schema of the SQL Objects, which is a part of what we want in this exercise.


image


If you try to generate the script by right clicking the object you will get an error message:


image


We will try to fix that issue as well. Please follow these steps:


1. Right click the login and go to the properties window.


2. Go to the ‘Securables’ tab and check/tick the ‘Grant’ check box for ‘View any definition’.


3. Click ‘OK’


image


Now you can see the definitions of the database objects.


image


image


image













Hope this might be useful to you as well.

Saturday 17 October 2015

Elevate permission on a SQL login having read access to run the SQL Profiler

Sometime it’s necessary to allow SQL logins only to have read access to the respective SQL Servers. But it becomes a necessity to allow the developers to run the SQL Profiler when it comes to troubleshoot or to debug a flow and to find the exact point where the problem is generating. How ever it’s a very common opinion that a login having a read only access cannot run the profiler unless it’s included into the ‘sysadmin’ SQL role.
Well this isn’t entirely true. We could allow a SQL login to start and monitor SQL activity using the SQL Profiler and yet keeping the read only access to the SQL schemas. Follow these steps to achieve this:
1. Connect to the SQL Server and expand the Security->Logins node

image

2. Right click the desired login and go to ‘Properties’ from the context menu

image

3. Go to the ‘Securables’ tab and check/tick the Grant checkbox on ‘Alter Trace’. And click ok to save the details.

image

Now you can run the profiler and monitor details using that SQL Login.

image

image

Wednesday 3 June 2015

Error occurs when CTE Alias is ‘RESULT’ - Incorrect syntax near 'RESULT'

Few days back one of my colleague ran into a very strange issue when he was asked to do an alteration to an existing procedure. The procedure was having a SELECT statement which included few Common Table Expressions. It has been running without an issue, until we tried to save the alteration. The alteration was a pretty simple one which was just to add couple of more columns. The query was similar to the one shown below

;WITH RESULT AS(
    /* Your logic  */
    SELECT GETDATE() AS DTE
)
SELECT * FROM RESULT


How ever when we tried to save the changes, it was throwing the following error.


Msg 102, Level 15, State 1, Line 2
Incorrect syntax near 'RESULT'.

But when we go through the query we couldn’t find any issues, and it seems the syntax was quite accurate. So we tried a different server and was able to save the changes without any error. The only difference was one server was running SQL Server 2012 which is having a higher build

Works fine on the following build



Microsoft SQL Server 2012 - 11.0.5058.0 (X64)
    May 14 2014 18:34:29
    Copyright (c) Microsoft Corporation
    Developer Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1) (Hypervisor)


Throws an error on the following build



Microsoft SQL Server 2012 - 11.0.2100.60 (X64)
    Feb 10 2012 19:39:15
    Copyright (c) Microsoft Corporation
    Developer Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1) (Hypervisor)


And when googled we could find that ‘RESULT’ is a future reserved keyword:


https://msdn.microsoft.com/en-us/library/ms189822.aspx


image


But we were still left out with a question of why it failed on an earlier build but succeeded on a most recent build. Please feel free to comment on this if you have further information.

Wednesday 20 May 2015

Conflict in log4net on GAC when a Crystal Report is viewed through .Net Code

We faced an issue sometime ago, which put us into a very tight situation. The issue was when a Crystal Report file is loaded through .Net code it threw the following error. This is the first of a series of error which lead to another and so forth.

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
---> System.TypeInitializationException: The type initializer for 'CrystalDecisions.ReportSource.ReportSourceFactory' threw an exception.
---> System.TypeInitializationException: The type initializer for 'CrystalDecisions.Shared.SharedUtils' threw an exception.
---> System.IO.FileLoadException: Could not load file or assembly 'log4net, Version=1.2.10.0, Culture=neutral,
PublicKeyToken=692fbea5521e1304' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference.
(Exception from HRESULT: 0x80131040)
File name: 'log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=692fbea5521e1304'
   at CrystalDecisions.Shared.SharedUtils..cctor()

 

And the confusion grew even further when we checked the GAC (Global Assembly Cache). Because we could see that in GAC, the mentioned assembly (log4net) is being registered with the version 1.2.10.0 and with the correct ‘PublicKeyToken’ (692fbea5521e1304).

image

And we didn’t really worry about the ‘Processor Architecture’ column, since our development environment is 64-bit and all the Crystal Reports development pre-requisites were there in the development environment and Crystal Runtime was already installed (version 13 – 64-bit). And in our application code we were using the same log4net and it was already presented in the bin folder.

Then when we googled the issue we could be able to come across with similar incidents, where the majority of the people were able to resolve the issue by installing the Crystal Runtime. But it was sort of a puzzle to us since we already had it installed it. But later we tried by un-installing the runtime and re-installing it again, assuming some corruption might had occur during the previous installation or afterwards. But the result was same.

Then we came across with the following article which gave us some kind of a hint of the issue we are facing:

http://scn.sap.com/message/9848374#9848374

And it occurred to us that even though we had the same assembly which the error is pointing installed in GAC, still the Crystal assemblies were expecting some other log4net assembly to be presented in GAC.

Therefore we installed the Crystal Runtime version 13 for 32-bit. Afterwards the GAC was having both the assemblies registered.

image

And this resolved the issue. And we came to a conclusion that even our development environment is 64-Bit, we need to have the log4net assembly for 32-bit since crystal is referring to that internally.

Hope this would help you if you are facing the same problem.

Wednesday 11 April 2012

Resolved ~ How to get back SSMS ‘Find and Replace’ Alert

 

As you know in SQL Server Management Studio (SSMS), once you have cleared the check box value of ‘Always show this message’, from the ‘Find and Replace’ alert, there’s no way of getting it back.

img_scr_01

If you remove the check box, instead of the alert you will get a message no the status bar as shown below.

img_scr_02

But there’s a workaround to fix this problem. Do the following steps

1. Close all the SSMS environments. (If you have opened)
2. Open the registry editor and locate the key '\HKEY_CURRENT_USER\Software\Microsoft\Microsoft SQL Server\100\Tools\Shell\Find'.
3. Change the value of 'HitReplaced' to '1'

img_scr_03

Thursday 8 March 2012

Locks and Duration of Transactions in MS SQL Server

 

It is a common argument which I hear among developers these days, regarding SQL locks. Some say that the ‘locks are held for the duration of the entire transaction’. But others debate that ‘locks will be only held for the duration of the statement execution’. But who is correct ?

Well both parties are correct up to a certain point. Actually lock durations are depend on the Isolation Levels.

As mentioned in the SQL-99 Standards, there are 4 Transaction Isolation Levels

  • Read Committed (Default)
  • Read Uncommitted
  • Repeatable Read
  • Serializable

SQL Server** provides following two additional isolation levels (** SQL Server 2005 & Upwards)

  • Snapshot
  • Read Committed Snapshot

There are several concurrency issues which can occur in a DBMS when multiple users try to access the same data. Each isolation level protects against a specific concurrency problem.

  • Lost Update
  • Dirty Read
  • Non-Repeatable Read
  • Phantom Reads

 

Lost Update – This can take place in two ways. First scenario: it can take place when data that has been updated by one transaction (Transaction A), overwritten by another transaction (Transaction B), before the Transaction A commits or rolls back. (But this type of lost update can never occur in SQL Server** under any transaction isolation level)

img_screen_02

The second scenario is when one transaction (Transaction A) reads a record and retrieve the value into a local variable and that same record will be updated by another transaction (Transaction B). And later Transaction A will update the record using the value in the local variable. In this scenario the update done by Transaction B can be considered as a ‘Lost Update’.

img_screen_04

 

Dirty Read – This is when the data which is changed by one transaction (Uncommitted) is accessed by a different transaction. All isolation levels except for the ‘Read Uncommitted’ are protected against ‘Dirty Reads’.

img_screen_05

 

Non Repeatable Read – This is when a specific set of data which is accessed more than once in one transaction (Transaction A) and between these accesses, it’s being updated or deleted by another transaction (Transaction B). The repeatable read, serializable, and snapshot isolation levels protect a transaction from non-repeatable reads.

img_screen_03

 

Phantom Read – This is when two queries in the same transaction, against the same table, use the same ‘WHERE’ clause, and the query executed last returns more rows than the first one. Only the serializable and snapshot isolation levels protect a transaction from phantom reads.

img_screen_06

 

In order to solve the above mentioned concurrency issues, SQL Server uses the following type of locks.

  • Shared or S-locks - Shared locks are sometimes referred to as read locks. There can be several shared locks on any resource (such as a row or a page) at any one time. Shared locks are compatible with other shared locks.
  • Exclusive or X-locks - Exclusive locks are also referred to as write locks. Only one exclusive lock can exist on a resource at any time. Exclusive locks are not compatible with other locks, including shared locks.
  • Update or U-locks - Update locks can be viewed as a combination of shared and exclusive locks. An update lock is used to lock rows when they are selected for update, before they are actually updated. Update locks are compatible with shared locks, but not with other update locks.

Please refer to the following link to get more information regarding lock types. http://msdn.microsoft.com/en-us/library/ms175519.aspx

As I have mentioned earlier, the type of lock which the SQL server will be acquired depends on the active transactions isolation level. I will briefly describe each isolation level a bit further.

Read Committed Isolation Level – This is the default isolation level for new connections in SQL Server. This makes sure that dirty reads do not occur in your transactions. If the connection uses this isolation level, and if it encounters a dirty row while executing a DML statement, it’ll wait until the transaction which owns that row has been committed or rolled back, before continuing execution further ahead.

img_screen_07

 

Read Uncommitted Isolation level - Though this is not highly recommended by experts, it's better to consider about it too. It may result in a 'dirty read', but when correctly used it could provide great performance benefits.

You should consider using this isolation level only in routines where the issue of dirty reads is not a problem. Such routines usually return information that is not directly used as a basis for decisions. A typical example where dirty reads might be allowed is for queries that return data that are only used in lists in the application (such as a list of customers) or if the database is only used for read operations.

The read uncommitted isolation level is by far the best isolation level to use for performance, as it does not wait for other connections to complete their transactions when it wants to read data that these transactions have modified. In the read uncommitted isolation level, shared locks are not acquired for read operations; this is what makes dirty reads possible. This fact also reduces the work and memory required by the SQL Server lock manager. Because shared locks are not acquired, it is no problem to read resources locked by exclusive locks. However, while a query is executing in the read uncommitted isolation level, another type of lock called a ‘schema stability lock’ (Sch-S) is acquired to prevent Data Definition Language (DDL) statements from changing the table structure. Below is an example of the behavior of this isolation level.

img_screen_08

 

Repeatable Read Isolation Level - In this isolation level, it guarantees that dirty reads do not happen in your transaction. Also it makes sure that if you execute/issue two DML statements against the same table with the same where clause, both queries will return the same results. But this isolation level will protect against updates and deletes of earlier accessed rows, but not the inserts, which is known as ‘Phantom’ rows concurrency problem. Note that phantom rows might also occur if you use aggregate functions, although it is not as easy to detect.

img_screen_09

 

Serializable Isolation Level – This guarantees that none of the aforesaid concurrency issues can occur. It is very much similar to the ‘repeatable read isolation level’ except that this prevents the ‘phantom read’ also. But use of this isolation level increases the risk of having more blocked transactions and deadlocks compared to ‘Repeat Read’. However it will guarantee that if you issue two DML statements against the same table with the same WHERE clause, both of them will return exactly the same results, including same number of row count. To protect the transaction from inserts, SQL Server will need to lock a range of an index over a column that is included in the WHERE clause with shared locks. If such an index does not exist, SQL Server will need to lock the entire table.

 

Snapshot Isolation Level – In addition to the SQL’s standard isolation levels, SQL 2005 introduced ‘Snapshot Isolation Level’. This will protect against all the above mentioned concurrency issues, like the ‘Serializable Isolation Level’. But the main difference of this is, that it does not achieve this by preventing access to rows by other transaction. Only by storing versions of rows while the transaction is active as well as tracking when a specific row was inserted.

To illustrate this I will be using a test database. It’s name is ‘SampleDB’. First you have to enable the ‘Snapshot Isolation Level’ prior using it

alter database SampleDB set allow_snapshot_isolation on;
alter database SampleDB set read_committed_snapshot off;


Now we’ll create a sample table and insert few records.


create table SampleIsolaion(
id int,
name varchar(20),
remarks varchar(20) default ''
)

insert into SampleIsolaion (id,name,remarks)
select 1, 'Value A', 'Def' union
select 2, 'Value B', 'Def'


 


img_screen_10


 




Read Committed Snapshot Isolation Level – This can be considered as a new implementation of the ‘Read Committed’ isolation level. When this option is set, this provides statement level read consistency and we will see this using some examples in the post. Using this option, the reads do not take any page or row locks (only SCH-s: Schema Stability locks) and read the version of the data using row versioning by reading the data from tempdb. This option is set at the database level using the ALTER DATABASE command


I will illustrate the use of this isolation level with a sample. First enable the required isolation level.


alter database SampleDB set read_committed_snapshot on;
alter database SampleDB set allow_snapshot_isolation on;



Now lets create a table and populate it with few sample data.


create table sample_table(
id int,
descr varchar(20),
remarks varchar(20)
)

insert into sample_table
select 1,'Val A','Def' union
select 2,'Val B','Def'


Now open two query windows in SQL Server Management Studio.


--Window 1
begin tran
update sample_table set descr = 'Val P', remarks = 'Window 1' where id = 1


 


Without committing execute the following in the second window



--Window 2
begin tran
set transaction isolation level read committed
select * from sample_table



And you can see, even without committing, it’ll read from the older values, from the row versions which were created in the tempdb. If it was only the ‘Read Commited’ isolation level without the ‘Read Committed Snapshot’ option turned on, this select statement would have been locked.

Friday 25 November 2011

Deploy/Use assemblies which require Unsafe/External Access with CLR and T-SQL

 

What is an Unsafe Assembly?

Assemblies which are built using normal computational functions are considered as safe assemblies. But when assemblies do external operations such as reading file information, creating files, etc.… they are categorized as unsafe/external assemblies.

**Visual studio creates safe assemblies by default.

We will create an assembly which access the external file system, so that it will need external access. We will create a simple function which will return the file size for a given file, using the ‘FileInfo’ class.

using System;
using Microsoft.SqlServer.Server;
using System.IO;

public partial class UserDefinedFunctions {
[SqlFunction]
public static long GetFileSize(string FileName) {
FileInfo fi = new FileInfo(FileName);
return fi.Length;
}

};



Now right click the project (from the solution explorer) and go the properties tab. Form the ‘Database’ tab select the permission level to ‘External’. (Default value is ‘Safe’)

img_scr_001

Open MS SQL Server Management Studio (Run it as Administrator since you are going to assign permission to the current user), and log in as a different user than the one you are trying to provide access permission (For this example I am logging as ‘sa’). Execute the following script.


use master;
grant external access assembly to [Domain\UserID];
use SampleCLR;


Use the appropriate values for ‘Domain’ and ‘UserID’. (And ‘SampleCLR’ is the database that I will be using)

**Please note that this is a server wide permission. Therefore user can create any external assembly in any database on the SQL Server.

Above script will grant permission the user to create external assemblies on the executed server. But it is not sufficient. The database should be allowed to have external access assemblies.

There are two methods of doing so.


  1. Making the database trusted.
  2. Using sign assemblies.

Method 1 ~ Making Database Trusted

Execute the following script (using Management Studio) in order to make the database trusted.

alter database SampleCLR set trustworthy on;



And if you inspect the database properties, you can see that the database’s ‘Trustworthy’ property value is changed to ‘True’

img_scr_002

Now go to visual studio and deploy the solution. It will succeed without any issues.

However if you try to deploy without doing the above mentioned steps, you will get the following error.


CREATE ASSEMBLY for assembly <AssemblyName> failed because assembly <AssemblyName> is not authorized for PERMISSION_SET = EXTERNAL_ACCESS. The assembly is authorized when either of the following is true: the database owner (DBO) has EXTERNAL ACCESS ASSEMBLY permission and the database has the TRUSTWORTHY database property on; or the assembly is signed with a certificate or an asymmetric key that has a corresponding login with EXTERNAL ACCESS ASSEMBLY permission


We will check the deployed assembly by executing the following script. (I have a file on my D:\ drive with the mentioned name.)


select dbo.GetFileSize(N'D:\data.csv')

img_scr_003


img_scr_004



And if you try to execute the function without making the database trusted you will get the following error


Msg 10314, Level 16, State 11, Line 1
An error occurred in the Microsoft .NET Framework while trying to load assembly id 65540. The server may be running out of resources, or the assembly may not be trusted with PERMISSION_SET = EXTERNAL_ACCESS or UNSAFE. Run the query again, or check documentation to see how to solve the assembly trust issues. For more information about this error:
System.IO.FileLoadException: Could not load file or assembly 'sqlclrproject, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. An error relating to security occurred. (Exception from HRESULT: 0x8013150A)
System.IO.FileLoadException:
   at System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
   at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
   at System.Reflection.Assembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
   at System.Reflection.Assembly.Load(String assemblyString)


Method 2 ~ Using Sign Assemblies

Set the trustworthy to false by using the following script (You only have to do this if you have made the database a trusted one in the previous example, and I am keeping it false for illustrated purpose)


alter database SampleCLR set trustworthy off;



In order to sign an assembly we need a public/private key file (.snk file). We will create one using the ‘sn.exe’.

img_scr_005


sn -k "D:\Sample CLR\SampleCLRKey.snk"



And sign the assembly using the key file that we have created now.

To sign an assembly: go to project properties => select the ‘Signing’ tab and check the ‘Sign the assembly’ check box and browse and select the created file. Save the project.

In order to deploy the assembly,


  1. Need to create an asymmetric key using the key file which we have created in the SQL Server
  2. Need to create a login using that asymmetric key
  3. Giving that login the permission for external access assemblies

img_scr_006


Use the following script to create the asymmetric key using SQL Server Management Studio. (** Please note that the key should be created on the master database)


use master;
create asymmetric key CLRExtensionKey
from file = 'D:\Sample CLR\SampleCLRKey.snk'
encryption by password = '@Str0ngP@$$w0rd'



Now create the login using the above created key (*Please note that the login should be created on the database which you want to publish the assembly to)


use SampleCLR;
create login CLRExtensionLogin from asymmetric key CLRExtensionKey;



Give the login permission for external access assemblies.


use master;
grant external access assembly to CLRExtensionLogin;



Now go to visual studio and deploy the solution. And you can use the following statement which we used in Method 1.


select dbo.GetFileSize(N'D:\data.csv')


img_scr_007

Tuesday 22 November 2011

Using CLR functions with T-SQL


Why use CLR?
Before using CLR, you should question ‘Why’. When using CLR functions within T-SQL, you have to maintain two different programming environments, unless what you gain worth more than having it.
We need to use the CLR functions when occasions such as:
When we have to access system resources like file system or network (**Extended stored procedures can do the same. But they are deprecated and will be removed from future versions of SQL)
Or when the business logics are too complex to write in T-SQL, which can be easily done using .net languages (Reusing the logics already written, without duplicating them using T-SQL)

To illustrate this I will create a CLR function which will create a text file and append the text which is passed from a T-SQL statement.
Open Visual studio and create a new ‘SQL Server Project’
img_scr_001

Next dialog you will be prompted to select the database which you plan to deploy your extension. You can either select from existing or connect to a different one.
img_scr_002

In next screen you will be prompted, whether you want to debug your .net coding. Select ‘yes’ or ‘no’ depending on your requirement.
img_scr_003

Right click on the newly created project and add new user-defined- function
img_scr_004
I have named it as ‘WriteToTextFileSample’.
img_scr_005
Use the following code:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;

using System.IO;
using System.Text;

public partial class UserDefinedFunctions {
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlString WriteToTextFileSample(string filename, string data) {
FileStream fs = File.Open(filename, FileMode.Append);
byte[] b = new UTF8Encoding(true).GetBytes(data);

fs.Write(b, 0, data.Length);
fs.Close();

return new SqlString("Completed");
}
};

**The functions should be 'public static' and all the functions should have '[Microsoft.SqlServer.Server.SqlFunction]' attribute or you will not be able to call it from SQL.


Go to the project properties and change the ‘Permission Level’ to ‘Unsafe’ in Database section. (This is only required if you are performing tasks such as writing to files, accessing system related resources. You do not need this if you are performing calculations, etc..)

Save your project. Before deploying this you have to enable the ‘clr  enable’ to ‘1’. Use the following T-SQL statement to do so.

sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'clr enabled', 1;
GO
RECONFIGURE;
GO


Once executed, deploy the project (Build—> Deploy Solution). You will be prompted with the SQL credentials.

img_scr_006



Once it’s deployed successfully use the following sample statement to use the function which we have created.

select dbo.WriteToTextFileSample(
N'D:\SampleCLRText.txt',
N'Hello from SQL !!!'
)


img_scr_007