<?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: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/" version="2.0">

<channel>
	<title>Jasny | Arnold's wor(l)ds</title>
	
	<link>http://www.jasny.net</link>
	<description>It's all about me, mysql and Einstein.</description>
	<lastBuildDate>Tue, 27 Jul 2010 12:31:32 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/Jasny" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="jasny" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>A secure backdoor for PHP</title>
		<link>http://www.jasny.net/articles/a-secure-backdoor-for-php/</link>
		<comments>http://www.jasny.net/articles/a-secure-backdoor-for-php/#comments</comments>
		<pubDate>Tue, 11 May 2010 14:48:23 +0000</pubDate>
		<dc:creator>Arnold Daniels</dc:creator>
				<category><![CDATA[Authentication]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.jasny.net/?p=415</guid>
		<description><![CDATA[A backdoor provides access to an application through a different method that the normal authentication process. There are many ways to do this. Some are more secure than others.]]></description>
			<content:encoded><![CDATA[<p>A <a href="http://en.wikipedia.org/wiki/Backdoor_%28computing%29" target="_blank">backdoor</a> provides access to an application bypassing the normal authentication process. There are many ways to do this. Some are more secure than others.</p>
<h3>Why do you need a backdoor?</h3>
<p>In a perfect word you could just deliver an application and all would be good. However in the real world there are unforeseen issues which need to be solved. This means that you as a developer will need access to the application. To reproduce the problem, you usually want to run the application logged in as the user that spotted the issue.</p>
<p>Another use of the backdoor is in a situation where you want to allow a user, that has already been authenticated, to bypassing further authentication. For example if you have a (web hosting) control panel where the user is already logged in, you can allow him to directly access the dashboard of the application without have to enter his password again. This requires a backdoor, since you don&#8217;t know his (unencrypted) password.<br />
<span id="more-415"></span></p>
<h3>A very simple solution</h3>
<p>The most simple solution is to use a backdoor password. This password will work for every user. A variation on this, is to have a superuser account, that is allowed to switch to any user on the system.</p>
<p>This solution is fine if you&#8217;re the only developer working on these applications. However in a professional environment this solution won&#8217;t do. With this method is easy to give somebody super privileges, but hard to take them away. This requires changing the backdoor password. Which is a tedious job if you&#8217;re managing any serious number of applications.</p>
<h3>The secure way</h3>
<p>It is easier if there is a project management system where you and other developers can log into. From within that system, the developer can directly login the customer application as any user. Within that application you can configure on which team each developer is. That limits to which applications the developer has access. More important, simply blocking the user account on the project management system will lock the developer out completely.</p>
<h3>Private and public keys</h3>
<p>The best known method for logging into a system, is the use of private/public (DSA) keys with SSH. The SSH client signs the request with the private key. The SSH server has the public key in the authorized_key file. It verifies the credentials using the public keys and grands access on success.</p>
<p>We can use the same method with PHP using the <a href="http://php.net/openssl" title="OpenSSL in PHP manual" target="_blank">OpenSLL</a> extension. We&#8217;ll let the client (project management system) sign the username and system name (URL) using openssl_sign. This signature is verified on the server (customer application) using openssl_verify. To unsure the login URL can&#8217;t be reused later, we&#8217;ll throw in a 5 second timeout.</p>
<h3>Generating the keys</h3>
<p>The keys can be generated on the (*nix) command line, using the &#8216;openssl&#8217; binary. I&#8217;m using RSA keys, but DSA should also work if preferred.</p>
<pre>
# Generate private key
openssl genrsa -out master.key 1024
# Generate public key
openssl rsa -in master.key -pubout -out master.pub
</pre>
<p>The public key should be copied to the &#8216;pubkeys&#8217; directory of the server application. Make sure the private key is absolutely private. Anybody who has a copy of that, can use the backdoor.</p>
<h3>Download</h3>
<p><i>Don&#8217;t use the downloaded code without replacing the private and public key!</i><br />
<a href="http://github.com/jasny/backdoor/archives/master" target="_blank">Download the code @ github</a><br />
<a href="http://www.jasny.net/code/backdoor/client/" target="_blank">A (not to impressive) demo</a></p>
<p>If I overlooked security issues with this implementation, please leave a comment below.</p>


<!-- Begin SexyBookmarks Menu Code -->
<div class="sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-sexy">
<ul class="socials">
		<li class="sexy-twitter">
			<a href="http://twitter.com/home?status=A+secure+backdoor+for+PHP+-+http://b2l.me/txbac+(via+@JasnyArnold)&amp;source=shareaholic" rel="nofollow" class="external" title="Tweet This!">Tweet This!</a>
		</li>
		<li class="sexy-dzone">
			<a href="http://www.dzone.com/links/add.html?url=http://www.jasny.net/articles/a-secure-backdoor-for-php/&amp;title=A+secure+backdoor+for+PHP&amp;description=POST_SUMMARY" rel="nofollow" class="external" title="Add this to DZone">Add this to DZone</a>
		</li>
		<li class="sexy-stumbleupon">
			<a href="http://www.stumbleupon.com/submit?url=http://www.jasny.net/articles/a-secure-backdoor-for-php/&amp;title=A+secure+backdoor+for+PHP" rel="nofollow" class="external" title="Stumble upon something good? Share it on StumbleUpon">Stumble upon something good? Share it on StumbleUpon</a>
		</li>
		<li class="sexy-reddit">
			<a href="http://reddit.com/submit?url=http://www.jasny.net/articles/a-secure-backdoor-for-php/&amp;title=A+secure+backdoor+for+PHP" rel="nofollow" class="external" title="Share this on Reddit">Share this on Reddit</a>
		</li>
		<li class="sexy-delicious">
			<a href="http://delicious.com/post?url=http://www.jasny.net/articles/a-secure-backdoor-for-php/&amp;title=A+secure+backdoor+for+PHP" rel="nofollow" class="external" title="Share this on del.icio.us">Share this on del.icio.us</a>
		</li>
		<li class="sexy-digg">
			<a href="http://digg.com/submit?phase=2&amp;url=http://www.jasny.net/articles/a-secure-backdoor-for-php/&amp;title=A+secure+backdoor+for+PHP" rel="nofollow" class="external" title="Digg this!">Digg this!</a>
		</li>
		<li class="sexy-technorati">
			<a href="http://technorati.com/faves?add=http://www.jasny.net/articles/a-secure-backdoor-for-php/" rel="nofollow" class="external" title="Share this on Technorati">Share this on Technorati</a>
		</li>
		<li class="sexy-googlebuzz">
			<a href="http://www.google.com/buzz/post?url=http://www.jasny.net/articles/a-secure-backdoor-for-php/&amp;imageurl=" rel="nofollow" class="external" title="Post on Google Buzz">Post on Google Buzz</a>
		</li>
		<li class="sexy-facebook">
			<a href="http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://www.jasny.net/articles/a-secure-backdoor-for-php/&amp;t=A+secure+backdoor+for+PHP" rel="nofollow" class="external" title="Share this on Facebook">Share this on Facebook</a>
		</li>
		<li class="sexy-linkedin">
			<a href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://www.jasny.net/articles/a-secure-backdoor-for-php/&amp;title=A+secure+backdoor+for+PHP&amp;summary=A%20backdoor%20provides%20access%20to%20an%20application%20bypassing%20the%20normal%20authentication%20process.%20There%20are%20many%20ways%20to%20do%20this.%20Some%20are%20more%20secure%20than%20others.%0D%0A%0D%0AWhy%20do%20you%20need%20a%20backdoor%3F%0D%0AIn%20a%20perfect%20word%20you%20could%20just%20deliver%20an%20application%20and%20all%20would%20be%20good.%20However%20in%20the%20real%20world%20there%20a&amp;source=Jasny | Arnold&#039;s wor(l)ds" rel="nofollow" class="external" title="Share this on LinkedIn">Share this on LinkedIn</a>
		</li>
		<li class="sexy-mail">
			<a href="mailto:?subject=%22A%20secure%20backdoor%20for%20PHP%22&amp;body=I+thought+this+article+might+interest+you.%0A%0A%22A%20backdoor%20provides%20access%20to%20an%20application%20bypassing%20the%20normal%20authentication%20process.%20There%20are%20many%20ways%20to%20do%20this.%20Some%20are%20more%20secure%20than%20others.%0D%0A%0D%0AWhy%20do%20you%20need%20a%20backdoor%3F%0D%0AIn%20a%20perfect%20word%20you%20could%20just%20deliver%20an%20application%20and%20all%20would%20be%20good.%20However%20in%20the%20real%20world%20there%20a%22%0A%0AYou+can+read+the+full+article+here%3A%20http://www.jasny.net/articles/a-secure-backdoor-for-php/" rel="nofollow" class="external" title="Email this to a friend?">Email this to a friend?</a>
		</li>
</ul>
<div style="clear:both;"></div>
</div>
<!-- End SexyBookmarks Menu Code -->

]]></content:encoded>
			<wfw:commentRss>http://www.jasny.net/articles/a-secure-backdoor-for-php/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Versioning MySQL data: Multi-table records</title>
		<link>http://www.jasny.net/articles/versioning-mysql-data-multi-table-records/</link>
		<comments>http://www.jasny.net/articles/versioning-mysql-data-multi-table-records/#comments</comments>
		<pubDate>Thu, 26 Nov 2009 01:41:45 +0000</pubDate>
		<dc:creator>Arnold Daniels</dc:creator>
				<category><![CDATA[MySQL, Sphinx and NoSQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.adaniels.nl/?p=342</guid>
		<description><![CDATA[In the article &#8216;Versioning MySQL data&#8216;, I showed the basics of implementing a revisioning system using trigger. As Jens Schauder already pointed out, often the data of a record is spread across multiple tables, like an invoice with multiple invoice lines. Having each invoice line versioned individually isn&#8217;t really useful. Instead we want a new [...]]]></description>
			<content:encoded><![CDATA[<p>In the article &#8216;<a href="http://www.adaniels.nl/articles/versioning-mysql-data/">Versioning MySQL data</a>&#8216;, I showed the basics of implementing a revisioning system using trigger. As Jens Schauder already pointed out, often the data of a record is spread across multiple tables, like an invoice with multiple invoice lines. Having each invoice line versioned individually isn&#8217;t really useful. Instead we want a new revision of the whole invoice on each change.</p>
<p><strong>The perfect solution</strong><br />
Ideally a change of one or more parts of the invoice would be changed, a new revision would be created. There are several issues in actually creating this those. Detecting the change of multiple parts of the invoice at once, generating a single revision, would mean we need to know if the actions are done within the same transaction. Unfortunately there is a connection_id(), but no transaction_id() function in MySQL. Also, the <a href="http://dev.mysql.com/doc/refman/5.1/en/error-messages-server.html#error_er_cant_update_used_table_in_sf_or_trg" target="_blank">query would fail</a> when a query inserts or updates a record in the child table, using the parent table. We need to come up with something else.</p>
<p>In the implementation we currently have in production, we version the rows in the parent as well in the child tables. For each version of the parent row, we register which versions of the child rows ware set. This however has really complicated the trigger code and tends to need a lot of checking an querying slowing the write process down. Since nobody ever looks at the versions of the child rows, the application forces a new version of the parent row. The benefits of versioning both are therefor minimal.</p>
<p><strong>Only versioning the parent</strong><br />
For this new (simplified) implementation, we will only have one revision number across all tables of the record. Changing data from the parent table, will trigger a new version. This will not only copy the parent row to the revisioning table, but also the rows of the children.</p>
<p>Writing to the child will not trigger a new version, instead it will update the data in the revisioning table. This means that when changing the record, you need to write to the parent table, before writing to the child tables. To force a new version without changing values use</p>

<div class="wp_syntax"><div class="code"><pre class="sql"><span style="color: #993333; font-weight: bold;">UPDATE</span> mytable <span style="color: #993333; font-weight: bold;">SET</span> _revision=<span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">WHERE</span> id=$id</pre></div></div>

<p><span id="more-342"></span></p>
<p>The parent and child tables are defined as</p>

<div class="wp_syntax"><div class="code"><pre class="sql"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> <span style="color: #ff0000;">`mytable`</span> <span style="color: #66cc66;">&#40;</span>
  <span style="color: #ff0000;">`id`</span> int<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">10</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <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;">AUTO_INCREMENT</span>,
  <span style="color: #ff0000;">`name`</span> varchar<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">255</span><span style="color: #66cc66;">&#41;</span> <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: #ff0000;">''</span>,
  <span style="color: #ff0000;">`description`</span> text,
  <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`id`</span><span style="color: #66cc66;">&#41;</span>,
  <span style="color: #993333; font-weight: bold;">UNIQUE</span> <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #ff0000;">`name`</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`name`</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span> ENGINE=InnoDB
&nbsp;
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> <span style="color: #ff0000;">`mychild`</span> <span style="color: #66cc66;">&#40;</span>
  <span style="color: #ff0000;">`id`</span> int<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">10</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <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;">AUTO_INCREMENT</span>,
  <span style="color: #ff0000;">`mytable_id`</span> int<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">10</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <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: #ff0000;">'0'</span>,
  <span style="color: #ff0000;">`title`</span> varchar<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">255</span><span style="color: #66cc66;">&#41;</span> <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: #ff0000;">''</span>,
  <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`id`</span><span style="color: #66cc66;">&#41;</span>,
  <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #ff0000;">`mytable_id`</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`mytable_id`</span><span style="color: #66cc66;">&#41;</span>,
  CONSTRAINT <span style="color: #ff0000;">`mychild_ibfk_1`</span> <span style="color: #993333; font-weight: bold;">FOREIGN</span> <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`mytable_id`</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">REFERENCES</span> <span style="color: #ff0000;">`mytable`</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`id`</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #993333; font-weight: bold;">DELETE</span> CASCADE
<span style="color: #66cc66;">&#41;</span> ENGINE=InnoDB</pre></div></div>

<p>Note that we are using InnoDB tables here. MyISAM doesn&#8217;t have foreign key constraints, therefor it&#8217;s not possible to define a parent-child relationship.</p>
<p><strong>Insert, update and delete</strong><br />
In the parent trigger, to different things happen concerning the child rows. When a new version is created, the data of `mychild` is copied to the revisioning table. On a revision switch, data will be copied from the revisioning table into `mychild`. The &#8220;`_revision_action` IS NULL&#8221; condition, means that `_revision_mytable` is only updated when a new revision is created.</p>

<div class="wp_syntax"><div class="code"><pre class="sql"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TRIGGER</span> <span style="color: #ff0000;">`mytable-afterupdate`</span> AFTER <span style="color: #993333; font-weight: bold;">UPDATE</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #ff0000;">`mytable`</span>
  <span style="color: #993333; font-weight: bold;">FOR</span> EACH ROW BEGIN
    DECLARE <span style="color: #ff0000;">`newrev`</span> <span style="color: #993333; font-weight: bold;">BOOLEAN</span>;
&nbsp;
    <span style="color: #993333; font-weight: bold;">UPDATE</span> <span style="color: #ff0000;">`_revision_mytable`</span> <span style="color: #993333; font-weight: bold;">SET</span> <span style="color: #ff0000;">`id`</span> = NEW.<span style="color: #ff0000;">`id`</span>, <span style="color: #ff0000;">`name`</span> = NEW.<span style="color: #ff0000;">`name`</span>, <span style="color: #ff0000;">`description`</span> = NEW.<span style="color: #ff0000;">`description`</span>, <span style="color: #ff0000;">`_revision_action`</span>=<span style="color: #ff0000;">'update'</span> <span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #ff0000;">`_revision`</span>=NEW.<span style="color: #ff0000;">`_revision`</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #ff0000;">`_revision_action`</span> <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NULL</span>;
    <span style="color: #993333; font-weight: bold;">SET</span> newrev = <span style="color: #66cc66;">&#40;</span>ROW_COUNT<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> &gt; <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">&#41;</span>;
    <span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> <span style="color: #ff0000;">`_revhistory_mytable`</span> <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span>NEW.<span style="color: #ff0000;">`id`</span>, NEW.<span style="color: #ff0000;">`_revision`</span>, @auth_uid, NOW<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
    <span style="color: #993333; font-weight: bold;">IF</span> newrev THEN
       <span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> <span style="color: #ff0000;">`_revision_mychild`</span> <span style="color: #993333; font-weight: bold;">SELECT</span> *, NEW.<span style="color: #ff0000;">`_revision`</span> <span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`mychild`</span> <span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #ff0000;">`mytable_id`</span> = NEW.<span style="color: #ff0000;">`id`</span>;
    ELSE
       <span style="color: #993333; font-weight: bold;">DELETE</span> <span style="color: #ff0000;">`t`</span>.* <span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`mychild`</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`t`</span> <span style="color: #993333; font-weight: bold;">LEFT</span> <span style="color: #993333; font-weight: bold;">JOIN</span> <span style="color: #ff0000;">`_revision_mychild`</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`r`</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #cc66cc;">0</span>=<span style="color: #cc66cc;">1</span> <span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #ff0000;">`t`</span>.<span style="color: #ff0000;">`mytable_id`</span> = NEW.<span style="color: #ff0000;">`id`</span>;
       <span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> <span style="color: #ff0000;">`mychild`</span> <span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #ff0000;">`id`</span>, <span style="color: #ff0000;">`mytable_id`</span>, <span style="color: #ff0000;">`title`</span> <span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`_revision_mychild`</span> <span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #ff0000;">`_revision`</span> = NEW.<span style="color: #ff0000;">`_revision`</span>;
    END <span style="color: #993333; font-weight: bold;">IF</span>;
  END
&nbsp;
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TRIGGER</span> <span style="color: #ff0000;">`mychild-afterinsert`</span> AFTER <span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #ff0000;">`mychild`</span>
  <span style="color: #993333; font-weight: bold;">FOR</span> EACH ROW BEGIN
    DECLARE CONTINUE HANDLER <span style="color: #993333; font-weight: bold;">FOR</span> <span style="color: #cc66cc;">1442</span> BEGIN END;
    <span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">IGNORE</span> <span style="color: #993333; font-weight: bold;">INTO</span> <span style="color: #ff0000;">`_revision_mychild`</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`id`</span>, <span style="color: #ff0000;">`mytable_id`</span>, <span style="color: #ff0000;">`title`</span>, <span style="color: #ff0000;">`_revision`</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">SELECT</span> NEW.<span style="color: #ff0000;">`id`</span>, NEW.<span style="color: #ff0000;">`mytable_id`</span>, NEW.<span style="color: #ff0000;">`title`</span>, <span style="color: #ff0000;">`_revision`</span> <span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`mytable`</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`p`</span> <span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #ff0000;">`p`</span>.<span style="color: #ff0000;">`id`</span>=NEW.<span style="color: #ff0000;">`mytable_id`</span>;
  END
&nbsp;
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TRIGGER</span> <span style="color: #ff0000;">`mychild-afterupdate`</span> AFTER <span style="color: #993333; font-weight: bold;">UPDATE</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #ff0000;">`mychild`</span>
  <span style="color: #993333; font-weight: bold;">FOR</span> EACH ROW BEGIN
    <span style="color: #993333; font-weight: bold;">REPLACE</span> <span style="color: #993333; font-weight: bold;">INTO</span> <span style="color: #ff0000;">`_revision_mychild`</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`id`</span>, <span style="color: #ff0000;">`mytable_id`</span>, <span style="color: #ff0000;">`title`</span>, <span style="color: #ff0000;">`_revision`</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">SELECT</span> NEW.<span style="color: #ff0000;">`id`</span>, NEW.<span style="color: #ff0000;">`mytable_id`</span>, NEW.<span style="color: #ff0000;">`title`</span>, <span style="color: #ff0000;">`_revision`</span> <span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`mytable`</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`p`</span> <span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #ff0000;">`p`</span>.<span style="color: #ff0000;">`id`</span>=NEW.<span style="color: #ff0000;">`mytable_id`</span>;
  END
&nbsp;
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TRIGGER</span> <span style="color: #ff0000;">`mychild-afterdelete`</span> AFTER <span style="color: #993333; font-weight: bold;">DELETE</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #ff0000;">`mychild`</span>
  <span style="color: #993333; font-weight: bold;">FOR</span> EACH ROW BEGIN
    DECLARE CONTINUE HANDLER <span style="color: #993333; font-weight: bold;">FOR</span> <span style="color: #cc66cc;">1442</span> BEGIN END;
    <span style="color: #993333; font-weight: bold;">DELETE</span> <span style="color: #ff0000;">`r`</span>.* <span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`_revision_mychild`</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`r`</span> <span style="color: #993333; font-weight: bold;">INNER</span> <span style="color: #993333; font-weight: bold;">JOIN</span> <span style="color: #ff0000;">`mytable`</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`p`</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #ff0000;">`r`</span>.<span style="color: #ff0000;">`_revision`</span> = <span style="color: #ff0000;">`p`</span>.<span style="color: #ff0000;">`_revision`</span> <span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #ff0000;">`r`</span>.<span style="color: #ff0000;">`id`</span> = OLD.<span style="color: #ff0000;">`id`</span>;
  END</pre></div></div>

<p>Changing data in table `mychild` simply updates the data in the revisioning table. The revision number is grabbed from the field in the parent table.</p>
<p>Switching the revision can only be done through the parent table. This will also automatically change the data in the child tables. We simply delete all rows of the record and replace them with data from the revisioning table. This would however trigger the deletion of the data in `_revision_child` on which the insert has nothing to do. To prevent this, we can abuse that fact that a trigger can&#8217;t update data of a table using in the insert/update/delete query. This causes <a href="http://dev.mysql.com/doc/refman/5.1/en/error-messages-server.html#error_er_cant_update_used_table_in_sf_or_trg">error 1442</a>. With a continue handler we can ignore this silently.</p>
<p>The InnoDB constraints will handle the cascading delete. Deleting child data <a href="http://dev.mysql.com/doc/refman/5.4/en/innodb-foreign-key-constraints.html" target="_blank">won&#8217;t activate the deletion trigger</a>, which is all the better in this case.</p>
<p><strong>Without a primary key</strong><br />
A primary key is not required for the child table, since versioning is done purely based on the id of `mytable`.</p>

<div class="wp_syntax"><div class="code"><pre class="sql"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> <span style="color: #ff0000;">`mypart`</span> <span style="color: #66cc66;">&#40;</span>
  <span style="color: #ff0000;">`mytable_id`</span> int<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">10</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span>,
  <span style="color: #ff0000;">`reference`</span> varchar<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">255</span><span style="color: #66cc66;">&#41;</span> <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;">KEY</span> <span style="color: #ff0000;">`mytable_id`</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`mytable_id`</span><span style="color: #66cc66;">&#41;</span>,
  CONSTRAINT <span style="color: #ff0000;">`mypart_ibfk_1`</span> <span style="color: #993333; font-weight: bold;">FOREIGN</span> <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`mytable_id`</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">REFERENCES</span> <span style="color: #ff0000;">`mytable`</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`id`</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #993333; font-weight: bold;">DELETE</span> CASCADE
<span style="color: #66cc66;">&#41;</span> ENGINE=InnoDB</pre></div></div>

<p>This does cause an issue for the update and delete triggers of the child table. It can&#8217;t use the primary to id to locate the current version of the modified/removed row. This can be solved by a trick I got from PhpMyAdmin. We can simply locate the record by comparing the old values of all fields. There is no constraint for the table enforcing the uniqueness of a row, so we could be targeting multiple identical rows. Since they are identical, it doesn&#8217;t matter which one we target, as long as we limit to 1 row.</p>

<div class="wp_syntax"><div class="code"><pre class="sql"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TRIGGER</span> <span style="color: #ff0000;">`mypart-afterupdate`</span> AFTER <span style="color: #993333; font-weight: bold;">UPDATE</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #ff0000;">`mypart`</span>
  <span style="color: #993333; font-weight: bold;">FOR</span> EACH ROW BEGIN
    <span style="color: #993333; font-weight: bold;">DELETE</span> <span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`_revision_mypart`</span> <span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #ff0000;">`_revision`</span> <span style="color: #993333; font-weight: bold;">IN</span> <span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #ff0000;">`_revision`</span> <span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`mytable`</span> <span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #ff0000;">`id`</span> = OLD.<span style="color: #ff0000;">`mytable_id`</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #ff0000;">`mytable_id`</span> = OLD.<span style="color: #ff0000;">`mytable_id`</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #ff0000;">`reference`</span> = OLD.<span style="color: #ff0000;">`reference`</span> <span style="color: #993333; font-weight: bold;">LIMIT</span> <span style="color: #cc66cc;">1</span>;
    <span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> <span style="color: #ff0000;">`_revision_mypart`</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`mytable_id`</span>, <span style="color: #ff0000;">`reference`</span>, <span style="color: #ff0000;">`_revision`</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">SELECT</span> NEW.<span style="color: #ff0000;">`mytable_id`</span>, NEW.<span style="color: #ff0000;">`reference`</span>, <span style="color: #ff0000;">`_revision`</span> <span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`mytable`</span> <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`p`</span> <span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #ff0000;">`p`</span>.<span style="color: #ff0000;">`id`</span>=NEW.<span style="color: #ff0000;">`mytable_id`</span>;
  END
&nbsp;
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TRIGGER</span> <span style="color: #ff0000;">`mypart-afterdelete`</span> AFTER <span style="color: #993333; font-weight: bold;">DELETE</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #ff0000;">`mypart`</span>
  <span style="color: #993333; font-weight: bold;">FOR</span> EACH ROW BEGIN
    DECLARE CONTINUE HANDLER <span style="color: #993333; font-weight: bold;">FOR</span> <span style="color: #cc66cc;">1442</span> BEGIN END;
    <span style="color: #993333; font-weight: bold;">DELETE</span> <span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`_revision_mypart`</span> <span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #ff0000;">`_revision`</span> <span style="color: #993333; font-weight: bold;">IN</span> <span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #ff0000;">`_revision`</span> <span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`mytable`</span> <span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #ff0000;">`id`</span> = OLD.<span style="color: #ff0000;">`mytable_id`</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #ff0000;">`mytable_id`</span> = OLD.<span style="color: #ff0000;">`mytable_id`</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #ff0000;">`reference`</span> = OLD.<span style="color: #ff0000;">`reference`</span> <span style="color: #993333; font-weight: bold;">LIMIT</span> <span style="color: #cc66cc;">1</span>;
  END</pre></div></div>

<p><strong>Unique keys</strong><br />
The revisioning table has multiple versions of a record. Unique indexes from the original table should be converted to non-unique indexes in the revisioning table. This information can be fetched using INFORMATION_SCHEMA.</p>

<div class="wp_syntax"><div class="code"><pre class="sql"><span style="color: #993333; font-weight: bold;">SELECT</span> c.CONSTRAINT_NAME, GROUP_CONCAT<span style="color: #66cc66;">&#40;</span>CONCAT<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'`'</span>, k.COLUMN_NAME, <span style="color: #ff0000;">'`'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> cols <span style="color: #993333; font-weight: bold;">FROM</span> INFORMATION_SCHEMA.TABLE_CONSTRAINTS <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`c`</span> <span style="color: #993333; font-weight: bold;">INNER</span> <span style="color: #993333; font-weight: bold;">JOIN</span> INFORMATION_SCHEMA.KEY_COLUMN_USAGE <span style="color: #993333; font-weight: bold;">AS</span> <span style="color: #ff0000;">`k`</span> <span style="color: #993333; font-weight: bold;">ON</span> c.TABLE_SCHEMA=k.TABLE_SCHEMA <span style="color: #993333; font-weight: bold;">AND</span> c.TABLE_NAME=k.TABLE_NAME <span style="color: #993333; font-weight: bold;">AND</span> c.CONSTRAINT_NAME=k.CONSTRAINT_NAME <span style="color: #993333; font-weight: bold;">WHERE</span> c.TABLE_SCHEMA=<span style="color: #993333; font-weight: bold;">DATABASE</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AND</span> c.TABLE_NAME=<span style="color: #ff0000;">'mytable'</span> <span style="color: #993333; font-weight: bold;">AND</span> c.CONSTRAINT_TYPE=<span style="color: #ff0000;">'UNIQUE'</span> <span style="color: #993333; font-weight: bold;">AND</span> c.CONSTRAINT_NAME != <span style="color: #ff0000;">'_revision'</span> <span style="color: #993333; font-weight: bold;">GROUP</span> <span style="color: #993333; font-weight: bold;">BY</span> c.CONSTRAINT_NAME</pre></div></div>

<p><strong>Revisioning and replication</strong><br />
Baron Schwartz pointed out a <a href="http://www.mysqlperformanceblog.com/2008/09/29/why-audit-logging-with-triggers-in-mysql-is-bad-for-replication/" target="_blank">race condition</a> when relying on auto-increment keys in triggers with replication. Actions carried out through triggers on a master are <a href="http://dev.mysql.com/doc/refman/5.0/en/faqs-triggers.html#qandaitem-22-5-1-12" target="_blank">not replicated to a slave server</a>. Instead, <a href="http://dev.mysql.com/doc/refman/5.0/en/faqs-triggers.html#qandaitem-22-5-1-10" target="_blank">triggers on the slave will be invoked</a>, which should do the same action as on the master.</p>
<p>It probably isn&#8217;t needed to have a copy of the revisioning tables on the slave. This would mean that we could simply omit the triggers. Unfortunately this causes problems when changing the revision. In that case we are forced to move switching of a revision out of the database. Instead the application needs to select the data from all revisioning tables and write that to the original tables. Any other thoughts on solving this issue are welcome.</p>
<p><strong id="download">Download</strong><br />
<a href='http://github.com/jasny/mysql-revisioning/archives/master'>&#8211;> Download mysql-revisioning script @github <--</a></p>


<!-- Begin SexyBookmarks Menu Code -->
<div class="sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-sexy">
<ul class="socials">
		<li class="sexy-twitter">
			<a href="http://twitter.com/home?status=Versioning+MySQL+data%3A+Multi-table+records+-+http://b2l.me/tr665+(via+@JasnyArnold)&amp;source=shareaholic" rel="nofollow" class="external" title="Tweet This!">Tweet This!</a>
		</li>
		<li class="sexy-dzone">
			<a href="http://www.dzone.com/links/add.html?url=http://www.jasny.net/articles/versioning-mysql-data-multi-table-records/&amp;title=Versioning+MySQL+data%3A+Multi-table+records&amp;description=POST_SUMMARY" rel="nofollow" class="external" title="Add this to DZone">Add this to DZone</a>
		</li>
		<li class="sexy-stumbleupon">
			<a href="http://www.stumbleupon.com/submit?url=http://www.jasny.net/articles/versioning-mysql-data-multi-table-records/&amp;title=Versioning+MySQL+data%3A+Multi-table+records" rel="nofollow" class="external" title="Stumble upon something good? Share it on StumbleUpon">Stumble upon something good? Share it on StumbleUpon</a>
		</li>
		<li class="sexy-reddit">
			<a href="http://reddit.com/submit?url=http://www.jasny.net/articles/versioning-mysql-data-multi-table-records/&amp;title=Versioning+MySQL+data%3A+Multi-table+records" rel="nofollow" class="external" title="Share this on Reddit">Share this on Reddit</a>
		</li>
		<li class="sexy-delicious">
			<a href="http://delicious.com/post?url=http://www.jasny.net/articles/versioning-mysql-data-multi-table-records/&amp;title=Versioning+MySQL+data%3A+Multi-table+records" rel="nofollow" class="external" title="Share this on del.icio.us">Share this on del.icio.us</a>
		</li>
		<li class="sexy-digg">
			<a href="http://digg.com/submit?phase=2&amp;url=http://www.jasny.net/articles/versioning-mysql-data-multi-table-records/&amp;title=Versioning+MySQL+data%3A+Multi-table+records" rel="nofollow" class="external" title="Digg this!">Digg this!</a>
		</li>
		<li class="sexy-technorati">
			<a href="http://technorati.com/faves?add=http://www.jasny.net/articles/versioning-mysql-data-multi-table-records/" rel="nofollow" class="external" title="Share this on Technorati">Share this on Technorati</a>
		</li>
		<li class="sexy-googlebuzz">
			<a href="http://www.google.com/buzz/post?url=http://www.jasny.net/articles/versioning-mysql-data-multi-table-records/&amp;imageurl=" rel="nofollow" class="external" title="Post on Google Buzz">Post on Google Buzz</a>
		</li>
		<li class="sexy-facebook">
			<a href="http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://www.jasny.net/articles/versioning-mysql-data-multi-table-records/&amp;t=Versioning+MySQL+data%3A+Multi-table+records" rel="nofollow" class="external" title="Share this on Facebook">Share this on Facebook</a>
		</li>
		<li class="sexy-linkedin">
			<a href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://www.jasny.net/articles/versioning-mysql-data-multi-table-records/&amp;title=Versioning+MySQL+data%3A+Multi-table+records&amp;summary=In%20the%20article%20%27Versioning%20MySQL%20data%27%2C%20I%20showed%20the%20basics%20of%20implementing%20a%20revisioning%20system%20using%20trigger.%20As%20Jens%20Schauder%20already%20pointed%20out%2C%20often%20the%20data%20of%20a%20record%20is%20spread%20across%20multiple%20tables%2C%20like%20an%20invoice%20with%20multiple%20invoice%20lines.%20Having%20each%20invoice%20line%20versioned%20individua&amp;source=Jasny | Arnold&#039;s wor(l)ds" rel="nofollow" class="external" title="Share this on LinkedIn">Share this on LinkedIn</a>
		</li>
		<li class="sexy-mail">
			<a href="mailto:?subject=%22Versioning%20MySQL%20data%3A%20Multi-table%20records%22&amp;body=I+thought+this+article+might+interest+you.%0A%0A%22In%20the%20article%20%27Versioning%20MySQL%20data%27%2C%20I%20showed%20the%20basics%20of%20implementing%20a%20revisioning%20system%20using%20trigger.%20As%20Jens%20Schauder%20already%20pointed%20out%2C%20often%20the%20data%20of%20a%20record%20is%20spread%20across%20multiple%20tables%2C%20like%20an%20invoice%20with%20multiple%20invoice%20lines.%20Having%20each%20invoice%20line%20versioned%20individua%22%0A%0AYou+can+read+the+full+article+here%3A%20http://www.jasny.net/articles/versioning-mysql-data-multi-table-records/" rel="nofollow" class="external" title="Email this to a friend?">Email this to a friend?</a>
		</li>
</ul>
<div style="clear:both;"></div>
</div>
<!-- End SexyBookmarks Menu Code -->

]]></content:encoded>
			<wfw:commentRss>http://www.jasny.net/articles/versioning-mysql-data-multi-table-records/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Follow me on twitter</title>
		<link>http://www.jasny.net/articles/follow-me-on-twitter/</link>
		<comments>http://www.jasny.net/articles/follow-me-on-twitter/#comments</comments>
		<pubDate>Fri, 13 Nov 2009 12:08:29 +0000</pubDate>
		<dc:creator>Arnold Daniels</dc:creator>
				<category><![CDATA[Einstein]]></category>

		<guid isPermaLink="false">http://www.adaniels.nl/articles/follow-me-on-twitter/</guid>
		<description><![CDATA[I&#8217;m giving microblogging another try. Follow my post on twitter @adaniels_nl.





		
			Tweet This!
		
		
			Add this to DZone
		
		
			Stumble upon something good? Share it on StumbleUpon
		
		
			Share this on Reddit
		
		
			Share this on del.icio.us
		
		
			Digg this!
		
		
			Share this on Technorati
		
		
			Post on Google Buzz
		
		
			Share this on Facebook
		
		
			Share this on LinkedIn
		
		
			Email this to a friend?
		





]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m giving microblogging another try. Follow my post on twitter @<a href="http://twitter.com/adaniels_nl">adaniels_nl</a>.</p>


<!-- Begin SexyBookmarks Menu Code -->
<div class="sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-sexy">
<ul class="socials">
		<li class="sexy-twitter">
			<a href="http://twitter.com/home?status=Follow+me+on+twitter+-+http://b2l.me/tr67a+(via+@JasnyArnold)&amp;source=shareaholic" rel="nofollow" class="external" title="Tweet This!">Tweet This!</a>
		</li>
		<li class="sexy-dzone">
			<a href="http://www.dzone.com/links/add.html?url=http://www.jasny.net/articles/follow-me-on-twitter/&amp;title=Follow+me+on+twitter&amp;description=POST_SUMMARY" rel="nofollow" class="external" title="Add this to DZone">Add this to DZone</a>
		</li>
		<li class="sexy-stumbleupon">
			<a href="http://www.stumbleupon.com/submit?url=http://www.jasny.net/articles/follow-me-on-twitter/&amp;title=Follow+me+on+twitter" rel="nofollow" class="external" title="Stumble upon something good? Share it on StumbleUpon">Stumble upon something good? Share it on StumbleUpon</a>
		</li>
		<li class="sexy-reddit">
			<a href="http://reddit.com/submit?url=http://www.jasny.net/articles/follow-me-on-twitter/&amp;title=Follow+me+on+twitter" rel="nofollow" class="external" title="Share this on Reddit">Share this on Reddit</a>
		</li>
		<li class="sexy-delicious">
			<a href="http://delicious.com/post?url=http://www.jasny.net/articles/follow-me-on-twitter/&amp;title=Follow+me+on+twitter" rel="nofollow" class="external" title="Share this on del.icio.us">Share this on del.icio.us</a>
		</li>
		<li class="sexy-digg">
			<a href="http://digg.com/submit?phase=2&amp;url=http://www.jasny.net/articles/follow-me-on-twitter/&amp;title=Follow+me+on+twitter" rel="nofollow" class="external" title="Digg this!">Digg this!</a>
		</li>
		<li class="sexy-technorati">
			<a href="http://technorati.com/faves?add=http://www.jasny.net/articles/follow-me-on-twitter/" rel="nofollow" class="external" title="Share this on Technorati">Share this on Technorati</a>
		</li>
		<li class="sexy-googlebuzz">
			<a href="http://www.google.com/buzz/post?url=http://www.jasny.net/articles/follow-me-on-twitter/&amp;imageurl=" rel="nofollow" class="external" title="Post on Google Buzz">Post on Google Buzz</a>
		</li>
		<li class="sexy-facebook">
			<a href="http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://www.jasny.net/articles/follow-me-on-twitter/&amp;t=Follow+me+on+twitter" rel="nofollow" class="external" title="Share this on Facebook">Share this on Facebook</a>
		</li>
		<li class="sexy-linkedin">
			<a href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://www.jasny.net/articles/follow-me-on-twitter/&amp;title=Follow+me+on+twitter&amp;summary=I%27m%20giving%20microblogging%20another%20try.%20Follow%20my%20post%20on%20twitter%20%40adaniels_nl.&amp;source=Jasny | Arnold&#039;s wor(l)ds" rel="nofollow" class="external" title="Share this on LinkedIn">Share this on LinkedIn</a>
		</li>
		<li class="sexy-mail">
			<a href="mailto:?subject=%22Follow%20me%20on%20twitter%22&amp;body=I+thought+this+article+might+interest+you.%0A%0A%22I%27m%20giving%20microblogging%20another%20try.%20Follow%20my%20post%20on%20twitter%20%40adaniels_nl.%22%0A%0AYou+can+read+the+full+article+here%3A%20http://www.jasny.net/articles/follow-me-on-twitter/" rel="nofollow" class="external" title="Email this to a friend?">Email this to a friend?</a>
		</li>
</ul>
<div style="clear:both;"></div>
</div>
<!-- End SexyBookmarks Menu Code -->

]]></content:encoded>
			<wfw:commentRss>http://www.jasny.net/articles/follow-me-on-twitter/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Versioning MySQL data</title>
		<link>http://www.jasny.net/articles/versioning-mysql-data/</link>
		<comments>http://www.jasny.net/articles/versioning-mysql-data/#comments</comments>
		<pubDate>Thu, 12 Nov 2009 16:36:18 +0000</pubDate>
		<dc:creator>Arnold Daniels</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[MySQL, Sphinx and NoSQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.adaniels.nl/?p=291</guid>
		<description><![CDATA[Advantages of a VCS above a nightly backup are that you can walk to the individual changes for a document, see who made each change and revert back to specific revision if needed. These are features which would also be nice for data stored in a database. This article shows how to use triggers to can implement versioning for data stored in a MySQL db.]]></description>
			<content:encoded><![CDATA[<p>As a developer you&#8217;re probably using a versioning control system, like subversion or git, to safeguard your data. Advantages of using a VCS are that you can walk to the individual changes for a document, see who made each change and revert back to specific revision if needed. These are features which would also be nice for data stored in a database. With the use of <a href="http://dev.mysql.com/doc/refman/5.0/en/triggers.html" target="_blank">triggers</a> we can implement versioning for data stored in a MySQL db.</p>
<p><strong>The revisioning table</strong><br />
We will not store the different versions of the records in the original table. We want this solution to be in the database layer instead of putting all the logic in the application layer. Instead we&#8217;ll create a new table, which stores all the different versions and lives next to the original table, which only contains the current version of each record. This revisioning table is copy of the original table, with a couple of additional fields.</p>

<div class="wp_syntax"><div class="code"><pre class="sql"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> <span style="color: #ff0000;">`_revision_mytable`</span> <span style="color: #993333; font-weight: bold;">LIKE</span> <span style="color: #ff0000;">`mytable`</span>;
&nbsp;
<span style="color: #993333; font-weight: bold;">ALTER</span> <span style="color: #993333; font-weight: bold;">TABLE</span> <span style="color: #ff0000;">`_revision_mytable`</span>
  <span style="color: #993333; font-weight: bold;">CHANGE</span> <span style="color: #ff0000;">`id`</span> <span style="color: #ff0000;">`id`</span> int<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">10</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">UNSIGNED</span>,
  <span style="color: #993333; font-weight: bold;">DROP</span> <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span>,
  <span style="color: #993333; font-weight: bold;">ADD</span> <span style="color: #ff0000;">`_revision`</span> bigint <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <span style="color: #993333; font-weight: bold;">AUTO_INCREMENT</span>,
  <span style="color: #993333; font-weight: bold;">ADD</span> <span style="color: #ff0000;">`_revision_previous`</span> bigint <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <span style="color: #993333; font-weight: bold;">NULL</span>,
  <span style="color: #993333; font-weight: bold;">ADD</span> <span style="color: #ff0000;">`_revision_action`</span> enum<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'INSERT'</span>,<span style="color: #ff0000;">'UPDATE'</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> <span style="color: #993333; font-weight: bold;">NULL</span>,
  <span style="color: #993333; font-weight: bold;">ADD</span> <span style="color: #ff0000;">`_revision_user_id`</span> int<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">10</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <span style="color: #993333; font-weight: bold;">NULL</span>,
  <span style="color: #993333; font-weight: bold;">ADD</span> <span style="color: #ff0000;">`_revision_timestamp`</span> datetime <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> <span style="color: #993333; font-weight: bold;">NULL</span>,
  <span style="color: #993333; font-weight: bold;">ADD</span> <span style="color: #ff0000;">`_revision_comment`</span> text <span style="color: #993333; font-weight: bold;">NULL</span>,
  <span style="color: #993333; font-weight: bold;">ADD</span> <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`_revision`</span><span style="color: #66cc66;">&#41;</span>,
  <span style="color: #993333; font-weight: bold;">ADD</span> <span style="color: #993333; font-weight: bold;">INDEX</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`_revision_previous`</span><span style="color: #66cc66;">&#41;</span>,
  <span style="color: #993333; font-weight: bold;">ADD</span> <span style="color: #993333; font-weight: bold;">INDEX</span> <span style="color: #ff0000;">`org_primary`</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`id`</span><span style="color: #66cc66;">&#41;</span>;</pre></div></div>

<p>The most important field is `_revision`. This field contains a unique identifier for a version of a record from the table. Since this is the unique identifier in the revisioning table, the original id field becomes a normal (indexed) field.<br />
<span id="more-291"></span></p>
<p>We&#8217;ll also store some additional information in the revisioning table. The `_revision_previous` field hold the revision nr of the version that was updated to create this revision. Field `_revision_action` holds the action that was executed to create this revision. This field has an extra function that will discussed later. The user id and timestamp are useful for blaming changes on someone. We can add some comment per revision.</p>
<p>The database user is probably always the same. Storing this in the user id field is not useful. Instead, we can set variable @auth_id after logging in and on connecting to the database to the session user.</p>
<p><strong>Altering the original table</strong><br />
The original table needs 2 additional fields: `_revision` and `_revision_comment`. The `_revision` field holds the current active version. The field can also be used to revert to a different revision. The value of `_revision_comment` set on an update or insert will end up in the revisioning table. The field in the original table will always be empty.</p>

<div class="wp_syntax"><div class="code"><pre class="sql"><span style="color: #993333; font-weight: bold;">ALTER</span> <span style="color: #993333; font-weight: bold;">TABLE</span> <span style="color: #ff0000;">`mytable`</span>
  <span style="color: #993333; font-weight: bold;">ADD</span> <span style="color: #ff0000;">`_revision`</span> bigint <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <span style="color: #993333; font-weight: bold;">NULL</span>,
  <span style="color: #993333; font-weight: bold;">ADD</span> <span style="color: #ff0000;">`_revision_comment`</span> text <span style="color: #993333; font-weight: bold;">NULL</span>,
  <span style="color: #993333; font-weight: bold;">ADD</span> <span style="color: #993333; font-weight: bold;">UNIQUE</span> <span style="color: #993333; font-weight: bold;">INDEX</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`_revision`</span><span style="color: #66cc66;">&#41;</span>;</pre></div></div>

<p><strong>The history table</strong><br />
Saving each version is not enough. Since we can revert back to older revisions and of course delete the record altogether, we want to store which version of the record was enabled at what time. The history table only needs to hold the revision number and a timestamp. We&#8217;ll add the primary key fields, so it&#8217;s easier to query. A user id field is included again to blame.</p>

<div class="wp_syntax"><div class="code"><pre class="sql"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> <span style="color: #ff0000;">`_revhistory_mytable`</span> <span style="color: #66cc66;">&#40;</span>
  <span style="color: #ff0000;">`id`</span> int<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">10</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">UNSIGNED</span>,
  <span style="color: #ff0000;">`_revision`</span> bigint <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <span style="color: #993333; font-weight: bold;">NULL</span>,
  <span style="color: #ff0000;">`_revhistory_user_id`</span> int<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">10</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <span style="color: #993333; font-weight: bold;">NULL</span>,
  <span style="color: #ff0000;">`_revhistory_timestamp`</span> timestamp <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> CURRENT_TIMESTAMP,
  <span style="color: #993333; font-weight: bold;">INDEX</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`id`</span><span style="color: #66cc66;">&#41;</span>,
  <span style="color: #993333; font-weight: bold;">INDEX</span> <span style="color: #66cc66;">&#40;</span>_revision<span style="color: #66cc66;">&#41;</span>,
  <span style="color: #993333; font-weight: bold;">INDEX</span> <span style="color: #66cc66;">&#40;</span>_revhistory_user_id<span style="color: #66cc66;">&#41;</span>,
  <span style="color: #993333; font-weight: bold;">INDEX</span> <span style="color: #66cc66;">&#40;</span>_revhistory_timestamp<span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span> ENGINE=InnoDB;</pre></div></div>

<p><strong>How to use</strong><br />
Inserting, updating and deleting data should work as normal, including the <a href="http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html" target="_blank">INSERT &#8230; ON DUPLICATE KEY UPDATE syntax</a>. When updating the _revision field shouldn&#8217;t be changed.</p>
<p>To switch to a different version, we would do something like</p>

<div class="wp_syntax"><div class="code"><pre class="sql"><span style="color: #993333; font-weight: bold;">UPDATE</span> mytable <span style="color: #993333; font-weight: bold;">SET</span> _revision=$rev <span style="color: #993333; font-weight: bold;">WHERE</span> id=$id;</pre></div></div>

<p>However if the record has been deleted, there will be no record in the original table, therefore the update won&#8217;t do anything. Instead we could insert a record, specifying the revision.</p>

<div class="wp_syntax"><div class="code"><pre class="sql"><span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> mytable <span style="color: #993333; font-weight: bold;">SET</span> _revision=$rev;</pre></div></div>

<p>We can combine these two into a statement that works either way.</p>

<div class="wp_syntax"><div class="code"><pre class="sql"><span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> mytable <span style="color: #993333; font-weight: bold;">SET</span> id=$id, _revision=$rev <span style="color: #993333; font-weight: bold;">ON</span> DUPLICATE <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #993333; font-weight: bold;">UPDATE</span> _revision=<span style="color: #993333; font-weight: bold;">VALUES</span><span style="color: #66cc66;">&#40;</span>_revision<span style="color: #66cc66;">&#41;</span>;</pre></div></div>

<p>The above query shows that there an additional constraint. The only thing that indicates that different versions is of the same record, is the primary key. Therefore value of the primary key can&#8217;t change on update. This might mean that some tables need to start using surrogate keys if they are not.</p>
<p><strong>On Insert</strong><br />
Let&#8217;s dive into the triggers. We&#8217;ll start with before insert. This trigger should get the values of a revision when the _revision field is set, or otherwise add a new row to the revision table.</p>

<div class="wp_syntax"><div class="code"><pre class="sql"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TRIGGER</span> <span style="color: #ff0000;">`mytable-beforeinsert`</span> BEFORE <span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #ff0000;">`mytable`</span>
  <span style="color: #993333; font-weight: bold;">FOR</span> EACH ROW BEGIN
    DECLARE <span style="color: #ff0000;">`var-id`</span> int<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">10</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">UNSIGNED</span>;
    DECLARE <span style="color: #ff0000;">`var-title`</span> varchar<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">45</span><span style="color: #66cc66;">&#41;</span>;
    DECLARE <span style="color: #ff0000;">`var-body`</span> text;
    DECLARE <span style="color: #ff0000;">`var-_revision`</span> BIGINT <span style="color: #993333; font-weight: bold;">UNSIGNED</span>;
    DECLARE revisionCursor CURSOR <span style="color: #993333; font-weight: bold;">FOR</span> <span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #ff0000;">`id`</span>, <span style="color: #ff0000;">`title`</span>, <span style="color: #ff0000;">`body`</span> <span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`_revision_mytable`</span> <span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #ff0000;">`_revision`</span>=<span style="color: #ff0000;">`var-_revision`</span> <span style="color: #993333; font-weight: bold;">LIMIT</span> <span style="color: #cc66cc;">1</span>;
&nbsp;
    <span style="color: #993333; font-weight: bold;">IF</span> NEW.<span style="color: #ff0000;">`_revision`</span> <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NULL</span> THEN
      <span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> <span style="color: #ff0000;">`_revision_mytable`</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`_revision_comment`</span>, <span style="color: #ff0000;">`_revision_user_id`</span>, <span style="color: #ff0000;">`_revision_timestamp`</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span>NEW.<span style="color: #ff0000;">`_revision_comment`</span>, @auth_uid, NOW<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
      <span style="color: #993333; font-weight: bold;">SET</span> NEW.<span style="color: #ff0000;">`_revision`</span> = LAST_INSERT_ID<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
    ELSE
      <span style="color: #993333; font-weight: bold;">SET</span> <span style="color: #ff0000;">`var-_revision`</span>=NEW.<span style="color: #ff0000;">`_revision`</span>;
      OPEN revisionCursor;
      FETCH revisionCursor <span style="color: #993333; font-weight: bold;">INTO</span> <span style="color: #ff0000;">`var-id`</span>, <span style="color: #ff0000;">`var-title`</span>, <span style="color: #ff0000;">`var-body`</span>;
      CLOSE revisionCursor;
&nbsp;
      <span style="color: #993333; font-weight: bold;">SET</span> NEW.<span style="color: #ff0000;">`id`</span> = <span style="color: #ff0000;">`var-id`</span>, NEW.<span style="color: #ff0000;">`title`</span> = <span style="color: #ff0000;">`var-title`</span>, NEW.<span style="color: #ff0000;">`body`</span> = <span style="color: #ff0000;">`var-body`</span>;
    END <span style="color: #993333; font-weight: bold;">IF</span>;
&nbsp;
    <span style="color: #993333; font-weight: bold;">SET</span> NEW.<span style="color: #ff0000;">`_revision_comment`</span> = <span style="color: #993333; font-weight: bold;">NULL</span>;
  END
&nbsp;
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TRIGGER</span> <span style="color: #ff0000;">`mytable-afterinsert`</span> AFTER <span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #ff0000;">`mytable`</span>
  <span style="color: #993333; font-weight: bold;">FOR</span> EACH ROW BEGIN
    <span style="color: #993333; font-weight: bold;">UPDATE</span> <span style="color: #ff0000;">`_revision_mytable`</span> <span style="color: #993333; font-weight: bold;">SET</span> <span style="color: #ff0000;">`id`</span> = NEW.<span style="color: #ff0000;">`id`</span>, <span style="color: #ff0000;">`title`</span> = NEW.<span style="color: #ff0000;">`title`</span>, <span style="color: #ff0000;">`body`</span> = NEW.<span style="color: #ff0000;">`body`</span>, <span style="color: #ff0000;">`_revision_action`</span>=<span style="color: #ff0000;">'INSERT'</span> <span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #ff0000;">`_revision`</span>=NEW.<span style="color: #ff0000;">`_revision`</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #ff0000;">`_revision_action`</span> <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NULL</span>;
    <span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> <span style="color: #ff0000;">`_revhistory_mytable`</span> <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span>NEW.<span style="color: #ff0000;">`id`</span>, NEW.<span style="color: #ff0000;">`_revision`</span>, @auth_uid, NOW<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
  END</pre></div></div>

<p>If the `_revision` field is NULL, we insert a new row into the revision table. This action is primarily to get a revision number. We set the comment, user id and timestamp. We won&#8217;t set the values, action and previous id yet. The insert might fail or be converted into an update action by insert on duplicate key update. If the insert action fails, we&#8217;ll have an unused row in the revisioning table. This is a problem, since the primary key has not been set, so it won&#8217;t show up anywhere. We can clean up these phantom records once in a while to keep the table clean.</p>
<p>When `_revision` is set, we use a cursor to get the values from the revision table. We can&#8217;t fetch to values directly into NEW, therefore we first fetch them into variables and than copy that into NEW.</p>
<p>After insert, we&#8217;ll update the revision, setting the values and the action. However, the insert might have been an undelete action. In that case `_revision_action` is already set and we don&#8217;t need to update the revision. We also add an entry in the history table.</p>
<p><strong>On Update</strong><br />
The before and after update trigger do more or less the same as the before and after insert trigger.</p>

<div class="wp_syntax"><div class="code"><pre class="sql"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TRIGGER</span> <span style="color: #ff0000;">`mytable-beforeupdate`</span> BEFORE <span style="color: #993333; font-weight: bold;">UPDATE</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #ff0000;">`mytable`</span>
  <span style="color: #993333; font-weight: bold;">FOR</span> EACH ROW BEGIN
    DECLARE <span style="color: #ff0000;">`var-id`</span> int<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">10</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">UNSIGNED</span>;
    DECLARE <span style="color: #ff0000;">`var-title`</span> varchar<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">45</span><span style="color: #66cc66;">&#41;</span>;
    DECLARE <span style="color: #ff0000;">`var-body`</span> text;
    DECLARE <span style="color: #ff0000;">`var-_revision`</span> BIGINT <span style="color: #993333; font-weight: bold;">UNSIGNED</span>;
    DECLARE <span style="color: #ff0000;">`var-_revision_action`</span> enum<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'INSERT'</span>,<span style="color: #ff0000;">'UPDATE'</span>,<span style="color: #ff0000;">'DELETE'</span><span style="color: #66cc66;">&#41;</span>;
    DECLARE revisionCursor CURSOR <span style="color: #993333; font-weight: bold;">FOR</span> <span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #ff0000;">`id`</span>, <span style="color: #ff0000;">`title`</span>, <span style="color: #ff0000;">`body`</span>, <span style="color: #ff0000;">`_revision_action`</span> <span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`_revision_mytable`</span> <span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #ff0000;">`_revision`</span>=<span style="color: #ff0000;">`var-_revision`</span> <span style="color: #993333; font-weight: bold;">LIMIT</span> <span style="color: #cc66cc;">1</span>;
&nbsp;
    <span style="color: #993333; font-weight: bold;">IF</span> NEW.<span style="color: #ff0000;">`_revision`</span> = OLD.<span style="color: #ff0000;">`_revision`</span> THEN
      <span style="color: #993333; font-weight: bold;">SET</span> NEW.<span style="color: #ff0000;">`_revision`</span> = <span style="color: #993333; font-weight: bold;">NULL</span>;
&nbsp;
    ELSEIF NEW.<span style="color: #ff0000;">`_revision`</span> <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> THEN 
      <span style="color: #993333; font-weight: bold;">SET</span> <span style="color: #ff0000;">`var-_revision`</span> = NEW.<span style="color: #ff0000;">`_revision`</span>;
&nbsp;
      OPEN revisionCursor;
      FETCH revisionCursor <span style="color: #993333; font-weight: bold;">INTO</span> <span style="color: #ff0000;">`var-id`</span>, <span style="color: #ff0000;">`var-title`</span>, <span style="color: #ff0000;">`var-body`</span>, <span style="color: #ff0000;">`var-_revision_action`</span>;
      CLOSE revisionCursor;
&nbsp;
      <span style="color: #993333; font-weight: bold;">IF</span> <span style="color: #ff0000;">`var-_revision_action`</span> <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> THEN
        <span style="color: #993333; font-weight: bold;">SET</span> NEW.<span style="color: #ff0000;">`id`</span> = <span style="color: #ff0000;">`var-id`</span>, NEW.<span style="color: #ff0000;">`title`</span> = <span style="color: #ff0000;">`var-title`</span>, NEW.<span style="color: #ff0000;">`body`</span> = <span style="color: #ff0000;">`var-body`</span>;
      END <span style="color: #993333; font-weight: bold;">IF</span>;
    END <span style="color: #993333; font-weight: bold;">IF</span>;
&nbsp;
    <span style="color: #993333; font-weight: bold;">IF</span> <span style="color: #66cc66;">&#40;</span>NEW.<span style="color: #ff0000;">`id`</span> != OLD.<span style="color: #ff0000;">`id`</span> <span style="color: #993333; font-weight: bold;">OR</span> NEW.<span style="color: #ff0000;">`id`</span> <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NULL</span> != OLD.<span style="color: #ff0000;">`id`</span> <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">&#41;</span> THEN
<span style="color: #808080; font-style: italic;">-- Workaround for missing SIGNAL command</span>
      DO <span style="color: #ff0000;">`Can't change the value of the primary key of table 'mytable' because of revisioning`</span>;
    END <span style="color: #993333; font-weight: bold;">IF</span>;
&nbsp;
    <span style="color: #993333; font-weight: bold;">IF</span> NEW.<span style="color: #ff0000;">`_revision`</span> <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NULL</span> THEN
      <span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> <span style="color: #ff0000;">`_revision_mytable`</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`_revision_previous`</span>, <span style="color: #ff0000;">`_revision_comment`</span>, <span style="color: #ff0000;">`_revision_user_id`</span>, <span style="color: #ff0000;">`_revision_timestamp`</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span>OLD.<span style="color: #ff0000;">`_revision`</span>, NEW.<span style="color: #ff0000;">`_revision_comment`</span>, @auth_uid, NOW<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
      <span style="color: #993333; font-weight: bold;">SET</span> NEW.<span style="color: #ff0000;">`_revision`</span> = LAST_INSERT_ID<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
    END <span style="color: #993333; font-weight: bold;">IF</span>;
&nbsp;
    <span style="color: #993333; font-weight: bold;">SET</span> NEW.<span style="color: #ff0000;">`_revision_comment`</span> = <span style="color: #993333; font-weight: bold;">NULL</span>;
  END
&nbsp;
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TRIGGER</span> <span style="color: #ff0000;">`mytable-afterupdate`</span> AFTER <span style="color: #993333; font-weight: bold;">UPDATE</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #ff0000;">`mytable`</span>
  <span style="color: #993333; font-weight: bold;">FOR</span> EACH ROW BEGIN
    <span style="color: #993333; font-weight: bold;">UPDATE</span> <span style="color: #ff0000;">`_revision_mytable`</span> <span style="color: #993333; font-weight: bold;">SET</span> <span style="color: #ff0000;">`id`</span> = NEW.<span style="color: #ff0000;">`id`</span>, <span style="color: #ff0000;">`title`</span> = NEW.<span style="color: #ff0000;">`title`</span>, <span style="color: #ff0000;">`body`</span> = NEW.<span style="color: #ff0000;">`body`</span>, <span style="color: #ff0000;">`_revision_action`</span>=<span style="color: #ff0000;">'UPDATE'</span> <span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #ff0000;">`_revision`</span>=NEW.<span style="color: #ff0000;">`_revision`</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #ff0000;">`_revision_action`</span> <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NULL</span>;
    <span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> <span style="color: #ff0000;">`_revhistory_mytable`</span> <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span>NEW.<span style="color: #ff0000;">`id`</span>, NEW.<span style="color: #ff0000;">`_revision`</span>, @auth_uid, NOW<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
  END</pre></div></div>

<p>If `_revision` is not set, it has the old value. In that case a new revision should be created. Setting `_revision` to NULL will have the same behaviour of not setting `_revision`. Next to the comment, user id and timestamp, we add also set the previous revision.</p>
<p>As said before, it&#8217;s very important that the value of primary key doesn&#8217;t change. We need to check this and trigger an error, if it would be changed.</p>
<p><strong>On Delete</strong><br />
Deleting won&#8217;t create a new revisiong. However we do want to log that the record has been deleted. Therefore we add an entry to the history table with `_revision` set to NULL.</p>

<div class="wp_syntax"><div class="code"><pre class="sql"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TRIGGER</span> <span style="color: #ff0000;">`mytable-afterdelete`</span> AFTER <span style="color: #993333; font-weight: bold;">DELETE</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #ff0000;">`mytable`</span>
  <span style="color: #993333; font-weight: bold;">FOR</span> EACH ROW BEGIN
    <span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> <span style="color: #ff0000;">`_revhistory_mytable`</span> <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span>OLD.<span style="color: #ff0000;">`id`</span>, <span style="color: #993333; font-weight: bold;">NULL</span>, @auth_uid, NOW<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
  END</pre></div></div>

<p><strong>To conclude</strong><br />
Using triggers we can implement the basic versioning functionality to MySQL. Since this is completely done the by database, it can be added to an existing application, without having to change to application code (or with very little changes). Using the history table, we can get the data of the database on any moment in time.</p>
<p>There are some situations where this solution as a bit to basic. A record might span across multiple table, like an invoice with invoice lines. In that case, we don&#8217;t want to revision each individual invoice line, but the invoice as a whole. I&#8217;ll come around in a follow up with a solution for this. I can tell up front that this solution is unfortunately not as clean as these basics.</p>
<p><strong>Continue reading</strong><br />
Please continue reading the follow up article &#8216;<a href="http://www.adaniels.nl/articles/versioning-mysql-data-multi-table-records/">Versioning MySQL data: Multi-table records</a>&#8216;. At the bottom of that article you&#8217;ll find <a href="http://www.adaniels.nl/articles/versioning-mysql-data-multi-table-records/#download">a download link</a> for a script that adds revisioning to existing MySQL tables.</p>


<!-- Begin SexyBookmarks Menu Code -->
<div class="sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-sexy">
<ul class="socials">
		<li class="sexy-twitter">
			<a href="http://twitter.com/home?status=Versioning+MySQL+data+-+http://b2l.me/tr67d+(via+@JasnyArnold)&amp;source=shareaholic" rel="nofollow" class="external" title="Tweet This!">Tweet This!</a>
		</li>
		<li class="sexy-dzone">
			<a href="http://www.dzone.com/links/add.html?url=http://www.jasny.net/articles/versioning-mysql-data/&amp;title=Versioning+MySQL+data&amp;description=POST_SUMMARY" rel="nofollow" class="external" title="Add this to DZone">Add this to DZone</a>
		</li>
		<li class="sexy-stumbleupon">
			<a href="http://www.stumbleupon.com/submit?url=http://www.jasny.net/articles/versioning-mysql-data/&amp;title=Versioning+MySQL+data" rel="nofollow" class="external" title="Stumble upon something good? Share it on StumbleUpon">Stumble upon something good? Share it on StumbleUpon</a>
		</li>
		<li class="sexy-reddit">
			<a href="http://reddit.com/submit?url=http://www.jasny.net/articles/versioning-mysql-data/&amp;title=Versioning+MySQL+data" rel="nofollow" class="external" title="Share this on Reddit">Share this on Reddit</a>
		</li>
		<li class="sexy-delicious">
			<a href="http://delicious.com/post?url=http://www.jasny.net/articles/versioning-mysql-data/&amp;title=Versioning+MySQL+data" rel="nofollow" class="external" title="Share this on del.icio.us">Share this on del.icio.us</a>
		</li>
		<li class="sexy-digg">
			<a href="http://digg.com/submit?phase=2&amp;url=http://www.jasny.net/articles/versioning-mysql-data/&amp;title=Versioning+MySQL+data" rel="nofollow" class="external" title="Digg this!">Digg this!</a>
		</li>
		<li class="sexy-technorati">
			<a href="http://technorati.com/faves?add=http://www.jasny.net/articles/versioning-mysql-data/" rel="nofollow" class="external" title="Share this on Technorati">Share this on Technorati</a>
		</li>
		<li class="sexy-googlebuzz">
			<a href="http://www.google.com/buzz/post?url=http://www.jasny.net/articles/versioning-mysql-data/&amp;imageurl=" rel="nofollow" class="external" title="Post on Google Buzz">Post on Google Buzz</a>
		</li>
		<li class="sexy-facebook">
			<a href="http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://www.jasny.net/articles/versioning-mysql-data/&amp;t=Versioning+MySQL+data" rel="nofollow" class="external" title="Share this on Facebook">Share this on Facebook</a>
		</li>
		<li class="sexy-linkedin">
			<a href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://www.jasny.net/articles/versioning-mysql-data/&amp;title=Versioning+MySQL+data&amp;summary=As%20a%20developer%20you%27re%20probably%20using%20a%20versioning%20control%20system%2C%20like%20subversion%20or%20git%2C%20to%20safeguard%20your%20data.%20Advantages%20of%20using%20a%20VCS%20are%20that%20you%20can%20walk%20to%20the%20individual%20changes%20for%20a%20document%2C%20see%20who%20made%20each%20change%20and%20revert%20back%20to%20specific%20revision%20if%20needed.%20These%20are%20features%20whic&amp;source=Jasny | Arnold&#039;s wor(l)ds" rel="nofollow" class="external" title="Share this on LinkedIn">Share this on LinkedIn</a>
		</li>
		<li class="sexy-mail">
			<a href="mailto:?subject=%22Versioning%20MySQL%20data%22&amp;body=I+thought+this+article+might+interest+you.%0A%0A%22As%20a%20developer%20you%27re%20probably%20using%20a%20versioning%20control%20system%2C%20like%20subversion%20or%20git%2C%20to%20safeguard%20your%20data.%20Advantages%20of%20using%20a%20VCS%20are%20that%20you%20can%20walk%20to%20the%20individual%20changes%20for%20a%20document%2C%20see%20who%20made%20each%20change%20and%20revert%20back%20to%20specific%20revision%20if%20needed.%20These%20are%20features%20whic%22%0A%0AYou+can+read+the+full+article+here%3A%20http://www.jasny.net/articles/versioning-mysql-data/" rel="nofollow" class="external" title="Email this to a friend?">Email this to a friend?</a>
		</li>
</ul>
<div style="clear:both;"></div>
</div>
<!-- End SexyBookmarks Menu Code -->

]]></content:encoded>
			<wfw:commentRss>http://www.jasny.net/articles/versioning-mysql-data/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>EAV multi-value fields</title>
		<link>http://www.jasny.net/articles/eav-multi-value-fields/</link>
		<comments>http://www.jasny.net/articles/eav-multi-value-fields/#comments</comments>
		<pubDate>Wed, 28 Oct 2009 16:59:51 +0000</pubDate>
		<dc:creator>Arnold Daniels</dc:creator>
				<category><![CDATA[MySQL, Sphinx and NoSQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.adaniels.nl/?p=278</guid>
		<description><![CDATA[In the article &#8216;An alternative way of EAV modelling&#8217;, I discussed how to do EAV modelling by casting all values (except text) to integers. I&#8217;ll continue on that and talk about more advanced topics like multi-value fields.
As binary set
Not all questions have only a single option. Some fields we want to represent by radio-buttons, allow [...]]]></description>
			<content:encoded><![CDATA[<p>In the <a href="http://www.adaniels.nl/articles/an-alternative-way-of-eav-modeling/">article &#8216;An alternative way of EAV modelling&#8217;</a>, I discussed how to do EAV modelling by casting all values (except text) to integers. I&#8217;ll continue on that and talk about more advanced topics like multi-value fields.</p>
<p><strong>As binary set</strong><br />
Not all questions have only a single option. Some fields we want to represent by radio-buttons, allow the user to select any number of options. For this we can mimic the behaviour of the SET field type of MySQL. A SET is almost similar to an ENUM, except that each bit represents an option. The value can have multiple bits enabled to represent multiple options.</p>
<p>Example: field options for field &#8216;programming language&#8217;</p>
<pre>
+-------+-------------+
| value | description |
+-------+-------------+
| 1     | C/C++       |
| 2     | PHP         |
| 4     | Java        |
| 8     | Python      |
| 16    | Ruby        |
+-------+-------------+
</pre>
<p>Choosing &#8216;C/C++&#8217;, &#8216;PHP&#8217; and &#8216;Python&#8217; would result in value 11.</p>
<p>There are 2 major disadvantages to this approach. First, with an integer, the number of options is limited to 4*8 = 32. Second, retrieving the description of options would cause joining field on field_option to be done like:</p>

<div class="wp_syntax"><div class="code"><pre class="sql"><span style="color: #993333; font-weight: bold;">SELECT</span> value_display<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`field_name`</span>, value_display<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`field_type`</span>, <span style="color: #ff0000;">`value`</span>.<span style="color: #ff0000;">`value`</span>, GROUP_CONCAT<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`field_option`</span>.<span style="color: #ff0000;">`description`</span><span style="color: #66cc66;">&#41;</span>, <span style="color: #ff0000;">`value`</span>.<span style="color: #ff0000;">`text`</span>, <span style="color: #ff0000;">`precision`</span>, <span style="color: #ff0000;">`date_format`</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`value`</span> <span style="color: #993333; font-weight: bold;">INNER</span> <span style="color: #993333; font-weight: bold;">JOIN</span> <span style="color: #ff0000;">`field`</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #ff0000;">`value`</span>.<span style="color: #ff0000;">`fid`</span> = <span style="color: #ff0000;">`field`</span>.<span style="color: #ff0000;">`fid`</span> <span style="color: #993333; font-weight: bold;">LEFT</span> <span style="color: #993333; font-weight: bold;">JOIN</span> <span style="color: #ff0000;">`field_option`</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #ff0000;">`value`</span>.<span style="color: #ff0000;">`fid`</span> = <span style="color: #ff0000;">`field_option`</span>.<span style="color: #ff0000;">`fid`</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">IF</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`field`</span>.<span style="color: #ff0000;">`field_type`</span>=<span style="color: #ff0000;">'SET, `value`.`value` &amp; `field_option`.`value`, `value`.`value` = `field_option`.`value`)) WHERE `value`.`item_id`=? GROUP BY `value`.`fid`;</span></pre></div></div>

<p>Because of this, the index on the value isn&#8217;t used. Instead, a function has to be performed on each option of the field. This should still give decent enough performance, because this scales linearly and not exponential.</p>
<p><strong>Multiple values</strong><br />
Another way is to store multiple values for the same property. This would mean replacing the primary key from the value table by a normal index.</p>

<div class="wp_syntax"><div class="code"><pre class="sql"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> <span style="color: #ff0000;">`value`</span> <span style="color: #66cc66;">&#40;</span>
  <span style="color: #ff0000;">`item_id`</span> int<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">10</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <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: #ff0000;">'0'</span>,
  <span style="color: #ff0000;">`fid`</span> int<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">10</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">UNSIGNED</span> <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: #ff0000;">'0'</span>,
  <span style="color: #ff0000;">`value`</span> int<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">11</span><span style="color: #66cc66;">&#41;</span> <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: #ff0000;">'0'</span>,
  <span style="color: #ff0000;">`text`</span> text,
  <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #ff0000;">`item_field`</span>  <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`item_id`</span>,<span style="color: #ff0000;">`fid`</span><span style="color: #66cc66;">&#41;</span>,
  <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #ff0000;">`value`</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`fid`</span>,<span style="color: #ff0000;">`value`</span><span style="color: #66cc66;">&#41;</span>,
  <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #ff0000;">`text`</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`text`</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">255</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span> ENGINE=InnoDB <span style="color: #993333; font-weight: bold;">DEFAULT</span> CHARSET=latin1;
&nbsp;
<span style="color: #993333; font-weight: bold;">SELECT</span> value_display<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`field_name`</span>, value_display<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`field_type`</span>, <span style="color: #ff0000;">`value`</span>.<span style="color: #ff0000;">`value`</span>, GROUP_CONCAT<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`field_option`</span>.<span style="color: #ff0000;">`description`</span><span style="color: #66cc66;">&#41;</span>, <span style="color: #ff0000;">`value`</span>.<span style="color: #ff0000;">`text`</span>, <span style="color: #ff0000;">`precision`</span>, <span style="color: #ff0000;">`date_format`</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`value`</span> <span style="color: #993333; font-weight: bold;">INNER</span> <span style="color: #993333; font-weight: bold;">JOIN</span> <span style="color: #ff0000;">`field`</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #ff0000;">`value`</span>.<span style="color: #ff0000;">`fid`</span> = <span style="color: #ff0000;">`field`</span>.<span style="color: #ff0000;">`fid`</span> <span style="color: #993333; font-weight: bold;">LEFT</span> <span style="color: #993333; font-weight: bold;">JOIN</span> <span style="color: #ff0000;">`field_option`</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #ff0000;">`value`</span>.<span style="color: #ff0000;">`fid`</span> = <span style="color: #ff0000;">`field_option`</span>.<span style="color: #ff0000;">`fid`</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #ff0000;">`value`</span>.<span style="color: #ff0000;">`value`</span> = <span style="color: #ff0000;">`field_option`</span>.<span style="color: #ff0000;">`value`</span> <span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #ff0000;">`value`</span>.<span style="color: #ff0000;">`item_id`</span>=? <span style="color: #993333; font-weight: bold;">GROUP</span> <span style="color: #993333; font-weight: bold;">BY</span> <span style="color: #ff0000;">`value`</span>.<span style="color: #ff0000;">`fid`</span>;</pre></div></div>

<p>The disadvantage of this, is that structural integrity is no longer enforced by the database. Only for a field with the type &#8216;SET&#8217;, multiple values should be allowed. However the database will allow multiple values for other field types (like numeric fields) as well. It is up to the application to replace existing values.</p>
<p><strong>Ranges with a single field</strong><br />
A completely different type of multi-value is ranges. A range has a top and bottom value. We can solve this by saving 2 values in the database. Of the values, the the highest one is always the upper limit and the lowest is the bottom limit.</p>

<div class="wp_syntax"><div class="code"><pre class="sql">delimiter |
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">FUNCTION</span> <span style="color: #ff0000;">`value_display`</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`type`</span> enum<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'NUMBER'</span>, <span style="color: #ff0000;">'ENUM'</span>, <span style="color: #ff0000;">'DATE'</span>, <span style="color: #ff0000;">'TIME'</span>, <span style="color: #ff0000;">'TEXT'</span><span style="color: #66cc66;">&#41;</span>, <span style="color: #ff0000;">`value`</span> INT, &lt;strong&gt;<span style="color: #ff0000;">`max_value`</span> INT&lt;/strong&gt;, <span style="color: #ff0000;">`option`</span> VARCHAR<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">255</span><span style="color: #66cc66;">&#41;</span>, <span style="color: #ff0000;">`text`</span> TEXT, <span style="color: #ff0000;">`precision`</span> INT, <span style="color: #ff0000;">`date_format`</span> VARCHAR<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">50</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> RETURNS VARCHAR<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">255</span><span style="color: #66cc66;">&#41;</span> CHARACTER <span style="color: #993333; font-weight: bold;">SET</span> latin1 NO SQL
BEGIN
  // ...
END
&nbsp;
<span style="color: #993333; font-weight: bold;">SELECT</span> value_display<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`field_name`</span>, value_display<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`field_type`</span>, MIN<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`value`</span>.<span style="color: #ff0000;">`value`</span><span style="color: #66cc66;">&#41;</span>, <span style="color: #993333; font-weight: bold;">IF</span><span style="color: #66cc66;">&#40;</span>COUNT<span style="color: #66cc66;">&#40;</span>*<span style="color: #66cc66;">&#41;</span>&gt;<span style="color: #cc66cc;">1</span>, MAX<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`value`</span>.<span style="color: #ff0000;">`value`</span>, <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">&#41;</span>, GROUP_CONCAT<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`field_option`</span>.<span style="color: #ff0000;">`description`</span><span style="color: #66cc66;">&#41;</span>, <span style="color: #ff0000;">`value`</span>.<span style="color: #ff0000;">`text`</span>, <span style="color: #ff0000;">`precision`</span>, <span style="color: #ff0000;">`date_format`</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`value`</span> <span style="color: #993333; font-weight: bold;">INNER</span> <span style="color: #993333; font-weight: bold;">JOIN</span> <span style="color: #ff0000;">`field`</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #ff0000;">`value`</span>.<span style="color: #ff0000;">`fid`</span> = <span style="color: #ff0000;">`field`</span>.<span style="color: #ff0000;">`fid`</span> <span style="color: #993333; font-weight: bold;">LEFT</span> <span style="color: #993333; font-weight: bold;">JOIN</span> <span style="color: #ff0000;">`field_option`</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #ff0000;">`value`</span>.<span style="color: #ff0000;">`fid`</span> = <span style="color: #ff0000;">`field_option`</span>.<span style="color: #ff0000;">`fid`</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #ff0000;">`value`</span>.<span style="color: #ff0000;">`value`</span> = <span style="color: #ff0000;">`field_option`</span>.<span style="color: #ff0000;">`value`</span> <span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #ff0000;">`value`</span>.<span style="color: #ff0000;">`item_id`</span>=? <span style="color: #993333; font-weight: bold;">GROUP</span> <span style="color: #993333; font-weight: bold;">BY</span> <span style="color: #ff0000;">`value`</span>.<span style="color: #ff0000;">`fid`</span>;</pre></div></div>

<p><strong>Range by 2 fields</strong><br />
Another was of looking at ranges is that the are simply 2 individual fields, eg `min weight` and `max weight`. When filtering you might want to get all items that have 70 kg in their weight range. You would translate this to `min weight` <= 70 and `max weight` >= 70. (In the example query `min weight` has fid=2 and `max weight` fid=3.)</p>

<div class="wp_syntax"><div class="code"><pre class="sql"><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #ff0000;">`item`</span>.* <span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`item`</span> <span style="color: #993333; font-weight: bold;">INNER</span> <span style="color: #993333; font-weight: bold;">JOIN</span> <span style="color: #ff0000;">`value`</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #ff0000;">`item`</span>.<span style="color: #ff0000;">`id`</span>=<span style="color: #ff0000;">`value`</span>.<span style="color: #ff0000;">`item_id`</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #ff0000;">`value`</span>.<span style="color: #ff0000;">`fid`</span> <span style="color: #993333; font-weight: bold;">IN</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">2</span>, <span style="color: #cc66cc;">3</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`value`</span>.<span style="color: #ff0000;">`fid`</span>=<span style="color: #cc66cc;">2</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #ff0000;">`value`</span>.<span style="color: #ff0000;">`value`</span> &lt;= <span style="color: #cc66cc;">70</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">OR</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`value`</span>.<span style="color: #ff0000;">`fid`</span>=<span style="color: #cc66cc;">3</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #ff0000;">`value`</span>.<span style="color: #ff0000;">`value`</span> &gt;= <span style="color: #cc66cc;">70</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">HAVING</span> count<span style="color: #66cc66;">&#40;</span>*<span style="color: #66cc66;">&#41;</span> =<span style="color: #cc66cc;">2</span> <span style="color: #993333; font-weight: bold;">GROUP</span> <span style="color: #993333; font-weight: bold;">BY</span> <span style="color: #ff0000;">`item`</span>.<span style="color: #ff0000;">`id`</span>;</pre></div></div>

<p><strong>Conclusion</strong><br />
We see that using multi-value fields forces to group on fid and generally complicates the queries. If you only need ranges it might be a good idea to use 2 fields instead to keep the queries simpler.</p>
<p><i>The code in this article has not been tested.</i></p>


<!-- Begin SexyBookmarks Menu Code -->
<div class="sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-sexy">
<ul class="socials">
		<li class="sexy-twitter">
			<a href="http://twitter.com/home?status=EAV+multi-value+fields+-+http://b2l.me/tr67e+(via+@JasnyArnold)&amp;source=shareaholic" rel="nofollow" class="external" title="Tweet This!">Tweet This!</a>
		</li>
		<li class="sexy-dzone">
			<a href="http://www.dzone.com/links/add.html?url=http://www.jasny.net/articles/eav-multi-value-fields/&amp;title=EAV+multi-value+fields&amp;description=POST_SUMMARY" rel="nofollow" class="external" title="Add this to DZone">Add this to DZone</a>
		</li>
		<li class="sexy-stumbleupon">
			<a href="http://www.stumbleupon.com/submit?url=http://www.jasny.net/articles/eav-multi-value-fields/&amp;title=EAV+multi-value+fields" rel="nofollow" class="external" title="Stumble upon something good? Share it on StumbleUpon">Stumble upon something good? Share it on StumbleUpon</a>
		</li>
		<li class="sexy-reddit">
			<a href="http://reddit.com/submit?url=http://www.jasny.net/articles/eav-multi-value-fields/&amp;title=EAV+multi-value+fields" rel="nofollow" class="external" title="Share this on Reddit">Share this on Reddit</a>
		</li>
		<li class="sexy-delicious">
			<a href="http://delicious.com/post?url=http://www.jasny.net/articles/eav-multi-value-fields/&amp;title=EAV+multi-value+fields" rel="nofollow" class="external" title="Share this on del.icio.us">Share this on del.icio.us</a>
		</li>
		<li class="sexy-digg">
			<a href="http://digg.com/submit?phase=2&amp;url=http://www.jasny.net/articles/eav-multi-value-fields/&amp;title=EAV+multi-value+fields" rel="nofollow" class="external" title="Digg this!">Digg this!</a>
		</li>
		<li class="sexy-technorati">
			<a href="http://technorati.com/faves?add=http://www.jasny.net/articles/eav-multi-value-fields/" rel="nofollow" class="external" title="Share this on Technorati">Share this on Technorati</a>
		</li>
		<li class="sexy-googlebuzz">
			<a href="http://www.google.com/buzz/post?url=http://www.jasny.net/articles/eav-multi-value-fields/&amp;imageurl=" rel="nofollow" class="external" title="Post on Google Buzz">Post on Google Buzz</a>
		</li>
		<li class="sexy-facebook">
			<a href="http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://www.jasny.net/articles/eav-multi-value-fields/&amp;t=EAV+multi-value+fields" rel="nofollow" class="external" title="Share this on Facebook">Share this on Facebook</a>
		</li>
		<li class="sexy-linkedin">
			<a href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://www.jasny.net/articles/eav-multi-value-fields/&amp;title=EAV+multi-value+fields&amp;summary=In%20the%20article%20%27An%20alternative%20way%20of%20EAV%20modelling%27%2C%20I%20discussed%20how%20to%20do%20EAV%20modelling%20by%20casting%20all%20values%20%28except%20text%29%20to%20integers.%20I%27ll%20continue%20on%20that%20and%20talk%20about%20more%20advanced%20topics%20like%20multi-value%20fields.%0D%0A%0D%0AAs%20binary%20set%0D%0ANot%20all%20questions%20have%20only%20a%20single%20option.%20Some%20fields%20we%20&amp;source=Jasny | Arnold&#039;s wor(l)ds" rel="nofollow" class="external" title="Share this on LinkedIn">Share this on LinkedIn</a>
		</li>
		<li class="sexy-mail">
			<a href="mailto:?subject=%22EAV%20multi-value%20fields%22&amp;body=I+thought+this+article+might+interest+you.%0A%0A%22In%20the%20article%20%27An%20alternative%20way%20of%20EAV%20modelling%27%2C%20I%20discussed%20how%20to%20do%20EAV%20modelling%20by%20casting%20all%20values%20%28except%20text%29%20to%20integers.%20I%27ll%20continue%20on%20that%20and%20talk%20about%20more%20advanced%20topics%20like%20multi-value%20fields.%0D%0A%0D%0AAs%20binary%20set%0D%0ANot%20all%20questions%20have%20only%20a%20single%20option.%20Some%20fields%20we%20%22%0A%0AYou+can+read+the+full+article+here%3A%20http://www.jasny.net/articles/eav-multi-value-fields/" rel="nofollow" class="external" title="Email this to a friend?">Email this to a friend?</a>
		</li>
</ul>
<div style="clear:both;"></div>
</div>
<!-- End SexyBookmarks Menu Code -->

]]></content:encoded>
			<wfw:commentRss>http://www.jasny.net/articles/eav-multi-value-fields/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>How I PHP: multiple inheritance</title>
		<link>http://www.jasny.net/articles/how-i-php-multiple-inheritance/</link>
		<comments>http://www.jasny.net/articles/how-i-php-multiple-inheritance/#comments</comments>
		<pubDate>Sat, 26 Sep 2009 19:38:48 +0000</pubDate>
		<dc:creator>Arnold Daniels</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">http://www.adaniels.nl/?p=242</guid>
		<description><![CDATA[Officially PHP doesn&#8217;t support multiple inheritance. There are several ways around this, without having to duplicate code.
Wrapper
The most commonly used method is to use a wrapper object.

&#60;?php
&#160;
abstract class FsNode
&#123;
  public $path;
&#160;
  public function __construct&#40;$path&#41; &#123;
    $this-&#62;path = $path;
  &#125;
&#160;
  public function rename&#40;$newname&#41; &#123;
    rename&#40;$this-&#62;path, $newname&#41;;
 [...]]]></description>
			<content:encoded><![CDATA[<p>Officially PHP doesn&#8217;t support multiple inheritance. There are several ways around this, without having to duplicate code.</p>
<h2>Wrapper</h2>
<p>The most commonly used method is to use a <a href="http://en.wikipedia.org/wiki/Wrapper_pattern">wrapper</a> object.</p>

<div class="wp_syntax"><div class="code"><pre class="php"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
&nbsp;
abstract <span style="color: #000000; font-weight: bold;">class</span> FsNode
<span style="color: #66cc66;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #0000ff;">$path</span>;
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$path</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">path</span> = <span style="color: #0000ff;">$path</span>;
  <span style="color: #66cc66;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> <span style="color: #000066;">rename</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$newname</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #000066;">rename</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">path</span>, <span style="color: #0000ff;">$newname</span><span style="color: #66cc66;">&#41;</span>;
    <span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">path</span> = <span style="color: #0000ff;">$newname</span>;
  <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> <span style="color: #000066;">File</span> <span style="color: #000000; font-weight: bold;">extends</span> FsNode
<span style="color: #66cc66;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getContents<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #000066;">file_get_contents</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">path</span><span style="color: #66cc66;">&#41;</span>;
  <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> <span style="color: #000066;">Dir</span> <span style="color: #000000; font-weight: bold;">extends</span> FsNode
<span style="color: #66cc66;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> scandir<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #b1b100;">return</span> scandir<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">path</span><span style="color: #66cc66;">&#41;</span>;
  <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> <span style="color: #000066;">Symlink</span>
<span style="color: #66cc66;">&#123;</span>
  protected <span style="color: #0000ff;">$node</span>;
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$node</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">node</span>  = <span style="color: #0000ff;">$node</span>;
  <span style="color: #66cc66;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> target<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$resolve</span>=<span style="color: #000000; font-weight: bold;">false</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #0000ff;">$resolve</span> ? <span style="color: #000066;">realpath</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">node</span>-&gt;<span style="color: #006600;">path</span><span style="color: #66cc66;">&#41;</span> : <span style="color: #000066;">readlink</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">node</span>-&gt;<span style="color: #006600;">path</span><span style="color: #66cc66;">&#41;</span>;
  <span style="color: #66cc66;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __call<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$method</span>, <span style="color: #0000ff;">$args</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #000066;">call_user_func_array</span><span style="color: #66cc66;">&#40;</span><span style="color: #000066;">array</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">node</span>, <span style="color: #0000ff;">$method</span><span style="color: #66cc66;">&#41;</span>, <span style="color: #0000ff;">$args</span><span style="color: #66cc66;">&#41;</span>;
  <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span>
&nbsp;
<span style="color: #0000ff;">$dir</span> = <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #000066;">Dir</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;/proc&quot;</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #0000ff;">$linktodir</span> = <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #000066;">Symlink</span><span style="color: #66cc66;">&#40;</span><span style="color: #000000; font-weight: bold;">new</span> <span style="color: #000066;">Dir</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;/proc/self&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #000066;">var_dump</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$linktodir</span>-&gt;<span style="color: #006600;">scandir</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>; <span style="color: #808080; font-style: italic;">// Will be called through __call()</span>
<span style="color: #000066;">echo</span> <span style="color: #0000ff;">$linktodir</span>-&gt;<span style="color: #006600;">target</span><span style="color: #66cc66;">&#40;</span><span style="color: #000000; font-weight: bold;">true</span><span style="color: #66cc66;">&#41;</span>, <span style="color: #ff0000;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>;</pre></div></div>

<p>A disadvantage is that is no longer possible to see if a node is a dir by using instanceof. Also, if most of the methods are defined in the wrapped class, this solution will hurt performance.</p>
<h2>Mixin</h2>
<p>A far more interesting approach is to use a <a href="http://en.wikipedia.org/wiki/Mixin">mixins</a>. When you call a non-static method, $this is always passed to that method. This is also the case if the calling object is not inherited from the called class. We can use that to our advantage to do the reverse of the wrapper.</p>

<div class="wp_syntax"><div class="code"><pre class="php">abstract <span style="color: #000000; font-weight: bold;">class</span> FsNode
<span style="color: #66cc66;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #0000ff;">$mixin</span>;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #0000ff;">$path</span>;
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __construct<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$path</span>, <span style="color: #0000ff;">$mixin</span>=<span style="color: #000000; font-weight: bold;">null</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">path</span> = <span style="color: #0000ff;">$path</span>;
    <span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">mixin</span> = <span style="color: #0000ff;">$mixin</span>;
  <span style="color: #66cc66;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">function</span> <span style="color: #000066;">rename</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$newname</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #000066;">rename</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">path</span>, <span style="color: #0000ff;">$newname</span><span style="color: #66cc66;">&#41;</span>;
    <span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">path</span> = <span style="color: #0000ff;">$newname</span>;
  <span style="color: #66cc66;">&#125;</span>
&nbsp;
  <span style="color: #000000; font-weight: bold;">public</span>  <span style="color: #000000; font-weight: bold;">function</span> __call<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$method</span>, <span style="color: #0000ff;">$args</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><span style="color: #000066;">isset</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">mixin</span><span style="color: #66cc66;">&#41;</span> &amp;&amp; <span style="color: #000066;">ctype_alnum</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$method</span><span style="color: #66cc66;">&#41;</span> &amp;&amp; <span style="color: #000066;">is_callable</span><span style="color: #66cc66;">&#40;</span><span style="color: #000066;">array</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">mixin</span>, <span style="color: #0000ff;">$method</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
      <span style="color: #b1b100;">return</span> <span style="color: #000066;">eval</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;return {$this-&gt;mixin}::$method(&quot;</span> . <span style="color: #66cc66;">&#40;</span>!<span style="color: #000066;">empty</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$args</span><span style="color: #66cc66;">&#41;</span> ? <span style="color: #ff0000;">'$args['</span> . <span style="color: #000066;">join</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'], $args['</span>, <span style="color: #000066;">array_keys</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$args</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> . <span style="color: #ff0000;">']'</span> : <span style="color: #ff0000;">''</span><span style="color: #66cc66;">&#41;</span> . <span style="color: #ff0000;">&quot;);&quot;</span><span style="color: #66cc66;">&#41;</span>;
    <span style="color: #66cc66;">&#125;</span>
    <span style="color: #000066;">trigger_error</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;Call to undefined method &quot;</span> . <span style="color: #000066;">get_class</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$this</span><span style="color: #66cc66;">&#41;</span> . <span style="color: #ff0000;">&quot;::$method()&quot;</span>, <span style="color: #000000; font-weight: bold;">E_USER_ERROR</span><span style="color: #66cc66;">&#41;</span>;
  <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> <span style="color: #000066;">File</span> <span style="color: #000000; font-weight: bold;">extends</span> FsNode
<span style="color: #66cc66;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getContents<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #000066;">file_get_contents</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">path</span><span style="color: #66cc66;">&#41;</span>;
  <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> <span style="color: #000066;">Dir</span> <span style="color: #000000; font-weight: bold;">extends</span> FsNode
<span style="color: #66cc66;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> scandir<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #b1b100;">return</span> scandir<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">path</span><span style="color: #66cc66;">&#41;</span>;
  <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> <span style="color: #000066;">Symlink</span> <span style="color: #000000; font-weight: bold;">extends</span> FsNode
<span style="color: #66cc66;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> target<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$resolve</span>=<span style="color: #000000; font-weight: bold;">false</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #0000ff;">$resolve</span> ? <span style="color: #000066;">realpath</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">path</span><span style="color: #66cc66;">&#41;</span> : <span style="color: #000066;">readlink</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">path</span><span style="color: #66cc66;">&#41;</span>;
  <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span>
&nbsp;
<span style="color: #0000ff;">$dir</span> = <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #000066;">Dir</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;/proc&quot;</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #0000ff;">$linktodir</span> = <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #000066;">Dir</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;/proc/self&quot;</span>, <span style="color: #ff0000;">'Symlink'</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #000066;">var_dump</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$linktodir</span>-&gt;<span style="color: #006600;">scandir</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #000066;">echo</span> <span style="color: #0000ff;">$linktodir</span>-&gt;<span style="color: #006600;">target</span><span style="color: #66cc66;">&#40;</span><span style="color: #000000; font-weight: bold;">true</span><span style="color: #66cc66;">&#41;</span>, <span style="color: #ff0000;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>; <span style="color: #808080; font-style: italic;">// Will be called through __call()</span></pre></div></div>

<p><b>caveat:</b> The Symlink class is never instantiated. Properties defined in the Symlink class are ignored. Also, since Symlink doesn&#8217;t extends Dir, it&#8217;s not possible to access protected properties defined in Dir.</p>
<h2>Compile time mixin</h2>
<p>To see if a node is a symlink, you would need to do</p>

<div class="wp_syntax"><div class="code"><pre class="php"><span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><span style="color: #000066;">isset</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$file</span>-&gt;<span style="color: #006600;">mixin</span><span style="color: #66cc66;">&#41;</span> &amp;&amp; <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$file</span>-&gt;<span style="color: #006600;">mixin</span> === <span style="color: #ff0000;">'Symlink'</span> || <span style="color: #000066;">is_subclass_of</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$file</span>-&gt;<span style="color: #006600;">mixin</span>, <span style="color: #ff0000;">'Symlink'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
  <span style="color: #808080; font-style: italic;">//...</span>
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>It would be nicer if you could simply use instance of. This is only possible by defining all combination. We can still use mixins though to prevent having to duplicate code.</p>

<div class="wp_syntax"><div class="code"><pre class="php">abstract <span style="color: #000000; font-weight: bold;">class</span> FsNode
<span style="color: #66cc66;">&#123;</span>
  protected <span style="color: #0000ff;">$mixin</span>;
  <span style="color: #808080; font-style: italic;">// Same as above</span>
<span style="color: #66cc66;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> <span style="color: #000066;">File</span> <span style="color: #000000; font-weight: bold;">extends</span> FsNode
<span style="color: #66cc66;">&#123;</span>
  <span style="color: #808080; font-style: italic;">// Same as above</span>
<span style="color: #66cc66;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> <span style="color: #000066;">Dir</span> <span style="color: #000000; font-weight: bold;">extends</span> FsNode
<span style="color: #66cc66;">&#123;</span>
  <span style="color: #808080; font-style: italic;">// Same as above</span>
<span style="color: #66cc66;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">interface</span> <span style="color: #000066;">Symlink</span>
<span style="color: #66cc66;">&#123;</span><span style="color: #66cc66;">&#125;</span>
&nbsp;
abstract <span style="color: #000000; font-weight: bold;">class</span> Symlink_Methods <span style="color: #000000; font-weight: bold;">extends</span> FsNode
<span style="color: #66cc66;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> target<span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$resolve</span>=<span style="color: #000000; font-weight: bold;">false</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #0000ff;">$resolve</span> ? <span style="color: #000066;">realpath</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">path</span><span style="color: #66cc66;">&#41;</span> : <span style="color: #000066;">readlink</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$this</span>-&gt;<span style="color: #006600;">path</span><span style="color: #66cc66;">&#41;</span>;
  <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> SymlinkFile <span style="color: #000000; font-weight: bold;">extends</span> <span style="color: #000066;">File</span> implements <span style="color: #000066;">Symlink</span>
<span style="color: #66cc66;">&#123;</span>
  protected <span style="color: #0000ff;">$mixin</span> = <span style="color: #ff0000;">'Symlink_Methods'</span>;
<span style="color: #66cc66;">&#125;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> SymlinkDir <span style="color: #000000; font-weight: bold;">extends</span> <span style="color: #000066;">Dir</span> implements <span style="color: #000066;">Symlink</span>
<span style="color: #66cc66;">&#123;</span>
  protected <span style="color: #0000ff;">$mixin</span> = <span style="color: #ff0000;">'Symlink_Methods'</span>;
<span style="color: #66cc66;">&#125;</span>
&nbsp;
<span style="color: #0000ff;">$dir</span> = <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #000066;">Dir</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;/proc&quot;</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #0000ff;">$linktodir</span> = <span style="color: #000000; font-weight: bold;">new</span> SymlinkDir<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;/proc/self&quot;</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #000066;">var_dump</span><span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$linktodir</span>-&gt;<span style="color: #006600;">scandir</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #000066;">echo</span> <span style="color: #0000ff;">$linktodir</span>-&gt;<span style="color: #006600;">target</span><span style="color: #66cc66;">&#40;</span><span style="color: #000000; font-weight: bold;">true</span><span style="color: #66cc66;">&#41;</span>, <span style="color: #ff0000;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>; <span style="color: #808080; font-style: italic;">// Will be called through __call()</span>
&nbsp;
<span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$dir</span> instanceof <span style="color: #000066;">Dir</span><span style="color: #66cc66;">&#41;</span>  ; <span style="color: #808080; font-style: italic;">// True</span>
<span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$dir</span> instanceof <span style="color: #000066;">Symlink</span><span style="color: #66cc66;">&#41;</span>  ; <span style="color: #808080; font-style: italic;">// False</span>
<span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$linktodir</span> instanceof <span style="color: #000066;">Dir</span><span style="color: #66cc66;">&#41;</span>  ; <span style="color: #808080; font-style: italic;">// True</span>
<span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span><span style="color: #0000ff;">$linktodir</span> instanceof <span style="color: #000066;">Symlink</span><span style="color: #66cc66;">&#41;</span>  ; <span style="color: #808080; font-style: italic;">// True</span></pre></div></div>



<!-- Begin SexyBookmarks Menu Code -->
<div class="sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-sexy">
<ul class="socials">
		<li class="sexy-twitter">
			<a href="http://twitter.com/home?status=How+I+PHP%3A+multiple+inheritance+-+http://b2l.me/tr67n+(via+@JasnyArnold)&amp;source=shareaholic" rel="nofollow" class="external" title="Tweet This!">Tweet This!</a>
		</li>
		<li class="sexy-dzone">
			<a href="http://www.dzone.com/links/add.html?url=http://www.jasny.net/articles/how-i-php-multiple-inheritance/&amp;title=How+I+PHP%3A+multiple+inheritance&amp;description=POST_SUMMARY" rel="nofollow" class="external" title="Add this to DZone">Add this to DZone</a>
		</li>
		<li class="sexy-stumbleupon">
			<a href="http://www.stumbleupon.com/submit?url=http://www.jasny.net/articles/how-i-php-multiple-inheritance/&amp;title=How+I+PHP%3A+multiple+inheritance" rel="nofollow" class="external" title="Stumble upon something good? Share it on StumbleUpon">Stumble upon something good? Share it on StumbleUpon</a>
		</li>
		<li class="sexy-reddit">
			<a href="http://reddit.com/submit?url=http://www.jasny.net/articles/how-i-php-multiple-inheritance/&amp;title=How+I+PHP%3A+multiple+inheritance" rel="nofollow" class="external" title="Share this on Reddit">Share this on Reddit</a>
		</li>
		<li class="sexy-delicious">
			<a href="http://delicious.com/post?url=http://www.jasny.net/articles/how-i-php-multiple-inheritance/&amp;title=How+I+PHP%3A+multiple+inheritance" rel="nofollow" class="external" title="Share this on del.icio.us">Share this on del.icio.us</a>
		</li>
		<li class="sexy-digg">
			<a href="http://digg.com/submit?phase=2&amp;url=http://www.jasny.net/articles/how-i-php-multiple-inheritance/&amp;title=How+I+PHP%3A+multiple+inheritance" rel="nofollow" class="external" title="Digg this!">Digg this!</a>
		</li>
		<li class="sexy-technorati">
			<a href="http://technorati.com/faves?add=http://www.jasny.net/articles/how-i-php-multiple-inheritance/" rel="nofollow" class="external" title="Share this on Technorati">Share this on Technorati</a>
		</li>
		<li class="sexy-googlebuzz">
			<a href="http://www.google.com/buzz/post?url=http://www.jasny.net/articles/how-i-php-multiple-inheritance/&amp;imageurl=" rel="nofollow" class="external" title="Post on Google Buzz">Post on Google Buzz</a>
		</li>
		<li class="sexy-facebook">
			<a href="http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://www.jasny.net/articles/how-i-php-multiple-inheritance/&amp;t=How+I+PHP%3A+multiple+inheritance" rel="nofollow" class="external" title="Share this on Facebook">Share this on Facebook</a>
		</li>
		<li class="sexy-linkedin">
			<a href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://www.jasny.net/articles/how-i-php-multiple-inheritance/&amp;title=How+I+PHP%3A+multiple+inheritance&amp;summary=Officially%20PHP%20doesn%27t%20support%20multiple%20inheritance.%20There%20are%20several%20ways%20around%20this%2C%20without%20having%20to%20duplicate%20code.%0D%0A%0D%0AWrapper%0D%0AThe%20most%20commonly%20used%20method%20is%20to%20use%20a%20wrapper%20object.%0D%0A%0D%0A&amp;source=Jasny | Arnold&#039;s wor(l)ds" rel="nofollow" class="external" title="Share this on LinkedIn">Share this on LinkedIn</a>
		</li>
		<li class="sexy-mail">
			<a href="mailto:?subject=%22How%20I%20PHP%3A%20multiple%20inheritance%22&amp;body=I+thought+this+article+might+interest+you.%0A%0A%22Officially%20PHP%20doesn%27t%20support%20multiple%20inheritance.%20There%20are%20several%20ways%20around%20this%2C%20without%20having%20to%20duplicate%20code.%0D%0A%0D%0AWrapper%0D%0AThe%20most%20commonly%20used%20method%20is%20to%20use%20a%20wrapper%20object.%0D%0A%0D%0A%22%0A%0AYou+can+read+the+full+article+here%3A%20http://www.jasny.net/articles/how-i-php-multiple-inheritance/" rel="nofollow" class="external" title="Email this to a friend?">Email this to a friend?</a>
		</li>
</ul>
<div style="clear:both;"></div>
</div>
<!-- End SexyBookmarks Menu Code -->

]]></content:encoded>
			<wfw:commentRss>http://www.jasny.net/articles/how-i-php-multiple-inheritance/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Suhosin patch for PHP 5.3</title>
		<link>http://www.jasny.net/articles/suhosin-patch-for-php-53/</link>
		<comments>http://www.jasny.net/articles/suhosin-patch-for-php-53/#comments</comments>
		<pubDate>Sat, 08 Aug 2009 17:05:15 +0000</pubDate>
		<dc:creator>Arnold Daniels</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">http://blog.adaniels.nl/?p=236</guid>
		<description><![CDATA[The hardened-php project has yet to release a suhosin patch for PHP 5.3.0. We&#8217;re already using PHP 5.3, therefore I&#8217;ve modified the 0.9.7 patch for 5.2.10 to work with 5.3.0.
-> Download Suhosin patch for PHP 5.3 

]]></description>
			<content:encoded><![CDATA[<p>The hardened-php project has yet to release a suhosin patch for PHP 5.3.0. We&#8217;re already using PHP 5.3, therefore I&#8217;ve modified the 0.9.7 patch for 5.2.10 to work with 5.3.0.</p>
<p>-> <a href='http://blog.adaniels.nl/wp-content/uploads/suhosinpatch.zip'>Download Suhosin patch for PHP 5.3</a> <-</p>


<!-- Begin SexyBookmarks Menu Code -->
<div class="sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-sexy">
<ul class="socials">
		<li class="sexy-twitter">
			<a href="http://twitter.com/home?status=Suhosin+patch+for+PHP+5.3+-+http://b2l.me/tr67z+(via+@JasnyArnold)&amp;source=shareaholic" rel="nofollow" class="external" title="Tweet This!">Tweet This!</a>
		</li>
		<li class="sexy-dzone">
			<a href="http://www.dzone.com/links/add.html?url=http://www.jasny.net/articles/suhosin-patch-for-php-53/&amp;title=Suhosin+patch+for+PHP+5.3&amp;description=POST_SUMMARY" rel="nofollow" class="external" title="Add this to DZone">Add this to DZone</a>
		</li>
		<li class="sexy-stumbleupon">
			<a href="http://www.stumbleupon.com/submit?url=http://www.jasny.net/articles/suhosin-patch-for-php-53/&amp;title=Suhosin+patch+for+PHP+5.3" rel="nofollow" class="external" title="Stumble upon something good? Share it on StumbleUpon">Stumble upon something good? Share it on StumbleUpon</a>
		</li>
		<li class="sexy-reddit">
			<a href="http://reddit.com/submit?url=http://www.jasny.net/articles/suhosin-patch-for-php-53/&amp;title=Suhosin+patch+for+PHP+5.3" rel="nofollow" class="external" title="Share this on Reddit">Share this on Reddit</a>
		</li>
		<li class="sexy-delicious">
			<a href="http://delicious.com/post?url=http://www.jasny.net/articles/suhosin-patch-for-php-53/&amp;title=Suhosin+patch+for+PHP+5.3" rel="nofollow" class="external" title="Share this on del.icio.us">Share this on del.icio.us</a>
		</li>
		<li class="sexy-digg">
			<a href="http://digg.com/submit?phase=2&amp;url=http://www.jasny.net/articles/suhosin-patch-for-php-53/&amp;title=Suhosin+patch+for+PHP+5.3" rel="nofollow" class="external" title="Digg this!">Digg this!</a>
		</li>
		<li class="sexy-technorati">
			<a href="http://technorati.com/faves?add=http://www.jasny.net/articles/suhosin-patch-for-php-53/" rel="nofollow" class="external" title="Share this on Technorati">Share this on Technorati</a>
		</li>
		<li class="sexy-googlebuzz">
			<a href="http://www.google.com/buzz/post?url=http://www.jasny.net/articles/suhosin-patch-for-php-53/&amp;imageurl=" rel="nofollow" class="external" title="Post on Google Buzz">Post on Google Buzz</a>
		</li>
		<li class="sexy-facebook">
			<a href="http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://www.jasny.net/articles/suhosin-patch-for-php-53/&amp;t=Suhosin+patch+for+PHP+5.3" rel="nofollow" class="external" title="Share this on Facebook">Share this on Facebook</a>
		</li>
		<li class="sexy-linkedin">
			<a href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://www.jasny.net/articles/suhosin-patch-for-php-53/&amp;title=Suhosin+patch+for+PHP+5.3&amp;summary=The%20hardened-php%20project%20has%20yet%20to%20release%20a%20suhosin%20patch%20for%20PHP%205.3.0.%20We%27re%20already%20using%20PHP%205.3%2C%20therefore%20I%27ve%20modified%20the%200.9.7%20patch%20for%205.2.10%20to%20work%20with%205.3.0.%0D%0A%0D%0A-%3E%20Download%20Suhosin%20patch%20for%20PHP%205.3%20&amp;source=Jasny | Arnold&#039;s wor(l)ds" rel="nofollow" class="external" title="Share this on LinkedIn">Share this on LinkedIn</a>
		</li>
		<li class="sexy-mail">
			<a href="mailto:?subject=%22Suhosin%20patch%20for%20PHP%205.3%22&amp;body=I+thought+this+article+might+interest+you.%0A%0A%22The%20hardened-php%20project%20has%20yet%20to%20release%20a%20suhosin%20patch%20for%20PHP%205.3.0.%20We%27re%20already%20using%20PHP%205.3%2C%20therefore%20I%27ve%20modified%20the%200.9.7%20patch%20for%205.2.10%20to%20work%20with%205.3.0.%0D%0A%0D%0A-%3E%20Download%20Suhosin%20patch%20for%20PHP%205.3%20%22%0A%0AYou+can+read+the+full+article+here%3A%20http://www.jasny.net/articles/suhosin-patch-for-php-53/" rel="nofollow" class="external" title="Email this to a friend?">Email this to a friend?</a>
		</li>
</ul>
<div style="clear:both;"></div>
</div>
<!-- End SexyBookmarks Menu Code -->

]]></content:encoded>
			<wfw:commentRss>http://www.jasny.net/articles/suhosin-patch-for-php-53/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Hide Gnome Panel</title>
		<link>http://www.jasny.net/articles/hide-gnome-panel/</link>
		<comments>http://www.jasny.net/articles/hide-gnome-panel/#comments</comments>
		<pubDate>Thu, 18 Jun 2009 18:17:18 +0000</pubDate>
		<dc:creator>Arnold Daniels</dc:creator>
				<category><![CDATA[Linux desktop]]></category>

		<guid isPermaLink="false">http://blog.adaniels.nl/?p=215</guid>
		<description><![CDATA[This article shows how to move Gnome Panels to the Compiz widget layer.]]></description>
			<content:encoded><![CDATA[<p>Since a few months I&#8217;ve done away with using the Gnome main menu. Instead I use <a href="http://do.davebsd.com/">Gnome Do</a>. I removed the bottom toolbar long ago, because always use alt-tab. </p>
<p>I&#8217;m not using the top toolbar much either. It was just taking up valuable screen space. I contains only the notification area and a logout button. I was looking at a way to remove it completely. The answer came in the Compiz widget layer. By placing it on the widget layer, fullsize windows actually fill the full screen, but the notification area is still available for applications who need it.</p>
<p>To move Gnome panel to the Widget layer, open &#8216;CompizConfig Settings Manager&#8217; and enable &#8216;Widget Layer&#8217;. Go to tab &#8216;Behaviour&#8217; and add the following text for the &#8216;Widget Windows&#8217; field:</p>
<pre>(class=Gnome-panel &#038; type=Dock)</pre>
<p>The desktop will now be completely clean:<br />
<a href="http://blog.adaniels.nl/wp-content/uploads/desktop-clean.png"><img src="http://blog.adaniels.nl/wp-content/uploads/desktop-clean-300x187.png" alt="Desktop clean" title="desktop-clean" width="300" height="187" class="alignnone size-medium wp-image-217" /></a></p>
<p>With <F9> we can display the widget layer, where the panel is found:<br />
<a href="http://blog.adaniels.nl/wp-content/uploads/desktop-widgets.png"><img src="http://blog.adaniels.nl/wp-content/uploads/desktop-widgets-300x187.png" alt="Desktop Widgets" title="desktop-widgets" width="300" height="187" class="alignnone size-medium wp-image-219" /></a></p>
<p>PS. The widgets you see on the widget layer are <a href="http://www.screenlets.org/index.php/Home">screenlets</a>. Ubuntu has the screenlets package in the universe repository.</p>


<!-- Begin SexyBookmarks Menu Code -->
<div class="sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-sexy">
<ul class="socials">
		<li class="sexy-twitter">
			<a href="http://twitter.com/home?status=Hide+Gnome+Panel+-+http://b2l.me/tr672+(via+@JasnyArnold)&amp;source=shareaholic" rel="nofollow" class="external" title="Tweet This!">Tweet This!</a>
		</li>
		<li class="sexy-dzone">
			<a href="http://www.dzone.com/links/add.html?url=http://www.jasny.net/articles/hide-gnome-panel/&amp;title=Hide+Gnome+Panel&amp;description=POST_SUMMARY" rel="nofollow" class="external" title="Add this to DZone">Add this to DZone</a>
		</li>
		<li class="sexy-stumbleupon">
			<a href="http://www.stumbleupon.com/submit?url=http://www.jasny.net/articles/hide-gnome-panel/&amp;title=Hide+Gnome+Panel" rel="nofollow" class="external" title="Stumble upon something good? Share it on StumbleUpon">Stumble upon something good? Share it on StumbleUpon</a>
		</li>
		<li class="sexy-reddit">
			<a href="http://reddit.com/submit?url=http://www.jasny.net/articles/hide-gnome-panel/&amp;title=Hide+Gnome+Panel" rel="nofollow" class="external" title="Share this on Reddit">Share this on Reddit</a>
		</li>
		<li class="sexy-delicious">
			<a href="http://delicious.com/post?url=http://www.jasny.net/articles/hide-gnome-panel/&amp;title=Hide+Gnome+Panel" rel="nofollow" class="external" title="Share this on del.icio.us">Share this on del.icio.us</a>
		</li>
		<li class="sexy-digg">
			<a href="http://digg.com/submit?phase=2&amp;url=http://www.jasny.net/articles/hide-gnome-panel/&amp;title=Hide+Gnome+Panel" rel="nofollow" class="external" title="Digg this!">Digg this!</a>
		</li>
		<li class="sexy-technorati">
			<a href="http://technorati.com/faves?add=http://www.jasny.net/articles/hide-gnome-panel/" rel="nofollow" class="external" title="Share this on Technorati">Share this on Technorati</a>
		</li>
		<li class="sexy-googlebuzz">
			<a href="http://www.google.com/buzz/post?url=http://www.jasny.net/articles/hide-gnome-panel/&amp;imageurl=" rel="nofollow" class="external" title="Post on Google Buzz">Post on Google Buzz</a>
		</li>
		<li class="sexy-facebook">
			<a href="http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://www.jasny.net/articles/hide-gnome-panel/&amp;t=Hide+Gnome+Panel" rel="nofollow" class="external" title="Share this on Facebook">Share this on Facebook</a>
		</li>
		<li class="sexy-linkedin">
			<a href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://www.jasny.net/articles/hide-gnome-panel/&amp;title=Hide+Gnome+Panel&amp;summary=Since%20a%20few%20months%20I%27ve%20done%20away%20with%20using%20the%20Gnome%20main%20menu.%20Instead%20I%20use%20Gnome%20Do.%20I%20removed%20the%20bottom%20toolbar%20long%20ago%2C%20because%20always%20use%20alt-tab.%20%0D%0A%0D%0AI%27m%20not%20using%20the%20top%20toolbar%20much%20either.%20It%20was%20just%20taking%20up%20valuable%20screen%20space.%20I%20contains%20only%20the%20notification%20area%20and%20a%20logout%20&amp;source=Jasny | Arnold&#039;s wor(l)ds" rel="nofollow" class="external" title="Share this on LinkedIn">Share this on LinkedIn</a>
		</li>
		<li class="sexy-mail">
			<a href="mailto:?subject=%22Hide%20Gnome%20Panel%22&amp;body=I+thought+this+article+might+interest+you.%0A%0A%22Since%20a%20few%20months%20I%27ve%20done%20away%20with%20using%20the%20Gnome%20main%20menu.%20Instead%20I%20use%20Gnome%20Do.%20I%20removed%20the%20bottom%20toolbar%20long%20ago%2C%20because%20always%20use%20alt-tab.%20%0D%0A%0D%0AI%27m%20not%20using%20the%20top%20toolbar%20much%20either.%20It%20was%20just%20taking%20up%20valuable%20screen%20space.%20I%20contains%20only%20the%20notification%20area%20and%20a%20logout%20%22%0A%0AYou+can+read+the+full+article+here%3A%20http://www.jasny.net/articles/hide-gnome-panel/" rel="nofollow" class="external" title="Email this to a friend?">Email this to a friend?</a>
		</li>
</ul>
<div style="clear:both;"></div>
</div>
<!-- End SexyBookmarks Menu Code -->

]]></content:encoded>
			<wfw:commentRss>http://www.jasny.net/articles/hide-gnome-panel/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>How I PHP: How to take a website offline.</title>
		<link>http://www.jasny.net/articles/how-i-php-how-to-take-a-website-offline/</link>
		<comments>http://www.jasny.net/articles/how-i-php-how-to-take-a-website-offline/#comments</comments>
		<pubDate>Wed, 17 Jun 2009 18:48:34 +0000</pubDate>
		<dc:creator>Arnold Daniels</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">http://blog.adaniels.nl/?p=211</guid>
		<description><![CDATA[I&#8217;ve seen a lot of methods used to take a website temporarily off-line for maintenance. Most involve a using PHP to disable the site or renaming the index file. There is however a far better method of doing this, by placing the following in the vhost file or in an .htaccess file in the document [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve seen a lot of methods used to take a website temporarily off-line for maintenance. Most involve a using PHP to disable the site or renaming the index file. There is however a far better method of doing this, by placing the following in the vhost file or in an .htaccess file in the document root:</p>
<pre>
Header always set Retry-After "Thu, 18 Jun 2009 08:00:00 +0200"
Redirect 503 /
</pre>
<p>This way you are sure no part of the site is used. Also by returning a 503 http response, search-engine crawlers will not reindex your site right at the moment it is down. You can use &#8216;ErrorDocument&#8217; to place a different text than the apache default.</p>


<!-- Begin SexyBookmarks Menu Code -->
<div class="sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-sexy">
<ul class="socials">
		<li class="sexy-twitter">
			<a href="http://twitter.com/home?status=How+I+PHP%3A+How+to+take+a+website+offline.+-+http://b2l.me/tr675+(via+@JasnyArnold)&amp;source=shareaholic" rel="nofollow" class="external" title="Tweet This!">Tweet This!</a>
		</li>
		<li class="sexy-dzone">
			<a href="http://www.dzone.com/links/add.html?url=http://www.jasny.net/articles/how-i-php-how-to-take-a-website-offline/&amp;title=How+I+PHP%3A+How+to+take+a+website+offline.&amp;description=POST_SUMMARY" rel="nofollow" class="external" title="Add this to DZone">Add this to DZone</a>
		</li>
		<li class="sexy-stumbleupon">
			<a href="http://www.stumbleupon.com/submit?url=http://www.jasny.net/articles/how-i-php-how-to-take-a-website-offline/&amp;title=How+I+PHP%3A+How+to+take+a+website+offline." rel="nofollow" class="external" title="Stumble upon something good? Share it on StumbleUpon">Stumble upon something good? Share it on StumbleUpon</a>
		</li>
		<li class="sexy-reddit">
			<a href="http://reddit.com/submit?url=http://www.jasny.net/articles/how-i-php-how-to-take-a-website-offline/&amp;title=How+I+PHP%3A+How+to+take+a+website+offline." rel="nofollow" class="external" title="Share this on Reddit">Share this on Reddit</a>
		</li>
		<li class="sexy-delicious">
			<a href="http://delicious.com/post?url=http://www.jasny.net/articles/how-i-php-how-to-take-a-website-offline/&amp;title=How+I+PHP%3A+How+to+take+a+website+offline." rel="nofollow" class="external" title="Share this on del.icio.us">Share this on del.icio.us</a>
		</li>
		<li class="sexy-digg">
			<a href="http://digg.com/submit?phase=2&amp;url=http://www.jasny.net/articles/how-i-php-how-to-take-a-website-offline/&amp;title=How+I+PHP%3A+How+to+take+a+website+offline." rel="nofollow" class="external" title="Digg this!">Digg this!</a>
		</li>
		<li class="sexy-technorati">
			<a href="http://technorati.com/faves?add=http://www.jasny.net/articles/how-i-php-how-to-take-a-website-offline/" rel="nofollow" class="external" title="Share this on Technorati">Share this on Technorati</a>
		</li>
		<li class="sexy-googlebuzz">
			<a href="http://www.google.com/buzz/post?url=http://www.jasny.net/articles/how-i-php-how-to-take-a-website-offline/&amp;imageurl=" rel="nofollow" class="external" title="Post on Google Buzz">Post on Google Buzz</a>
		</li>
		<li class="sexy-facebook">
			<a href="http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://www.jasny.net/articles/how-i-php-how-to-take-a-website-offline/&amp;t=How+I+PHP%3A+How+to+take+a+website+offline." rel="nofollow" class="external" title="Share this on Facebook">Share this on Facebook</a>
		</li>
		<li class="sexy-linkedin">
			<a href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://www.jasny.net/articles/how-i-php-how-to-take-a-website-offline/&amp;title=How+I+PHP%3A+How+to+take+a+website+offline.&amp;summary=I%27ve%20seen%20a%20lot%20of%20methods%20used%20to%20take%20a%20website%20temporarily%20off-line%20for%20maintenance.%20Most%20involve%20a%20using%20PHP%20to%20disable%20the%20site%20or%20renaming%20the%20index%20file.%20There%20is%20however%20a%20far%20better%20method%20of%20doing%20this%2C%20by%20placing%20the%20following%20in%20the%20vhost%20file%20or%20in%20an%20.htaccess%20file%20in%20the%20document%20root&amp;source=Jasny | Arnold&#039;s wor(l)ds" rel="nofollow" class="external" title="Share this on LinkedIn">Share this on LinkedIn</a>
		</li>
		<li class="sexy-mail">
			<a href="mailto:?subject=%22How%20I%20PHP%3A%20How%20to%20take%20a%20website%20offline.%22&amp;body=I+thought+this+article+might+interest+you.%0A%0A%22I%27ve%20seen%20a%20lot%20of%20methods%20used%20to%20take%20a%20website%20temporarily%20off-line%20for%20maintenance.%20Most%20involve%20a%20using%20PHP%20to%20disable%20the%20site%20or%20renaming%20the%20index%20file.%20There%20is%20however%20a%20far%20better%20method%20of%20doing%20this%2C%20by%20placing%20the%20following%20in%20the%20vhost%20file%20or%20in%20an%20.htaccess%20file%20in%20the%20document%20root%22%0A%0AYou+can+read+the+full+article+here%3A%20http://www.jasny.net/articles/how-i-php-how-to-take-a-website-offline/" rel="nofollow" class="external" title="Email this to a friend?">Email this to a friend?</a>
		</li>
</ul>
<div style="clear:both;"></div>
</div>
<!-- End SexyBookmarks Menu Code -->

]]></content:encoded>
			<wfw:commentRss>http://www.jasny.net/articles/how-i-php-how-to-take-a-website-offline/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Bye bye MySQL?</title>
		<link>http://www.jasny.net/articles/bye-bye-mysql/</link>
		<comments>http://www.jasny.net/articles/bye-bye-mysql/#comments</comments>
		<pubDate>Mon, 20 Apr 2009 14:08:21 +0000</pubDate>
		<dc:creator>Arnold Daniels</dc:creator>
				<category><![CDATA[MySQL, Sphinx and NoSQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://blog.adaniels.nl/?p=194</guid>
		<description><![CDATA[Sun will be bought by Oracle. Will this be the beginning of the end of MySQL?
MySQL has a serious market share. For that oracle has already tried to buy MySQL back in 2006. In an interview responding to the offer in 2006, MySQL chief Marten Mickos told that the reason for declining was that they [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.sun.com/third-party/global/oracle/index.jsp">Sun will be bought by Oracle</a>. Will this be the beginning of the end of MySQL?</p>
<p><a href="http://www.mysql.com/why-mysql/marketshare">MySQL has a serious market share</a>. For that oracle has already <a href="http://news.cnet.com/2100-7344_3-6040197.html">tried to buy MySQL</a> back in 2006. In an interview responding to the offer in 2006, MySQL chief Marten Mickos told that the reason for declining was that they wanted to keep MySQL an independent product. From that I assume that oracle wanted to merge Oracle DB and MySQL technology. Even though MySQL will be part of a major merger for which the rules aren&#8217;t yet clear, you might think that Oracle hasn&#8217;t changed their ideas about what they want with MySQL in the last 3 years.</p>
<p>Won&#8217;t MySQL just lose most of its market share if it become something else. Other databases like PostgreSQL have been making mayor steps and are in many expects better than MySQL. MySQL has remained to be the only serious open-source RDBMS in respects of market share though. I believe this is mainly because MySQL is known, tried and tested. This might be a fragile thing though.</p>
<p>Based on Oracle&#8217;s decision, I might just take a more serious look at PostgreSQL. Changing is usually not so nice, but change often is.</p>
<p>Any thoughts? Leave a comment or trackback.</p>


<!-- Begin SexyBookmarks Menu Code -->
<div class="sexy-bookmarks sexy-bookmarks-expand sexy-bookmarks-bg-sexy">
<ul class="socials">
		<li class="sexy-twitter">
			<a href="http://twitter.com/home?status=Bye+bye+MySQL%3F+-+http://b2l.me/tr677+(via+@JasnyArnold)&amp;source=shareaholic" rel="nofollow" class="external" title="Tweet This!">Tweet This!</a>
		</li>
		<li class="sexy-dzone">
			<a href="http://www.dzone.com/links/add.html?url=http://www.jasny.net/articles/bye-bye-mysql/&amp;title=Bye+bye+MySQL%3F&amp;description=POST_SUMMARY" rel="nofollow" class="external" title="Add this to DZone">Add this to DZone</a>
		</li>
		<li class="sexy-stumbleupon">
			<a href="http://www.stumbleupon.com/submit?url=http://www.jasny.net/articles/bye-bye-mysql/&amp;title=Bye+bye+MySQL%3F" rel="nofollow" class="external" title="Stumble upon something good? Share it on StumbleUpon">Stumble upon something good? Share it on StumbleUpon</a>
		</li>
		<li class="sexy-reddit">
			<a href="http://reddit.com/submit?url=http://www.jasny.net/articles/bye-bye-mysql/&amp;title=Bye+bye+MySQL%3F" rel="nofollow" class="external" title="Share this on Reddit">Share this on Reddit</a>
		</li>
		<li class="sexy-delicious">
			<a href="http://delicious.com/post?url=http://www.jasny.net/articles/bye-bye-mysql/&amp;title=Bye+bye+MySQL%3F" rel="nofollow" class="external" title="Share this on del.icio.us">Share this on del.icio.us</a>
		</li>
		<li class="sexy-digg">
			<a href="http://digg.com/submit?phase=2&amp;url=http://www.jasny.net/articles/bye-bye-mysql/&amp;title=Bye+bye+MySQL%3F" rel="nofollow" class="external" title="Digg this!">Digg this!</a>
		</li>
		<li class="sexy-technorati">
			<a href="http://technorati.com/faves?add=http://www.jasny.net/articles/bye-bye-mysql/" rel="nofollow" class="external" title="Share this on Technorati">Share this on Technorati</a>
		</li>
		<li class="sexy-googlebuzz">
			<a href="http://www.google.com/buzz/post?url=http://www.jasny.net/articles/bye-bye-mysql/&amp;imageurl=" rel="nofollow" class="external" title="Post on Google Buzz">Post on Google Buzz</a>
		</li>
		<li class="sexy-facebook">
			<a href="http://www.facebook.com/share.php?v=4&amp;src=bm&amp;u=http://www.jasny.net/articles/bye-bye-mysql/&amp;t=Bye+bye+MySQL%3F" rel="nofollow" class="external" title="Share this on Facebook">Share this on Facebook</a>
		</li>
		<li class="sexy-linkedin">
			<a href="http://www.linkedin.com/shareArticle?mini=true&amp;url=http://www.jasny.net/articles/bye-bye-mysql/&amp;title=Bye+bye+MySQL%3F&amp;summary=Sun%20will%20be%20bought%20by%20Oracle.%20Will%20this%20be%20the%20beginning%20of%20the%20end%20of%20MySQL%3F%0D%0A%0D%0AMySQL%20has%20a%20serious%20market%20share.%20For%20that%20oracle%20has%20already%20tried%20to%20buy%20MySQL%20back%20in%202006.%20In%20an%20interview%20responding%20to%20the%20offer%20in%202006%2C%20MySQL%20chief%20Marten%20Mickos%20told%20that%20the%20reason%20for%20declining%20was%20that%20they%20&amp;source=Jasny | Arnold&#039;s wor(l)ds" rel="nofollow" class="external" title="Share this on LinkedIn">Share this on LinkedIn</a>
		</li>
		<li class="sexy-mail">
			<a href="mailto:?subject=%22Bye%20bye%20MySQL%3F%22&amp;body=I+thought+this+article+might+interest+you.%0A%0A%22Sun%20will%20be%20bought%20by%20Oracle.%20Will%20this%20be%20the%20beginning%20of%20the%20end%20of%20MySQL%3F%0D%0A%0D%0AMySQL%20has%20a%20serious%20market%20share.%20For%20that%20oracle%20has%20already%20tried%20to%20buy%20MySQL%20back%20in%202006.%20In%20an%20interview%20responding%20to%20the%20offer%20in%202006%2C%20MySQL%20chief%20Marten%20Mickos%20told%20that%20the%20reason%20for%20declining%20was%20that%20they%20%22%0A%0AYou+can+read+the+full+article+here%3A%20http://www.jasny.net/articles/bye-bye-mysql/" rel="nofollow" class="external" title="Email this to a friend?">Email this to a friend?</a>
		</li>
</ul>
<div style="clear:both;"></div>
</div>
<!-- End SexyBookmarks Menu Code -->

]]></content:encoded>
			<wfw:commentRss>http://www.jasny.net/articles/bye-bye-mysql/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
	</channel>
</rss><!-- Dynamic page generated in 1.865 seconds. --><!-- Cached page generated by WP-Super-Cache on 2010-08-25 08:27:46 -->
