<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>grokgarble.com &#187; T-SQL</title>
	<atom:link href="http://jeffmurr.com/blog/?cat=2&#038;feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://jeffmurr.com/blog</link>
	<description>Database, Software, and System Engineering</description>
	<lastBuildDate>Tue, 26 Sep 2017 19:07:40 +0000</lastBuildDate>
	<language>en-US</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=3.9.30</generator>
	<item>
		<title>To VARCHAR or NVARCHAR? (and how it bit me using HASHBYTES)</title>
		<link>http://jeffmurr.com/blog/?p=202</link>
		<comments>http://jeffmurr.com/blog/?p=202#comments</comments>
		<pubDate>Tue, 20 Aug 2013 16:53:45 +0000</pubDate>
		<dc:creator><![CDATA[Jeff Murr]]></dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[T-SQL]]></category>

		<guid isPermaLink="false">http://jeffmurr.com/blog/?p=202</guid>
		<description><![CDATA[The Difference The key difference between the two data types is how they&#8217;re stored. VARCHAR is stored as regular 8-bit data, NVARCHAR strings are stored in the database as UTF-16. UTF-8 (UCS Transformation Format—8-bit) is a variable-width encoding that can represent every character in the Unicode character set. It was designed for backward compatibility with [&#8230;]]]></description>
				<content:encoded><![CDATA[<h3><strong>The Difference</strong></h3>
<p>The key difference between the two data types is how they&#8217;re stored. <a href="http://technet.microsoft.com/en-us/library/ms176089.aspx">VARCHAR </a>is stored as regular 8-bit data, <a href="http://technet.microsoft.com/en-us/library/ms186939.aspx">NVARCHAR </a>strings are stored in the database as UTF-16.</p>
<p>UTF-8 (UCS Transformation Format—8-bit) is a variable-width encoding that can represent every character in the Unicode character set. It was designed for backward compatibility with ASCII and to avoid the complications of <a href="http://en.wikipedia.org/wiki/Endianness">endianness </a>and byte order marks in UTF-16 and UTF-32.</p>
<p>UTF-8 has become the dominant character encoding.  Over half of all internet pages are encoded this way, the Internet Mail Consortium (IMC) recommends that all e-mail programs be able to display and create mail using UTF-8, and UTF-8 is also increasingly being used as the default character encoding in operating systems, programming languages, APIs, and software applications.</p>
<p>UTF-8 is [or continues to be] kind of a big deal&#8230; The others, not so much anymore.</p>
<h3><strong>Storage</strong></h3>
<p>NVARCHAR strings have the same length restrictions as its VARCHAR brother — 8,000 bytes. However, since NVARCHARs use two bytes for each character, that means a given NVARCHAR can only hold 4,000 characters (<i>not</i> bytes) maximum. The amount of storage needed for NVARCHAR entities is going to be twice whatever you&#8217;d allocate for a plain old VARCHAR.  Therefore, most don&#8217;t want to use NVARCHAR universally, and may want to fall back on VARCHAR — which takes up less space per row — whenever possible.</p>
<h3><strong>How it bit me&#8230;</strong></h3>
<p>I have some data that&#8217;s MD5 hased using a C# function much like this example from <a href="http://msdn.microsoft.com/en-us/library/system.security.cryptography.md5.aspx">MSDN </a>that I needed to validate at my data layer (SQL Server 2008 R2).  However, I was getting different values that should have matched since I was providing the same intput.</p>
<p>Here&#8217;s the function using the MD5 class</p>
<pre class="brush:csharp">static string GetMd5Hash(MD5 md5Hash, string input)
        {

            // Convert the input string to a byte array and compute the hash. 
            byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));

            // Create a new Stringbuilder to collect the bytes 
            // and create a string.
            StringBuilder sBuilder = new StringBuilder();

            // Loop through each byte of the hashed data  
            // and format each one as a hexadecimal string. 
            for (int i = 0; i &lt; data.Length; i++)
            {
                sBuilder.Append(data[i].ToString("x2"));
            }

            // Return the hexadecimal string. 
            return sBuilder.ToString();
        }</pre>
<p>The code is storing the returned string object in a column along with some salted details for a password.  Somehow a few of the values were not syncing up with the input correctly.  To test I used input and the  <a href="http://technet.microsoft.com/en-us/library/ms174415.aspx">HASHBYTES </a>function to convert and compare to stored values with original inputs&#8217; HASED values to find the culprits.  But, what I found was nothing matched!  I went back to simple data to troubleshoot and found that I was getting different values for &#8220;FOO&#8221; from using the C# method vs. the SQL method!</p>
<p>Here&#8217;s an example:</p>
<h4>C#</h4>
<pre class="brush:csharp">MD5 md5Hash = MD5.Create();
string input = "FOO";
string results = GetMd5Hash(md5Hash, input);
#results = 901890A8E9C8CF6D5A1A542B229FEBFF</pre>
<h4>SQL</h4>
<pre class="brush:sql">DECLARE @nvarchar nvarchar(400) 

SET @nvarchar = 'FOO'

SELECT CONVERT(VARCHAR(32), HASHBYTES( 'MD5', @nvarchar ), 2)
--RESULT:  4676C8342EF52153F898C2EAAD1C528D</pre>
<h3><strong>The Problem</strong></h3>
<p>The <a href="http://technet.microsoft.com/en-us/library/ms174415.aspx">HASHBYTES </a>built-in function indicates it will take an input of varchar, nvarchar, or varbinary to be hashed.  What is easy to overlook is that <strong>the encoding of datatype matters.  </strong></p>
<p>Even though it clearly shows in the C# code and example that it is encoding to UTF-8, I didn&#8217;t catch it until after I pulled out a few remaining hairs that the encoding of the variables in storage were causing my problem.  SQL ambiguates  the conversion of nvarchar and varchar on the fly, displaying them both as unincoded strings, post conversion when you select on them.  So, the difference its transparent when inspecting the result sets.  At least that makes me &#8220;feel&#8221; like less of an idiot.</p>
<h2><strong>Solution</strong></h2>
<p>Depending on how your variable is stored within SQL will dictate the output of your hash, regardless of algorithm since the <strong>binary</strong> data presented to the function will be different per <strong>data type</strong>.</p>
<p>Therefore, if you&#8217;re wondering why your HASHED values of any encryption algorithm differ from their clear text counter parts.  Ensure your encoding of your data type is the same as the original source.</p>
<p>For a proof, play with the below and modify the datatypes of both the conversion and variables and see how encryption and hashing are always done at the byte level.</p>
<pre class="brush:sql"> DECLARE @varchar varchar(400) 
 DECLARE @nvarchar nvarchar(400) 

 SET @varchar = 'FOO'
 SET @nvarchar = 'FOO'

 SELECT CONVERT(VARCHAR(32), HASHBYTES( 'MD5', @varchar ), 2)
--RESULT:  901890A8E9C8CF6D5A1A542B229FEBFF
 SELECT CONVERT(VARCHAR(32), HASHBYTES( 'MD5', @nvarchar ), 2)
--RESULT: 4676C8342EF52153F898C2EAAD1C528D</pre>
<div data-counters='1' data-style='square' data-size='regular' data-url='http://jeffmurr.com/blog/?p=202' data-title='To VARCHAR or NVARCHAR? (and how it bit me using HASHBYTES)' class='linksalpha_container linksalpha_app_3'><a href='//www.linksalpha.com/share?network='facebook' class='linksalpha_icon_facebook'></a><a href='//www.linksalpha.com/share?network='twitter' class='linksalpha_icon_twitter'></a><a href='//www.linksalpha.com/share?network='googleplus' class='linksalpha_icon_googleplus'></a><a href='//www.linksalpha.com/share?network='mail' class='linksalpha_icon_mail'></a></div><div data-position='' data-url='http://jeffmurr.com/blog/?p=202' data-title='To VARCHAR or NVARCHAR? (and how it bit me using HASHBYTES)' class='linksalpha_container linksalpha_app_7'><a href='//www.linksalpha.com/share?network='facebook' class='linksalpha_icon_facebook'></a><a href='//www.linksalpha.com/share?network='twitter' class='linksalpha_icon_twitter'></a><a href='//www.linksalpha.com/share?network='googleplus' class='linksalpha_icon_googleplus'></a><a href='//www.linksalpha.com/share?network='mail' class='linksalpha_icon_mail'></a></div>
<!-- NgfbSharing::get_buttons content filter skipped: buttons not allowed in rss feeds -->
]]></content:encoded>
			<wfw:commentRss>http://jeffmurr.com/blog/?feed=rss2&#038;p=202</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Grant Execute Permission on All Stored Procedures in a SQL Database</title>
		<link>http://jeffmurr.com/blog/?p=8</link>
		<comments>http://jeffmurr.com/blog/?p=8#comments</comments>
		<pubDate>Sat, 26 Jan 2013 21:38:50 +0000</pubDate>
		<dc:creator><![CDATA[Jeff Murr]]></dc:creator>
				<category><![CDATA[T-SQL]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://jeffmurr.com/blog/?p=8</guid>
		<description><![CDATA[First blog post.  I&#8217;ll make it short, simple, and [hopefully] sweet. I like it when bloggers have the solution easy to find at the top and then explain in a little more detail below.  I&#8217;ll try following that as much as possible. Recently, I was asked to blanket all user stored procedures.  The practicality of this [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>First blog post.  I&#8217;ll make it short, simple, and [hopefully] sweet.</p>
<p>I like it when bloggers have the solution easy to find at the top and then explain in a little more detail below.  I&#8217;ll try following that as much as possible.</p>
<p>Recently, I was asked to blanket all user stored procedures.  The practicality of this may be limited, but a useful trick and I thought I&#8217;d share along with breaking it down.</p>
<p>SQL 2000</p>
<pre class="brush:sql">USE [DataBaseName]
DECLARE Proc_Cursor CURSOR
FOR SELECT NAME FROM sysobjects WHERE objectproperty( id, N'IsMSShipped' ) = 0
AND objectproperty( id, N'IsProcedure' ) = 1
OPEN Proc_Cursor
DECLARE @Name VARCHAR(500)
DECLARE @Query VARCHAR(500)
FETCH NEXT FROM Proc_Cursor INTO @Name;
WHILE @@FETCH_STATUS = 0
BEGIN
  SET @Query = 'GRANT EXEC ON ' + @Name + ' TO [CustomRole]'
  EXEC(@Query)
  FETCH NEXT FROM Proc_Cursor INTO @Name;
END
CLOSE Proc_Cursor;
DEALLOCATE Proc_Cursor;</pre>
<p><code><br />
</code></p>
<p>SQL 2005/SQL 2008/2008 R2</p>
<pre class="brush:sql">USE [DataBaseName]
DECLARE Proc_Cursor CURSOR
FOR SELECT NAME FROM sys.objects WHERE type = 'P' AND is_ms_shipped = '0'
OPEN Proc_Cursor
DECLARE @Name VARCHAR(500)
DECLARE @Query VARCHAR(500)
FETCH NEXT FROM Proc_Cursor INTO @Name;
WHILE @@FETCH_STATUS = 0
BEGIN
  SET @Query = 'GRANT EXEC ON ' + @Name + ' TO [CustomRole]'
  EXEC(@Query)
  FETCH NEXT FROM Proc_Cursor INTO @Name;
END
CLOSE Proc_Cursor;
DEALLOCATE Proc_Cursor</pre>
<p>I&#8217;ll break the above methods down for in the 2008 version to simplify reading.</p>
<p>First, we create a cursor of all objects that are stored procedures that are user defined.</p>
<blockquote>
<pre class="brush:sql">DECLARE Proc_Cursor CURSOR
FOR SELECT NAME FROM sys.objects WHERE type = 'P' AND is_ms_shipped = '0'</pre>
</blockquote>
<p>Next, open the cursor and work each stroed proc captured in the above select statement with a WHILE loop, creating dynamic SQL.  The dynamic SQL is needed since you can&#8217;t execute a GRANT command with a variable out right:</p>
<blockquote>
<pre class="brush:sql">OPEN Proc_Cursor
DECLARE @Name VARCHAR(500)
DECLARE @Query VARCHAR(500)
FETCH NEXT FROM Proc_Cursor INTO @Name;
WHILE @@FETCH_STATUS = 0
BEGIN
  SET @Query = 'GRANT EXEC ON ' + @Name + ' TO [CustomRole]'</pre>
</blockquote>
<p>Execute our new Query each time we find a new stored proc in our cursor then fetch the next:</p>
<blockquote>
<pre class="brush:sql">  EXEC(@Query)
  FETCH NEXT FROM Proc_Cursor INTO @Name;
END</pre>
</blockquote>
<p>When we&#8217;re done, make sure to close your cursor and deallocate its resources:</p>
<blockquote>
<pre class="brush:sql">CLOSE Proc_Cursor;
DEALLOCATE Proc_Cursor;</pre>
</blockquote>
<p>Happy granting&#8230;</p>
<div data-counters='1' data-style='square' data-size='regular' data-url='http://jeffmurr.com/blog/?p=8' data-title='Grant Execute Permission on All Stored Procedures in a SQL Database' class='linksalpha_container linksalpha_app_3'><a href='//www.linksalpha.com/share?network='facebook' class='linksalpha_icon_facebook'></a><a href='//www.linksalpha.com/share?network='twitter' class='linksalpha_icon_twitter'></a><a href='//www.linksalpha.com/share?network='googleplus' class='linksalpha_icon_googleplus'></a><a href='//www.linksalpha.com/share?network='mail' class='linksalpha_icon_mail'></a></div><div data-position='' data-url='http://jeffmurr.com/blog/?p=8' data-title='Grant Execute Permission on All Stored Procedures in a SQL Database' class='linksalpha_container linksalpha_app_7'><a href='//www.linksalpha.com/share?network='facebook' class='linksalpha_icon_facebook'></a><a href='//www.linksalpha.com/share?network='twitter' class='linksalpha_icon_twitter'></a><a href='//www.linksalpha.com/share?network='googleplus' class='linksalpha_icon_googleplus'></a><a href='//www.linksalpha.com/share?network='mail' class='linksalpha_icon_mail'></a></div>
<!-- NgfbSharing::get_buttons content filter skipped: buttons not allowed in rss feeds -->
]]></content:encoded>
			<wfw:commentRss>http://jeffmurr.com/blog/?feed=rss2&#038;p=8</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
