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

<channel>
	<title>DbTracer</title>
	<atom:link href="http://blog.dbtracer.org/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.dbtracer.org</link>
	<description>MS SQL Compare and Continuous Integration Tool</description>
	<lastBuildDate>Mon, 30 Aug 2010 08:24:47 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Audit Trail &#8211; Tracing Data Changes in Database</title>
		<link>http://blog.dbtracer.org/2010/08/30/audit-trail-tracing-data-changes-in-database/</link>
		<comments>http://blog.dbtracer.org/2010/08/30/audit-trail-tracing-data-changes-in-database/#comments</comments>
		<pubDate>Mon, 30 Aug 2010 07:00:14 +0000</pubDate>
		<dc:creator>Petr Kozelek</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[Tracing]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[DBTracer]]></category>
		<category><![CDATA[tracing]]></category>

		<guid isPermaLink="false">http://blog.dbtracer.org/?p=147</guid>
		<description><![CDATA[The common requirement in many enterprise applications is logging of data changes in a database &#8211; what data has changed, who changed them and when (audit logging). Bloggers published many articles about this old problem but there is only few general approaches how to do that in relational databases. Promiscuous Women Cause Problems for Database [...]


Related posts:<ul><li><a href='http://blog.dbtracer.org/2010/01/12/database-continuous-integration-with-dbtracer/' rel='bookmark' title='Permanent Link: Database Continuous Integration with DBTracer'>Database Continuous Integration with DBTracer</a></li>
</ul>]]></description>
			<content:encoded><![CDATA[<p>The common requirement in many enterprise applications is logging of data changes  in a database &#8211; what data has changed, who changed them and when (<a href="http://en.wikipedia.org/wiki/Audit_trail">audit logging</a>).  Bloggers published many articles about this old problem but there is only few general approaches how to do that in relational databases.<span id="more-147"></span></p>
<h2>Promiscuous Women Cause Problems for Database Administrators</h2>
<p>This is a fiction story that never happened:</p>
<p>Juliet Capulet meets Paul Smith; they fell in love and marry on 25th August 2009. When Juliet is back at work she asks the db admin to change her name in a company database. The admin is not happy to have additional work with this stuff but he does it for her.</p>
<p>Juliet&#8217;s and Paul&#8217;s marriage is not going well and Juliet divorces Paul after a short period. Soon Juliet feels alone, she meets Romeo Montague and, of course, falls in desperate love with him. Logically, another wedding is arranged and Juliet asks db admin to change her name again on 10th January 2010.</p>
<p>The tragedy of all Juliet&#8217;s love relationships finishes when she finds her husband Romeo as a roulette player spending all their money. She divorces again and changes her name to Juliet Singleton on 21st July 2010 with the vision not to marry anybody again. Needless to say, the db admin is close to committing suicide because his database does not allow changing the name more than twice.</p>
<p>What would you suggest the database admin to do better in his next life?</p>
<h2>Problem description</h2>
<p>Let us summarize what the db admin was asked to do with Juliet&#8217;s personal data:</p>
<ul>
<li>Juliet Capulet gets the job on 2005-03-01</li>
<li>Name <em>Juliet Capulet</em> changes to <em>Juliet Smith </em>on 2009-08-25</li>
<li>Name <em>Juliet Smith </em>changes to <em>Juliet Montague</em> on 2010-01-10</li>
<li>Name <em>Juliet Montague </em>changes to <em>Julie Singleton</em> on 2010-07-21</li>
</ul>
<h2>Solution No.1: Roll off Out-dated data</h2>
<p>The simplest solution for keeping historical data in the database is to create a duplicated record before update. After that we can update the requested data. In case of tracing Juliet&#8217;s name  we get these data in the database table:</p>
<table>
<tbody>
<tr>
<td>id</td>
<td>name</td>
<td>created_date</td>
<td>created _by</td>
</tr>
<tr>
<td>124</td>
<td>Juliet Capulet</td>
<td>2005-03-01</td>
<td>admin</td>
</tr>
<tr>
<td>124</td>
<td>Juliet Smith</td>
<td>2009-08-25</td>
<td>admin</td>
</tr>
<tr>
<td>124</td>
<td>Juliet Montague</td>
<td>2010-01-10</td>
<td>admin</td>
</tr>
<tr>
<td>124</td>
<td>Juliet Singleton</td>
<td>2010-07-21</td>
<td>admin</td>
</tr>
</tbody>
</table>
<p>In real database schema, id is primary key and has to be unique. So we need extra column containing information about row id from which data were rolled off. Additionally, it would be helpful to have a column representing status of the record. Because situation gets more complex here I show how data evolve in database:</p>
<p>Juliet Capulet gets the job on 2005-03-01.</p>
<table>
<tbody>
<tr>
<td>id</td>
<td>original_id</td>
<td>status</td>
<td>name</td>
<td>created_date</td>
<td>created _by</td>
</tr>
<tr>
<td>124</td>
<td>124</td>
<td>active</td>
<td>Juliet Capulet</td>
<td>2005-03-01</td>
<td>admin</td>
</tr>
</tbody>
</table>
<p>Name <em>Juliet Capulet</em> changes to <em>Juliet Smith </em>on 2009-08-25.</p>
<table>
<tbody>
<tr>
<td>id</td>
<td>original_id</td>
<td>status</td>
<td>name</td>
<td>created_date</td>
<td>created _by</td>
</tr>
<tr>
<td>124</td>
<td>124</td>
<td>active</td>
<td>Juliet Smith</td>
<td>2009-08-25</td>
<td>admin</td>
</tr>
<tr>
<td>254</td>
<td>124</td>
<td>history</td>
<td>Juliet Capulet</td>
<td>2005-03-01</td>
<td>admin</td>
</tr>
</tbody>
</table>
<p>Name <em>Juliet Smith </em>changes to <em>Juliet Montague</em> on 2010-01-10.</p>
<table>
<tbody>
<tr>
<td>id</td>
<td>original_id</td>
<td>status</td>
<td>name</td>
<td>created_date</td>
<td>created _by</td>
</tr>
<tr>
<td>124</td>
<td>124</td>
<td>active</td>
<td>Juliet Montague</td>
<td>2010-01-10</td>
<td>admin</td>
</tr>
<tr>
<td>254</td>
<td>124</td>
<td>history</td>
<td>Juliet Capulet</td>
<td>2005-03-01</td>
<td>admin</td>
</tr>
<tr>
<td>347</td>
<td>124</td>
<td>history</td>
<td>Juliet Smith</td>
<td>2009-08-25</td>
<td>admin</td>
</tr>
</tbody>
</table>
<p>Name <em>Juliet Montague </em>changes to <em>Julie Singleton</em> on 2010-07-21.</p>
<table>
<tbody>
<tr>
<td>id</td>
<td>original_id</td>
<td>status</td>
<td>name</td>
<td>created_date</td>
<td>created _by</td>
</tr>
<tr>
<td>124</td>
<td>124</td>
<td>active</td>
<td>Juliet Singleton</td>
<td>2010-07-21</td>
<td>admin</td>
</tr>
<tr>
<td>254</td>
<td>124</td>
<td>history</td>
<td>Juliet Capulet</td>
<td>2005-03-01</td>
<td>admin</td>
</tr>
<tr>
<td>347</td>
<td>124</td>
<td>history</td>
<td>Juliet Smith</td>
<td>2009-08-25</td>
<td>admin</td>
</tr>
<tr>
<td>489</td>
<td>124</td>
<td>history</td>
<td>Juliet Montague</td>
<td>2010-01-10</td>
<td>admin</td>
</tr>
</tbody>
</table>
<p>You can see that each change to the record with id=124 invokes a) creating duplicated row with <code>status=history</code> and b) updating the column name to a requested value with created_date set to current date. When the active record is going to be &#8220;deleted&#8221; then only the status flag changes the value from <em>active</em> to <em>history</em>.</p>
<h3>Advantages</h3>
<p>It is simple to implement audit logging based on rolling out old data. You do not need additional tables. Maintenance is simple, too. If you decide to remove old data then it is the matter of one SQL.</p>
<h3>Disadvantages</h3>
<p>But what if you need to implement audit logging in more tables? You need to add columns <code>original_id, status, created_date and created_by</code>. And you have to implement previously introduced roll-off logic, either to database directly (usually with table triggers) or in the application.</p>
<p>The problem can be that when data changes then the whole record is copied, i.e. also data which do not change. It causes data duplication and, potentially, database disk space can increase markedly if changes occur frequently. For example, if table persons has a column photo with binary data containing the photography then each and every time Juliet&#8217;s name changes the whole record (including the photo) is copied to rolled-off record.</p>
<p>Another disadvantage is that the complexity of each table supporting audit logging increases. You must have in mind all the time that retrieving the records is not simple. You always have to use the SELECT clause with condition</p>

