<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Not this... &#187; dbi</title>
	<atom:link href="http://blog.timbunce.org/tag/dbi/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.timbunce.org</link>
	<description>Listen. Reflect. Explore. Solve.</description>
	<lastBuildDate>Thu, 24 Dec 2009 23:16:13 +0000</lastBuildDate>
	<generator>http://wordpress.com/</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<cloud domain='blog.timbunce.org' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://www.gravatar.com/blavatar/eb188a9f7199a98e44133dc454d3873b?s=96&#038;d=http://s2.wp.com/i/buttonw-com.png</url>
		<title>Not this... &#187; dbi</title>
		<link>http://blog.timbunce.org</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://blog.timbunce.org/osd.xml" title="Not this&#8230;" />
	<atom:link rel='hub' href='http://blog.timbunce.org/?pushpress=hub'/>
		<item>
		<title>Pay no attention to that callback behind the curtain!</title>
		<link>http://blog.timbunce.org/2008/05/01/pay-no-attention-to-that-callback-behind-the-curtain/</link>
		<comments>http://blog.timbunce.org/2008/05/01/pay-no-attention-to-that-callback-behind-the-curtain/#comments</comments>
		<pubDate>Thu, 01 May 2008 10:32:13 +0000</pubDate>
		<dc:creator>TimBunce</dc:creator>
				<category><![CDATA[perl]]></category>
		<category><![CDATA[dbi]]></category>
		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://timbunce.wordpress.com/?p=38</guid>
		<description><![CDATA[So you&#8217;ve got some perl code that connects to a particular database via a particular DBI driver. You want it to connect to a different database or driver. But you can&#8217;t change that part of the code. What can you do?
I ran into this problem recently. A large application is using an old version of [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.timbunce.org&blog=2562816&post=38&subd=timbunce&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<p>So you&#8217;ve got some perl code that connects to a particular database via a particular DBI driver. You want it to connect to a different database or driver. <em>But you can&#8217;t change that part of the code.</em> What can you do?</p>
<p>I ran into this problem recently. A large application is using an old version of <a href="http://search.cpan.org/dist/DBIx-HA/">DBIx::HA</a> which doesn&#8217;t support <a href="http://search.cpan.org/perldoc?DBD::Gofer">DBD::Gofer</a>. DBIx::HA can&#8217;t be upgraded (long story, don&#8217;t ask) but I wanted to use DBD::Gofer to provide <a href="http://search.cpan.org/~timb/DBI/lib/DBD/Gofer.pm#cache">client-side caching</a> via <a href="http://search.cpan.org/perldoc?Cache::FastMmap">Cache::FastMmap</a>. (I&#8217;ll save more details of that, and the 40% reduction in database requests it gave, for another post.)</p>
<p>I needed a way for DBIx::HA to think that it was connecting to a particular driver and database, but for it to actually connect to another. Using <code>$ENV{DBI_AUTOPROXY}</code> wasn&#8217;t an option because that has global effect whereas I needed fine control over which connections were affected. It&#8217;s also fairly blunt instrument in other ways.</p>
<p>It seemed like I was stuck. Then I remembered the DBI callback mechanism &#8211; it would provide an elegant solution to this. I added it to DBI 1.49 back in November 2005 and enhanced it further in 1.55. I&#8217;d never documented it though. I think I was never quite sure it had sufficient functionality to be really useful. Now I&#8217;m sure it has.</p>
<p>The DBI callback mechanism lets you intercept, and optionally replace, <em>any</em> method call on a DBI handle. At the extreme, it lets you become a puppet master, deceiving the application in any way you want.</p>
<p><span style="text-align:center; display: block;"><a href="http://blog.timbunce.org/2008/05/01/pay-no-attention-to-that-callback-behind-the-curtain/"><img src="http://img.youtube.com/vi/YWyCCJ6B2WE/2.jpg" alt="" /></a></span></p>
<p>Here&#8217;s how the code looked (with a few irrelevant details changed):</p>
<pre>
    # The following section of code uses the DBI Callback mechanism to
    # intercept connect() calls to DBD::Sybase and, where appropriate,
    # reroute them to DBD::Gofer.
    our $in_callback;

    # get Gofer $drh and make it pretend to be named Sybase
    # to keep DBIx::HA 0.62 happy
    my $gofer_drh  = DBI-&gt;install_driver("Gofer");
    $gofer_drh-&gt;{Name} = "Sybase";

    # get the Sybase drh and install a callback to intercept connect()s
    my $sybase_drh = DBI-&gt;install_driver("Sybase");
    $sybase_drh-&gt;{Callbacks} = {
        connect =&gt; sub {
            # protect against recursion when gofer itself makes a connection
            return if $in_callback; local $in_callback = 1;

            my $drh = shift;
            my ($dsn, $u, $p, $attr) = @_;
            warn "connect via callback $drh $dsn\n" if $DEBUG;

            # we're only interested in connections to particular databases
            return unless $dsn =~ /some pattern/;

            # rewrite the DSN to connect to the same DSN via Gofer
            # using the null transport so we can use Gofer caching
            $dsn = "transport=null;dsn=dbi:Sybase(ReadOnly=1):$dsn";

            my $dbh = $gofer_drh-&gt;connect($dsn, $u, $p, $attr);

            if (not $dbh) { # gofer connection failed for some reason
                warn "connect via gofer failed: $DBI::errstr\n"
                    unless our $connect_via_gofer_err++; # warn once
                return; # DBI will now call original connect method
            }

            undef $_;    # tell DBI not to call original connect method
            return $dbh; # tell DBI to return this $dbh instead
        },
    };
</pre>
<p>So the application, via DBIx::HA, executed</p>
<p><code>&nbsp;&nbsp;$dbh = DBI-&gt;connect("dbi:Sybase:foo",...)</code></p>
<p>but what it got back was a DBD::Gofer dbh, as if the application has executed</p>
<p><code>&nbsp;&nbsp;$dbh = DBI-&gt;connect("dbi:Gofer:transport=null;dsn=dbi:Sybase(ReadOnly=1):foo",...)</code>.</p>
<p>I guess I should document the callback mechanism now. Meanwhile the closest thing  to documentation is <a href="http://search.cpan.org/src/TIMB/DBI-1.604/t/70callbacks.t">the test file</a>.</p>
<p>I&#8217;ve always enjoyed this kind of &#8220;plumbing&#8221;. If you come up with any interesting uses of DBI callbacks, do let me know.</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/timbunce.wordpress.com/38/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/timbunce.wordpress.com/38/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/timbunce.wordpress.com/38/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/timbunce.wordpress.com/38/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/timbunce.wordpress.com/38/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/timbunce.wordpress.com/38/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/timbunce.wordpress.com/38/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/timbunce.wordpress.com/38/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/timbunce.wordpress.com/38/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/timbunce.wordpress.com/38/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/timbunce.wordpress.com/38/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/timbunce.wordpress.com/38/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.timbunce.org&blog=2562816&post=38&subd=timbunce&ref=&feed=1" />]]></content:encoded>
			<wfw:commentRss>http://blog.timbunce.org/2008/05/01/pay-no-attention-to-that-callback-behind-the-curtain/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/1cf82705f5ab43c73273ab5d690866b3?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">TimBunce</media:title>
		</media:content>

		<media:content url="http://img.youtube.com/vi/YWyCCJ6B2WE/2.jpg" medium="image" />
	</item>
	</channel>
</rss>