<div class="wp_codebox"><table><tr id="p1474"><td class="line_numbers"><pre>1
</pre></td><td class="code" id="p147code4"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #66cc66;">*</span> <span style="color: #993333; font-weight: bold;">FROM</span> persons <span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #993333; font-weight: bold;">status</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'active'</span></pre></td></tr></table></div>

<p>When you need to roll back historical data for a particular record you have to copy all columns from the historical record to the active record. It would be easier just to switch status value from &#8220;history&#8221; to &#8220;active&#8221; but it would break reference integrity if the record was referenced in other tables.</p>
<h2>Solution No.2: Dedicated Data-Tracing Table</h2>
<p>Another approach is based on separate audit log table that is dedicated to logging data changes coming from all tables having audit log feature:</p>
<table>
<tbody>
<tr>
<td>id</td>
<td>table</td>
<td>column</td>
<td>row</td>
<td>changed_date</td>
<td>changed_by</td>
<td>old_value</td>
<td>new_value</td>
</tr>
<tr>
<td>1241</td>
<td>persons</td>
<td>name</td>
<td>124</td>
<td>2005-03-01</td>
<td>admin</td>
<td>Juliet Capulet</td>
<td>Juliet Capulet</td>
</tr>
<tr>
<td>1654</td>
<td>persons</td>
<td>name</td>
<td>124</td>
<td>2009-08-25</td>
<td>admin</td>
<td>Juliet Capulet</td>
<td>Juliet Smith</td>
</tr>
<tr>
<td>2547</td>
<td>persons</td>
<td>name</td>
<td>124</td>
<td>2010-01-10</td>
<td>admin</td>
<td>Juliet Smith</td>
<td>Juliet Montague</td>
</tr>
<tr>
<td>3645</td>
<td>persons</td>
<td>name</td>
<td>124</td>
<td>2010-07-21</td>
<td>admin</td>
<td>Juliet Montague</td>
<td>Juliet Singleton</td>
</tr>
</tbody>
</table>
<h3>Advantages</h3>
<p>This solutions separates the concerns much better. There is only one common data store for all historical data. Further, you have to implement audit log feature only once for all tables which should support it.</p>
<p>Compared to the previous solution, when the record changes only the changed data are logged. Thus it is expected to be a little bit faster but I did not do any tests so I cannot prove it exactly. The real advantage is that you need lower disk space to store data changes. You can improve the table structure when you normalize the log table and you put just integer references to &#8220;table&#8221; and &#8220;column&#8221;.</p>
<p>You can easily retrieve user activity just by the query</p>

<div class="wp_codebox"><table><tr id="p1475"><td class="line_numbers"><pre>1
</pre></td><td class="code" id="p147code5"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #66cc66;">*</span> <span style="color: #993333; font-weight: bold;">FROM</span> audit_log <span style="color: #993333; font-weight: bold;">WHERE</span> changed_by<span style="color: #66cc66;">=</span><span style="color: #ff0000;">'admin'</span></pre></td></tr></table></div>

<h3>Disadvantages</h3>
<p>All data changes are logged in a common table so old and new values stored there must be of some generic type. For example, in MS SQL it can be &#8220;sql_variant&#8221;. Or you can convert the values to &#8220;varchar&#8221; before storing them in the log table.</p>
<p>Rollback is rather difficult task to be implemented. If you want to roll data back to 3rd March 21010 you have to use query</p>

<div class="wp_codebox"><table><tr id="p1476"><td class="line_numbers"><pre>1
</pre></td><td class="code" id="p147code6"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #66cc66;">&#91;</span><span style="color: #993333; font-weight: bold;">table</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">,</span> <span style="color: #66cc66;">&#91;</span><span style="color: #993333; font-weight: bold;">column</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">,</span> old_value<span style="color: #66cc66;">,</span> new_value <span style="color: #993333; font-weight: bold;">FROM</span> audit_log <span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #66cc66;">&#91;</span><span style="color: #993333; font-weight: bold;">table</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">'persons'</span> <span style="color: #993333; font-weight: bold;">AND</span> row<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">124</span> <span style="color: #993333; font-weight: bold;">and</span> changed_date &amp;gt; <span style="color: #ff0000;">'2010-03-01'</span> <span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> changed_date</pre></td></tr></table></div>

<p>and then you iterate through the result set and build the dynamic query because table and column info is in the result. It is more complicated compared to the previous solution. Fortunately, the feature has to be implemented only once and the can be reused across the whole application.</p>


<p>Related posts:<ul><li><a href='http://blog.dbtracer.org/2010/01/12/database-continuous-integration-with-dbtracer/' rel='bookmark' title='Permanent Link: Database Continuous Integration with DBTracer'>Database Continuous Integration with DBTracer</a></li>
</ul></p>]]></content:encoded>
			<wfw:commentRss>http://blog.dbtracer.org/2010/08/30/audit-trail-tracing-data-changes-in-database/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Speed Up Typing Text with WatiN</title>
		<link>http://blog.dbtracer.org/2010/08/05/speed-up-typing-text-with-watin/</link>
		<comments>http://blog.dbtracer.org/2010/08/05/speed-up-typing-text-with-watin/#comments</comments>
		<pubDate>Thu, 05 Aug 2010 22:50:21 +0000</pubDate>
		<dc:creator>Petr Kozelek</dc:creator>
				<category><![CDATA[Tips]]></category>
		<category><![CDATA[WatiN]]></category>

		<guid isPermaLink="false">http://blog.dbtracer.org/?p=125</guid>
		<description><![CDATA[I use WatiN for UA testing and I was facing the problem that WatiN is slow while typing text into text field with TextField.TypeText(string) method. TypeText(string) is slow because during run it fires sequences of key events: KeyDown(char), KeyPress(char), KeyUp(char). The sequence is invoked as many times as the length of the input string is. As the [...]


No related posts.]]></description>
			<content:encoded><![CDATA[<p>I use <a href="http://watin.sourceforge.net/">WatiN</a> for UA testing and I was facing the problem that WatiN is slow while typing text into text field with <code>TextField.TypeText(string)</code> method.</p>
<p><span id="more-125"></span><code>TypeText(string)</code> is slow because during run it fires sequences of key events: <code>KeyDown(char), KeyPress(char), KeyUp(char)</code>. The sequence is invoked as many times as the length of the input string is. As the result, the input text is typed to the text field one by one char. It is slow and when you have hundreds of tests then you wait tens of minutes for their execution! I created simple extension method to speed up typing of text markedly &#8211; for a string 10 chars long the performance of typing is around 30 times higher.</p>

<div class="wp_codebox"><table><tr id="p1259"><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code" id="p125code9"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF; font-weight: bold;">public</span> <span style="color: #0600FF; font-weight: bold;">static</span> <span style="color: #6666cc; font-weight: bold;">class</span> WatiNExtensions
<span style="color: #008000;">&#123;</span>
    <span style="color: #0600FF; font-weight: bold;">public</span> <span style="color: #0600FF; font-weight: bold;">static</span> <span style="color: #6666cc; font-weight: bold;">void</span> TypeTextQuickly<span style="color: #008000;">&#40;</span><span style="color: #0600FF; font-weight: bold;">this</span> TextField textField, <span style="color: #6666cc; font-weight: bold;">string</span> text<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        textField<span style="color: #008000;">.</span><span style="color: #0000FF;">SetAttributeValue</span><span style="color: #008000;">&#40;</span><span style="color: #666666;">&quot;value&quot;</span>, text<span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span>
    <span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span></pre></td></tr></table></div>

<p>In my solution I do not use simulated key events. I use direct setting of <code>value</code> attribute in text field. The limitation of this solution is that it does not raise <code>focus</code> and <code>blur</code> events. Additionally, no key events are fired.</p>
<p>Usage is simple:</p>

<div class="wp_codebox"><table><tr id="p12510"><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code" id="p125code10"><pre class="csharp" style="font-family:monospace;">var browser <span style="color: #008000;">=</span> <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span style="color: #008000;">new</span></a> IE<span style="color: #008000;">&#40;</span><span style="color: #666666;">&quot;http://google.com&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span>
browser<span style="color: #008000;">.</span><span style="color: #0000FF;">TextField</span><span style="color: #008000;">&#40;</span><span style="color: #666666;">&quot;q&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">.</span><span style="color: #0000FF;">TypeTextQuickly</span><span style="color: #008000;">&#40;</span><span style="color: #666666;">&quot;WatiN&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span> <span style="color: #008080; font-style: italic;">// fast - raises neither key events nor focus and blur on text field</span>
<span style="color: #008080; font-style: italic;">// browser.TextField(&quot;q&quot;).TypeText(&quot;WatiN&quot;); // slow - raises key events</span></pre></td></tr></table></div>



<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.dbtracer.org/2010/08/05/speed-up-typing-text-with-watin/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Porting a Subversion to a Git Repository with an Error &#8220;Permission denied: Can&#8217;t open &#8216;/tmp/report.tmp&#8217;&#8221;</title>
		<link>http://blog.dbtracer.org/2010/01/20/porting-subversion-git-with-error/</link>
		<comments>http://blog.dbtracer.org/2010/01/20/porting-subversion-git-with-error/#comments</comments>
		<pubDate>Wed, 20 Jan 2010 17:02:27 +0000</pubDate>
		<dc:creator>Petr Kozelek</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Git]]></category>
		<category><![CDATA[solutions]]></category>
		<category><![CDATA[Subversion]]></category>

		<guid isPermaLink="false">http://petrkozelek.e-blog.cz/?p=102</guid>
		<description><![CDATA[I was dealing with a problem of converting existing Subversion repository to a new git repository on my local Windows XP station.I carefully followed steps described here: C:\Program Files\Git\bin&#62;git svn init -s file:///D:/path/to/svn/repository Initialized empty Git repository in C:/Program Files/Git/bin/.git/ But Ooops! Error occurred when I tried to fetch all the history to Git repository: [...]


No related posts.]]></description>
			<content:encoded><![CDATA[<p>I was dealing with a problem of converting existing Subversion repository to a new git repository on my local Windows XP station.<span id="more-102"></span>I carefully followed steps described <a href="http://blog.romansklenar.cz/porting-a-subversion-repository-into-git/">here</a>:</p>
<pre>C:\Program Files\Git\bin&gt;git svn init -s file:///D:/path/to/svn/repository
Initialized empty Git repository in C:/Program Files/Git/bin/.git/</pre>
<p>But Ooops! Error occurred when I tried to fetch all the history to Git repository:</p>
<pre>C:\Program Files\Git\bin&gt;git svn fetch
 A       notes.txt
 A       pages.txt
 A       settings.config
r7 = f3dba0984f11e2f358923c23d89440789eb4591b (refs/remotes/references)
<strong>Permission denied: Can't open '/tmp/report.tmp': Permission denied at C:\Program Files\Git/libexec/git-core/git-svn line 2723</strong></pre>
<p>It was an misguiding error since I had neither a &#8220;tmp&#8221; directory in the original <kbd>svn</kbd> repository nor &#8220;report.tmp&#8221; directory<strong><strong>.</strong></strong> For my surprise the problem was caused by different formats used by in original Subversion repository and by Subversion module included in my Git instance that probably uses older Subversion format. I use Git 1.6.5.1.1367.gcd48 that probably has Subversion module supporting format 4 but my Subversion repository was in format 5.</p>
<h2>Solution</h2>
<p>Luckily the solution for such WTF <a href="http://code.google.com/p/msysgit/issues/detail?id=298#c5">exists</a>. If I access Subversion repository via SVN server instead of directly via file path problem will not occur. Thus, at first it is necessary to run SVN server:</p>
<pre>svnserve.exe -d -r D:/parent/path/to/repository/</pre>
<p>And then you can access Subversion repository via its server:</p>
<pre>git.exe svn init -s "<strong>svn://localhost</strong>/relative/path/to/subversion/repository"</pre>


<p>No related posts.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.dbtracer.org/2010/01/20/porting-subversion-git-with-error/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Database Continuous Integration with DBTracer</title>
		<link>http://blog.dbtracer.org/2010/01/12/database-continuous-integration-with-dbtracer/</link>
		<comments>http://blog.dbtracer.org/2010/01/12/database-continuous-integration-with-dbtracer/#comments</comments>
		<pubDate>Mon, 11 Jan 2010 23:55:37 +0000</pubDate>
		<dc:creator>Petr Kozelek</dc:creator>
				<category><![CDATA[Database Continuous Integration]]></category>
		<category><![CDATA[continuous integration]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[DBTracer]]></category>

		<guid isPermaLink="false">http://petrkozelek.e-blog.cz/?p=77</guid>
		<description><![CDATA[In my company we use principles of continuous integration in our C#.Net+MS SQL development. We use Subversion for source control management and CruiseControl.Net as integration server. The problem came when we needed to choose a tool for continuous integration of database changes since we did not find any open-source alternative. The common repository for all [...]


Related posts:<ul><li><a href='http://blog.dbtracer.org/2010/08/30/audit-trail-tracing-data-changes-in-database/' rel='bookmark' title='Permanent Link: Audit Trail &#8211; Tracing Data Changes in Database'>Audit Trail &#8211; Tracing Data Changes in Database</a></li>
</ul>]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-121" title="DBTracker" src="http://petrkozelek.e-blog.cz/wp-content/uploads/dbt-logo1.png" alt="" width="104" height="55" /><br />
In my company we use principles of continuous integration in our C#.Net+MS SQL development. We use Subversion for source control management and CruiseControl.Net as integration server. The problem came when we needed to choose a tool for continuous integration of database changes since we did not find any open-source alternative.</p>
<p><span id="more-77"></span></p>
<p>The common repository for all source code changes is Subversion (currently we think of migrating to <a href="http://git-scm.com/">Git</a>, anyway). For tracking changes of database schema changes we use Subversion, too.</p>
<p>In our team each developer has his own database server installed on his PC and he is an administrator of his own database server. The core of everything is the SCM. Developers check out latest code from there, integration server uses it as well to get code base and integration tests. The idea connected with tracking changes of database schema was to include changes under version control. Then both developers and integration server were able to retrieve database schema changes and to handle them.</p>
<h2>Database Change Scripts</h2>
<p>If a developer wishes to do some changes in database schema, he can freely do that on his local database without fear to influence work of the others. As the result of his work he is expected to create a <em>database change script</em> that includes all schema changes needed to be implemented. Let&#8217;s say we need to add a column to the table. The change script will contain these SQL commands:</p>

<div class="wp_codebox"><table><tr id="p7712"><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code" id="p77code12"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">ALTER</span> <span style="color: #993333; font-weight: bold;">TABLE</span> <span style="color: #993333; font-weight: bold;">Order</span>
<span style="color: #993333; font-weight: bold;">ADD</span> <span style="color: #993333; font-weight: bold;">Status</span> int <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> <span style="color: #cc66cc;">0</span>
GO</pre></td></tr></table></div>

<p>The script will add a column &#8220;Status&#8221; to a table &#8220;Order&#8221;. You can feel it would be very annoying for a developer to change database schema only via change scripts in regular daily work. We established a helpful practice how to make things easier for the developer. The change script should be the result of his work that he wish to be integrated. We work as follows:</p>
<ol>
<li>When developer is going to do schema changes (on his local machine, of course), first he creates a clone of database version that was already fully integrated to source control. Let&#8217;s say that database is in version 1.5 so he creates a clone of it with help of <a href="http://dbtracer.org/">DBTracer</a>:
<pre>cmd&gt; dbt create /database=reference_db_v_1_5 /db-version=1.5 /connection=(local)</pre>
</li>
<li>At this point he has a reference database that will serve him as a reference point when he will compare it with his test database. The test database is created in the same way as reference one:
<pre>cmd&gt; dbt create /database=test /connection=(local) /db-version=1.5 /override-if-exists</pre>
</li>
<li>Now the developer is ready to do whatever he wants in the &#8220;test&#8221; database. For example he can add a column &#8220;Status&#8221; to a table &#8220;Order&#8221;. Of course you are not limited to add only one schema change to one change script.</li>
<li>When he is ready with schema changes he compares the test database with a reference database &#8220;reference_db_v_1_5&#8243;. Tools for comparing databases are very much helpful here. In my team we use <a href="http://sqlmanager.net/products/mssql/dbcomparer">EMS DB Comparer</a>.</li>
<li>The tool generates a change script. It is possible to modify it manually if we are not satisfied with the result. After that, the change script is ready to be checked in to version control.</li>
</ol>
<h3>Change Script Names</h3>
<p>We use the following convention for our change scripts:</p>
<pre>&lt;major_version&gt;.&lt;minor_version&gt;.&lt;revision&gt;-&lt;some description of change script&gt;.UP.sql</pre>
<p>For example:</p>
<pre>003.012.0541-add column Status to table Order.UP.sql</pre>
<p>In this example the change script lies within database major version=3, minor version=12 and its revision=541. There is also a short description &#8220;add column Status to table Order&#8221; defining what is inside the change script. Additionally, the keyword &#8220;UP&#8221; in the change script is reserved for future when we will need to distinguish between <em>upgrade change scripts </em>and <em>downgrade change scripts</em>.</p>
<p>Now the change script is ready to go to version control.</p>
<h2>Our Solution &#8211; DBTracer</h2>
<p>We searched for a simple tool that would maintain a our database migration scripts. Additionally, it should provide following features:</p>
<ul>
<li>command line interface</li>
<li>storing SQL database version in the database itself</li>
</ul>
<p>Unfortunately, no such tool existed that would have been acceptable. Hence, we inspired by <a href="http://wildbit.com/blog/2008/03/24/database-continuous-integration-in-net/">Alexander Kleshchevnikov</a> and wrote our own tool <a href="http://dbtracer.org/">DBTracer</a>. Currently it is in experimental phase for public. We use it internally in our team but still API changes are going on.</p>
<h2>Further Reading</h2>
<ul>
<li><a href="http://odetocode.com/Blogs/scott/archive/2008/01/31/three-rules-for-database-work.aspx">Three Rules for Database Work</a></li>
<li><a href="http://wildbit.com/blog/2008/03/24/database-continuous-integration-in-net/">Database Continuous Integration in .NET</a></li>
<li><a href="http://martinfowler.com/articles/evodb.html">Evolutionary Database Design</a></li>
</ul>


<p>Related posts:<ul><li><a href='http://blog.dbtracer.org/2010/08/30/audit-trail-tracing-data-changes-in-database/' rel='bookmark' title='Permanent Link: Audit Trail &#8211; Tracing Data Changes in Database'>Audit Trail &#8211; Tracing Data Changes in Database</a></li>
</ul></p>]]></content:encoded>
			<wfw:commentRss>http://blog.dbtracer.org/2010/01/12/database-continuous-integration-with-dbtracer/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
