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

<channel>
	<title>Redfin Developers&#039; Blog &#187; Michael Smedberg</title>
	<atom:link href="http://blog.redfin.com/devblog/author/michaelsmedberg/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.redfin.com/devblog</link>
	<description>Redfin Developers&#039; Blog</description>
	<lastBuildDate>Mon, 23 Jan 2012 04:49:17 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Prefetching Web Content: Trials and Tribulations</title>
		<link>http://blog.redfin.com/devblog/2011/03/prefetching_web_content_trials_and_tribulations.html</link>
		<comments>http://blog.redfin.com/devblog/2011/03/prefetching_web_content_trials_and_tribulations.html#comments</comments>
		<pubDate>Thu, 17 Mar 2011 21:43:12 +0000</pubDate>
		<dc:creator>Michael Smedberg</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.redfin.com/devblog/?p=532</guid>
		<description><![CDATA[Stoyan is totally right and I&#8217;m totally wrong (see his comment below, which reads &#8220;The thing about google maps you load is that it&#8217;s an html page. When you load html page in object tag it&#8217;s as if you put it in an iframe. It includes all markup and extra css/js/img resources.&#8221;) My test was [...]]]></description>
			<content:encoded><![CDATA[<p><a href='http://www.phpied.com/preload-cssjavascript-without-execution/'>Stoyan</a> is totally right and I&#8217;m totally wrong (see his comment below, which reads &#8220;The thing about google maps you load is that it&#8217;s an html page. When you load html page in object tag it&#8217;s as if you put it in an iframe. It includes all markup and extra css/js/img resources.&#8221;)  My test was incorrect.  I was testing with a <a href='http://maps.google.com/maps?oe=utf-8&amp;file=api&amp;v=2.193&amp;client=gme-redfin&amp;key=ABQIAAAAs8xBAcNJJYewz0__DWutVBTRtbDPQN51lWuTk2cjlljNVeQwDRSCrVHNxjeGU_CaVw6wCLKru3fHXA'>Google Maps URL</a>, but I should have been testing with a <a href='http://maps.google.com/maps/api/js?sensor=false&amp;oe=utf-8&amp;file=api&amp;v=3.3&amp;client=gme-redfin'>Google Maps API URL</a>.  I can&#8217;t explain how I used the wrong URL- I THOUGHT I copied that URL directly from our <a href='http://www.redfin.com/homes-for-sale'>web site</a>, but apparently not.</p>
<p>I&#8217;m sorry for the mistake and any confusion it may have created.</p>
<p><em>[Click below for the full content of the original post.]</em><br />
<span id="more-532"></span></p>
<p><s>There has been <a href='http://www.adequatelygood.com/2010/1/Preloading-JS-and-CSS-as-Print-Stylesheets' target='_new'>a</a> <a href='https://developer.mozilla.org/en/Link_prefetching_FAQ' target='_new'>lot</a> <a href='http://www.petefreitag.com/item/312.cfm' target='_new'>of</a> discussion of resource <a href='http://en.wikipedia.org/wiki/Link_prefetching' target='_new'>prefetching</a> for HTTP, but unfortunately all of the alternatives I&#8217;ve seen have problems.</s></p>
<p><s><br />
<h2>What Is It?</h2>
<p></s></p>
<p><s>Prefetching resources can greatly enhance the perceived performance of your web apps.  A common use of prefetching is to download images that will be used later.  For instance, the Aardvark page might link to the Bonobo page, and the Bonobo page might display a large image of Jerry the Bonobo.  If a user were reading the Aardvark page, it might be good for the browser to download Jerry&#8217;s image in preparation for when the user clicks on the link to the Bonobo page.  When the user clicks through to the Bonobo page, the browser can render the image without having to download it- Jerry&#8217;s photo can be rendered very quickly.</s></p>
<p><s>Prefetching resources can also HURT performance when done wrong.  In the worst case, the browser might download Jerry&#8217;s photo before downloading content for the Aardvark page, so a user that wants to see aardvarks is delayed.  And if the photo isn&#8217;t properly cached, the browser might have to go get Jerry&#8217;s photo AGAIN when the user goes to the Bonobo page.</s></p>
<p><s><br />
<h2>Approaches</h2>
<p></s></p>
<p><s><strong>Firefox Native Support</strong></s></p>
<p><s><a href='https://developer.mozilla.org/en/Link_prefetching_FAQ' target='_new'>Firefox</a> has a special feature just for this- including &lt;link rel=&#8217;prefetch&#8217; href=&#8217;http://www.animals.net/jerry.jpg&#8217;&gt; in your html tells Firefox to download the photo of Jerry when it gets some free time.  Firefox will NOT make the user wait for any content on the CURRENT page.  Pretty nifty.</s></p>
<p><s>Unfortunately, it doesn&#8217;t work in other browsers.</s></p>
<p><s>Worse, it triggers a <a href='http://statichtml.com/2011/link-prefetching-broken-in-chrome.html' target='_new'>BAD bug</a> in Chrome 9.  Chrome 9 will prefetch the resource, but then refuse to use it on the next page AND NOT TRY TO GET A NEW COPY.  The second page will just barf.  At least that&#8217;s what happens when the resource is Javascript.  NOTE: This seems to be fixed in Chrome 10 (and users are auto-upgraded), but wow, what a nasty bug.</s></p>
<p><s>One workaround would be to detect the User Agent on the server, and return browser specific HTML.  For Firefox, you could use link prefetching, and for other browsers you could skip it.  This is bad for a couple reasons.  First and obviously, you don&#8217;t get the benefits of resource prefetching in other browsers.  Second, if the content varies by browser, it&#8217;s hard to cache the page well (e.g. in a <a href='http://en.wikipedia.org/wiki/Content_delivery_network' target='_new'>CDN</a>.)</s></p>
<p><s><strong>Custom Javascript</strong></s></p>
<p><s><a href='http://www.phpied.com/' target='_new'>Stoyan Stefanov</a> describes a better workaround <a href='http://www.phpied.com/preload-cssjavascript-without-execution/' target='_new'>on his blog</a>.  He advocates including some client-side Javascript that&#8217;ll include the resources in a browser specific manner- via dynamic Images in IE, and via dynamic Objects in other browsers.</s></p>
<p><s>Others have jumped on this bandwagon.  The estimable <a href='http://stevesouders.com/' target='_new'>Steve Souders</a> uses this approach in his <a href='http://www.stevesouders.com/blog/2010/12/15/controljs-part-1/' target='_new'>ControlJS</a> library.  Further, it&#8217;s been adopted by <a href='https://github.com/caridy/yui3-gallery/blob/master/src/gallery-preload/js/gallery-preload.js' target='_new'>YUI</a>.</s></p>
<p><s>Unfortunately, this approach is (slightly) broken.</s></p>
<p><s>Stoyan wrote a great test case which you can see here: <a href='http://www.phpied.com/files/object-prefetch/page1.php?id=1' target='_new'>http://www.phpied.com/files/object-prefetch/page1.php?id=1</a>.  His code works perfectly for his test case.  In particular, his &#8220;page 1&#8243; will download BUT NOT EXECUTE a Javascript file (1.sleep.expires.js.)</s></p>
<p><s>I extended his test case slightly here: <a href='http://blog.redfin.com/devblog/files/2011/03/page_one_a.html' target='_new'>http://blog.redfin.com/devblog/files/2011/03/page_one_a.html</a>.  I added an additional resource- a link to Google Maps.  Unfortunately, including Google Maps breaks this code.  The code from Google Maps is executed when prefetched (in Firefox and Chrome.)  This is worse than it might seem.  First, Google Maps hasn&#8217;t been properly initialized, etc., so it throws errors (and also has other bizarre effects- in some cases it creates a hidden iframe, and sets focus to that frame!)  Second, the parsing and execution of Google Maps code takes a while, and the browser is frozen during that time.  It can be hard to tell that the code is executed, but you can verify it with a debugging proxy like <a href='http://www.charlesproxy.com/' target='_new'>Charles</a>.  If you <a href='http://blog.redfin.com/devblog/files/2011/03/page_one_a.html' target='_new'>hit the page</a>, you&#8217;ll see that your browser downloads a LOT of content from Google- a lot more than we intended to prefetch.</s></p>
<p><s><br />
<h2>Our Approach</h2>
<p></s></p>
<p><s>This is tricky- how do you get prefetching on multiple browsers without execution and without server-side logic?  We ended up using Stoyan&#8217;s approach for IE, using the &#8216;native&#8217; approach on Firefox (via a dynamic iframe), and giving up on other browsers.</s></p>
<p><s>The Javascript looks like this (using the <a href='http://dojotoolkit.org/' target='_new'>Dojo library</a>):</s></p>
<p><code><br />
var prefetchURLs = [<br />
&nbsp;&nbsp;&nbsp;&nbsp;'url1',<br />
&nbsp;&nbsp;&nbsp;&nbsp;...<br />
];<br />
dojo.addOnLoad(function() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;redfin.util.prefetchMapURLs(prefetchURLs);<br />
});</p>
<p>...</p>
<p>redfin.util.prefetchMapURLs = function(URLs) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (dojo.isIE) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setTimeout(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new function() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (var i = 0; i &lt; URLs.length; ++i) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new Image().src = URLs[i];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;500<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;else if (dojo.isFF) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var iframe = document.createElement(&#039;iframe&#039;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iframe.id = &#039;ifrm_prefetch&#039;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iframe.width=&#039;0&#039;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iframe.height=&#039;0&#039;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iframe.src=&#039;/prefetch-urls&#039;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dojo.body().appendChild(iframe);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
</code></p>
<p><s>For Firefox, the /prefetch-urls link will return HTML that uses the standard Firefox technique (&lt;link rel=&#8217;prefetch&#8217;&gt;, as discussed above.)  Firefox properly defers download until it is not busy, it doesn&#8217;t run the Javascript, etc.  For Internet Explorer, we wait a bit after onload and then download the content using Stoyan&#8217;s approach.  For other browsers, we don&#8217;t prefetch.  As other browsers start to support &lt;link rel=&#8217;prefetch&#8217;&gt; it&#8217;s easy to add support for them.</s></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.redfin.com/devblog/2011/03/prefetching_web_content_trials_and_tribulations.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Boilerplate JDBC Wrapper</title>
		<link>http://blog.redfin.com/devblog/2011/03/boilerplate_jdbc_wrapper.html</link>
		<comments>http://blog.redfin.com/devblog/2011/03/boilerplate_jdbc_wrapper.html#comments</comments>
		<pubDate>Fri, 11 Mar 2011 19:43:01 +0000</pubDate>
		<dc:creator>Michael Smedberg</dc:creator>
				<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://blog.redfin.com/devblog/?p=450</guid>
		<description><![CDATA[Boilerplate code to wrap implementations of important JDBC interfaces]]></description>
			<content:encoded><![CDATA[<p>We use <a href="http://download-llnw.oracle.com/javase/6/docs/technotes/guides/jdbc/">JDBC</a> to connect to our database, but most of our code doesn&#8217;t connect directly to JDBC.  Instead, we go through <a href="http://www.hibernate.org/">Hibernate</a>, which is great for most purposes, but can make it difficult to do low level tweaks.  We might want to do things like:</p>
<ol>
<li>Generate performance metrics per-thread, to get a SQL oriented performance profile for individual <a href="http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller">controllers</a></li>
<li>Provide a single, central location to tweak SQL before running it</li>
<li>Write unit tests that make assertions about the number or type of SQL statements that higher level code runs</li>
<li>Trace Queries and ResultSet sizes</li>
<li>Debug the SQL generated by third party libraries, and how those libraries use JDBC</li>
</ol>
<p>I wrote wrappers for the most relevant interfaces (<a href="http://download-llnw.oracle.com/javase/6/docs/api/java/sql/Driver.html">Driver</a>, <a href="http://download-llnw.oracle.com/javase/6/docs/api/java/sql/Connection.html">Connection</a>, <a href="http://download-llnw.oracle.com/javase/6/docs/api/java/sql/Statement.html">Statement</a>, <a href="http://download-llnw.oracle.com/javase/6/docs/api/java/sql/CallableStatement.html">CallableStatement</a>, <a href="http://download-llnw.oracle.com/javase/6/docs/api/java/sql/PreparedStatement.html">PreparedStatement</a>, <a href="http://download-llnw.oracle.com/javase/6/docs/api/java/sql/ResultSet.html">ResultSet</a>.)  It&#8217;s 100% boilerplate (I didn&#8217;t implement any USEFUL functionality- that&#8217;s for you to do!)  It took me a few hours, so I thought I&#8217;d share- no point in us all writing the same boilerplate over and over!  Obviously, you&#8217;ll have to tweak this code for your own purposes.</p>
<p>To use it, you would use &#8216;redfin&#8217; in your JDBC URL scheme, like this: &#8216;jdbc:redfin://blahblah&#8217;.  You&#8217;d also set your JDBC driver class to &#8216;redfin.util.jdbc.DriverWrapper&#8217;.  The exact mechanism you use to do this is obviously dependent on your environment.</p>
<p><em>[Click through to the full post for the code.]</em><br />
<span id="more-450"></span><br />
<strong>DriverWrapper.java</strong>:<br />
<code><br />
package redfin.util.jdbc;</p>
<p>import java.sql.Connection;<br />
import java.sql.Driver;<br />
import java.sql.DriverManager;<br />
import java.sql.DriverPropertyInfo;<br />
import java.sql.SQLException;<br />
import java.util.Properties;</p>
<p>public class DriverWrapper implements Driver {<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;// The class of the driver that we're wrapping<br />
&nbsp;&nbsp;&nbsp;&nbsp;//TODO: CHANGE THIS<br />
&nbsp;&nbsp;&nbsp;&nbsp;public static final String WRAPPED_DRIVER = "org.postgresql.Driver";<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;// The scheme of the driver we're wrapping.  For instance, if the JDBC URL for<br />
&nbsp;&nbsp;&nbsp;&nbsp;// the DB we want to connect to is:<br />
&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jdbc:postgresql://db_server.redfintest.com/production<br />
&nbsp;&nbsp;&nbsp;&nbsp;// then this string should be "jdbc:postgresql:"<br />
&nbsp;&nbsp;&nbsp;&nbsp;//TODO: CHANGE THIS<br />
&nbsp;&nbsp;&nbsp;&nbsp;public static final String WRAPPED_DRIVER_SCHEME = "jdbc:postgresql:";<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;// The scheme of THIS driver (the wrapper.)  Clients use this scheme when they<br />
&nbsp;&nbsp;&nbsp;&nbsp;// want to use this driver.<br />
&nbsp;&nbsp;&nbsp;&nbsp;public static final String THIS_DRIVER_SCHEME = "jdbc:redfin:";</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;private Driver wrappedDriver;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;static {<br />
&nbsp;&nbsp;&nbsp;&nbsp;    try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;        DriverManager.registerDriver(new DriverWrapper());<br />
&nbsp;&nbsp;&nbsp;&nbsp;    } catch (Exception e) {}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public DriverWrapper() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// TODO: For more flexibility, we COULD defer this, and encode this <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp;&nbsp;&nbsp;info into the driver scheme.  That way, we could allow users to <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;&nbsp;&nbsp;&nbsp;dynamically specify the underlying driver and scheme in the JDBC URL.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedDriver = (Driver) Class.forName(WRAPPED_DRIVER).newInstance();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} catch (InstantiationException e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} catch (IllegalAccessException e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} catch (ClassNotFoundException e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean acceptsURL(String url) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Remove our special stuff from the URL<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String fixedUrl = fixupUrl(url);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// If the fixed URL is the same as the original URL, then it's NOT one of<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// our URLs and we shouldn't handle it.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (fixedUrl.equals(url)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Pass the corrected URL to the underlying driver-<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// if the underlying driver can accept the URL, then we can too!<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedDriver.acceptsURL(fixedUrl);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Connection connect(String url, Properties info) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Remove our special stuff from the URL<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;url = fixupUrl(url);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// And pass through<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Connection conn = wrappedDriver.connect(url, info);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new ConnectionWrapper(conn);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public DriverPropertyInfo[] getPropertyInfo(String url, Properties info)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedDriver.getPropertyInfo(url, info);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getMajorVersion() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedDriver.getMajorVersion();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getMinorVersion() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedDriver.getMinorVersion();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean jdbcCompliant() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedDriver.jdbcCompliant();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;private String fixupUrl(String url) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (url.startsWith(THIS_DRIVER_SCHEME)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;url = WRAPPED_DRIVER_SCHEME + url.substring(THIS_DRIVER_SCHEME.length());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return url;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
</code></p>
<p><strong>ConnectionWrapper.java</strong>:<br />
<code><br />
package redfin.util.jdbc;</p>
<p>import java.sql.Array;<br />
import java.sql.Blob;<br />
import java.sql.CallableStatement;<br />
import java.sql.Clob;<br />
import java.sql.Connection;<br />
import java.sql.DatabaseMetaData;<br />
import java.sql.NClob;<br />
import java.sql.PreparedStatement;<br />
import java.sql.SQLClientInfoException;<br />
import java.sql.SQLException;<br />
import java.sql.SQLWarning;<br />
import java.sql.SQLXML;<br />
import java.sql.Savepoint;<br />
import java.sql.Statement;<br />
import java.sql.Struct;<br />
import java.util.Map;<br />
import java.util.Properties;</p>
<p>import redfin.util.stats.PerfStatsManager;</p>
<p>/**<br />
 * A wrapper for Connections generated by DriverWrapper.  See comments in DriverWrapper.<br />
 *<br />
 */<br />
public class ConnectionWrapper implements Connection {<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;private Connection wrappedConnection;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public ConnectionWrapper(Connection wrappedConnection) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.wrappedConnection = wrappedConnection;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;// Semi-copied from http://www.java2s.com/Open-Source/Java-Document/Database-JDBC-Connection-Pool/mysql/com/mysql/jdbc/jdbc2/optional/JDBC4PreparedStatementWrapper.java.htm<br />
&nbsp;&nbsp;&nbsp;&nbsp;public  T unwrap(Class iface) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    if (&nbsp;&nbsp;&nbsp;&nbsp;"java.sql.Connection".equals(iface.getName())<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;            || "java.sql.Wrapper.class".equals(iface.getName())) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;        return iface.cast(this);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedConnection.unwrap(iface);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} catch (ClassCastException cce) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new SQLException("Unable to unwrap to " + iface.toString(), cce);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean isWrapperFor(Class iface) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;    if (&nbsp;&nbsp;&nbsp;&nbsp;"java.sql.Connection".equals(iface.getName())<br />
&nbsp;&nbsp;&nbsp;&nbsp;            || "java.sql.Wrapper.class".equals(iface.getName())) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedConnection.isWrapperFor(iface);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Statement createStatement() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new StatementWrapper(this, wrappedConnection.createStatement());<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public PreparedStatement prepareStatement(String sql) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new PreparedStatementWrapper(this, wrappedConnection.prepareStatement(sql));<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public CallableStatement prepareCall(String sql) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new CallableStatementWrapper(this, wrappedConnection.prepareCall(sql));<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public String nativeSQL(String sql) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedConnection.nativeSQL(sql);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setAutoCommit(boolean autoCommit) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedConnection.setAutoCommit(autoCommit);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean getAutoCommit() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedConnection.getAutoCommit();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void commit() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedConnection.commit();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void rollback() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedConnection.rollback();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void close() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedConnection.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean isClosed() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedConnection.isClosed();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public DatabaseMetaData getMetaData() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedConnection.getMetaData();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setReadOnly(boolean readOnly) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedConnection.setReadOnly(readOnly);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean isReadOnly() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedConnection.isReadOnly();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setCatalog(String catalog) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedConnection.setCatalog(catalog);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public String getCatalog() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedConnection.getCatalog();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setTransactionIsolation(int level) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedConnection.setTransactionIsolation(level);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getTransactionIsolation() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedConnection.getTransactionIsolation();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public SQLWarning getWarnings() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedConnection.getWarnings();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void clearWarnings() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedConnection.clearWarnings();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Statement createStatement(int resultSetType, int resultSetConcurrency)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new StatementWrapper(this, wrappedConnection.createStatement(resultSetType, resultSetConcurrency));<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public PreparedStatement prepareStatement(String sql, int resultSetType,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int resultSetConcurrency) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new PreparedStatementWrapper(this, wrappedConnection.prepareStatement(sql, resultSetType, resultSetConcurrency));<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public CallableStatement prepareCall(String sql, int resultSetType,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int resultSetConcurrency) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new CallableStatementWrapper(this, wrappedConnection.prepareCall(sql, resultSetType, resultSetConcurrency));<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Map&lt;String, Class&gt; getTypeMap() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedConnection.getTypeMap();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setTypeMap(Map&lt;String, Class&gt; map) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedConnection.setTypeMap(map);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setHoldability(int holdability) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedConnection.setHoldability(holdability);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getHoldability() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedConnection.getHoldability();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Savepoint setSavepoint() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedConnection.setSavepoint();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Savepoint setSavepoint(String name) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedConnection.setSavepoint(name);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void rollback(Savepoint savepoint) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedConnection.rollback(savepoint);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void releaseSavepoint(Savepoint savepoint) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedConnection.releaseSavepoint(savepoint);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Statement createStatement(int resultSetType,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int resultSetConcurrency, int resultSetHoldability)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return  new StatementWrapper(this, wrappedConnection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability));<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public PreparedStatement prepareStatement(String sql, int resultSetType,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int resultSetConcurrency, int resultSetHoldability)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new PreparedStatementWrapper(this, wrappedConnection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability));<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public CallableStatement prepareCall(String sql, int resultSetType,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int resultSetConcurrency, int resultSetHoldability)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new CallableStatementWrapper(this, wrappedConnection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability));<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new PreparedStatementWrapper(this, wrappedConnection.prepareStatement(sql, autoGeneratedKeys));<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public PreparedStatement prepareStatement(String sql, int[] columnIndexes)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new PreparedStatementWrapper(this, wrappedConnection.prepareStatement(sql, columnIndexes));<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public PreparedStatement prepareStatement(String sql, String[] columnNames)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new PreparedStatementWrapper(this, wrappedConnection.prepareStatement(sql, columnNames));<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Clob createClob() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedConnection.createClob();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Blob createBlob() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedConnection.createBlob();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public NClob createNClob() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedConnection.createNClob();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public SQLXML createSQLXML() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedConnection.createSQLXML();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean isValid(int timeout) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedConnection.isValid(timeout);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setClientInfo(String name, String value)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws SQLClientInfoException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedConnection.setClientInfo(name, value);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setClientInfo(Properties properties)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws SQLClientInfoException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedConnection.setClientInfo(properties);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public String getClientInfo(String name) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedConnection.getClientInfo(name);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Properties getClientInfo() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedConnection.getClientInfo();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Array createArrayOf(String typeName, Object[] elements)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedConnection.createArrayOf(typeName, elements);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Struct createStruct(String typeName, Object[] attributes)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedConnection.createStruct(typeName, attributes);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
</code></p>
<p><strong>StatementWrapper.java</strong>:<br />
<code><br />
package redfin.util.jdbc;</p>
<p>import java.sql.Connection;<br />
import java.sql.ResultSet;<br />
import java.sql.SQLException;<br />
import java.sql.SQLWarning;<br />
import java.sql.Statement;</p>
<p>import redfin.util.stats.PerfStatsManager;</p>
<p>/**<br />
 * A wrapper for Statements generated by ConnectionWrapper.  See comments in DriverWrapper.<br />
 *<br />
 */<br />
public class StatementWrapper implements Statement {<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;private Connection parentConnection;<br />
&nbsp;&nbsp;&nbsp;&nbsp;private Statement wrappedStatement;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public StatementWrapper(Connection parentConnection, Statement wrappedStatement) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.parentConnection = parentConnection;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.wrappedStatement = wrappedStatement;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (PerfStatsManager.perfStatsEnabled()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerfStatsManager.getThreadLocalJDBCPerfStats().incrementNumStatements();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;// Semi-copied from http://www.java2s.com/Open-Source/Java-Document/Database-JDBC-Connection-Pool/mysql/com/mysql/jdbc/jdbc2/optional/JDBC4PreparedStatementWrapper.java.htm<br />
&nbsp;&nbsp;&nbsp;&nbsp;public  T unwrap(Class iface) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    if (&nbsp;&nbsp;&nbsp;&nbsp;"java.sql.Statement".equals(iface.getName())<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;            || "java.sql.Wrapper.class".equals(iface.getName())) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;        return iface.cast(this);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedStatement.unwrap(iface);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} catch (ClassCastException cce) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new SQLException("Unable to unwrap to " + iface.toString(), cce);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean isWrapperFor(Class iface) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;    if (&nbsp;&nbsp;&nbsp;&nbsp;"java.sql.Statement".equals(iface.getName())<br />
&nbsp;&nbsp;&nbsp;&nbsp;            || "java.sql.Wrapper.class".equals(iface.getName())) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedStatement.isWrapperFor(iface);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public ResultSet executeQuery(String sql) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new ResultSetWrapper(this, wrappedStatement.executeQuery(sql));<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int executeUpdate(String sql) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedStatement.executeUpdate(sql);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void close() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedStatement.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getMaxFieldSize() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedStatement.getMaxFieldSize();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setMaxFieldSize(int max) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedStatement.setMaxFieldSize(max);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getMaxRows() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedStatement.getMaxRows();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setMaxRows(int max) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedStatement.setMaxRows(max);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setEscapeProcessing(boolean enable) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedStatement.setEscapeProcessing(enable);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getQueryTimeout() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedStatement.getQueryTimeout();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setQueryTimeout(int seconds) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedStatement.setQueryTimeout(seconds);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void cancel() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedStatement.cancel();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public SQLWarning getWarnings() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedStatement.getWarnings();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void clearWarnings() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedStatement.clearWarnings();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setCursorName(String name) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedStatement.setCursorName(name);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean execute(String sql) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedStatement.execute(sql);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public ResultSet getResultSet() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new ResultSetWrapper(this, wrappedStatement.getResultSet());<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getUpdateCount() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedStatement.getUpdateCount();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean getMoreResults() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedStatement.getMoreResults();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setFetchDirection(int direction) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedStatement.setFetchDirection(direction);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getFetchDirection() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedStatement.getFetchDirection();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setFetchSize(int rows) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedStatement.setFetchSize(rows);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getFetchSize() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedStatement.getFetchSize();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getResultSetConcurrency() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedStatement.getResultSetConcurrency();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getResultSetType() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedStatement.getResultSetType();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void addBatch(String sql) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedStatement.addBatch(sql);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void clearBatch() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedStatement.clearBatch();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int[] executeBatch() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return = wrappedStatement.executeBatch();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Connection getConnection() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return parentConnection;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean getMoreResults(int current) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedStatement.getMoreResults(current);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public ResultSet getGeneratedKeys() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new ResultSetWrapper(this, wrappedStatement.getGeneratedKeys());<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedStatement.executeUpdate(sql, autoGeneratedKeys);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedStatement.executeUpdate(sql, columnIndexes);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int executeUpdate(String sql, String[] columnNames) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedStatement.executeUpdate(sql, columnNames);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedStatement.execute(sql, autoGeneratedKeys);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean execute(String sql, int[] columnIndexes) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedStatement.execute(sql, columnIndexes);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean execute(String sql, String[] columnNames) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedStatement.execute(sql, columnNames);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getResultSetHoldability() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedStatement.getResultSetHoldability();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean isClosed() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedStatement.isClosed();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setPoolable(boolean poolable) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedStatement.setPoolable(poolable);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean isPoolable() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedStatement.isPoolable();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
</code></p>
<p><strong>CallableStatementWrapper.java</strong>:<br />
<code><br />
package redfin.util.jdbc;</p>
<p>import java.io.InputStream;<br />
import java.io.Reader;<br />
import java.math.BigDecimal;<br />
import java.net.URL;<br />
import java.sql.Array;<br />
import java.sql.Blob;<br />
import java.sql.CallableStatement;<br />
import java.sql.Clob;<br />
import java.sql.Connection;<br />
import java.sql.Date;<br />
import java.sql.NClob;<br />
import java.sql.ParameterMetaData;<br />
import java.sql.Ref;<br />
import java.sql.ResultSet;<br />
import java.sql.ResultSetMetaData;<br />
import java.sql.RowId;<br />
import java.sql.SQLException;<br />
import java.sql.SQLWarning;<br />
import java.sql.SQLXML;<br />
import java.sql.Time;<br />
import java.sql.Timestamp;<br />
import java.util.Calendar;<br />
import java.util.Map;</p>
<p>import redfin.util.stats.PerfStatsManager;</p>
<p>
/**<br />
 * A wrapper for CallableStatements generated by ConnectionWrapper.  See comments in DriverWrapper.<br />
 *<br />
 */<br />
public class CallableStatementWrapper implements CallableStatement {<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;private Connection parentConnection;<br />
&nbsp;&nbsp;&nbsp;&nbsp;private CallableStatement wrappedCallableStatement;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public CallableStatementWrapper(Connection parentConnection, CallableStatement wrappedCallableStatement) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.parentConnection = parentConnection;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.wrappedCallableStatement = wrappedCallableStatement;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (PerfStatsManager.perfStatsEnabled()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerfStatsManager.getThreadLocalJDBCPerfStats().incrementNumStatements();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;// Semi-copied from http://www.java2s.com/Open-Source/Java-Document/Database-JDBC-Connection-Pool/mysql/com/mysql/jdbc/jdbc2/optional/JDBC4PreparedStatementWrapper.java.htm<br />
&nbsp;&nbsp;&nbsp;&nbsp;public  T unwrap(Class iface) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    if (&nbsp;&nbsp;&nbsp;&nbsp;"java.sql.CallableStatement".equals(iface.getName())<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;            || "java.sql.PreparedStatement".equals(iface.getName())<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;            || "java.sql.Statement".equals(iface.getName())<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;            || "java.sql.Wrapper.class".equals(iface.getName())) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;        return iface.cast(this);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.unwrap(iface);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} catch (ClassCastException cce) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new SQLException("Unable to unwrap to " + iface.toString(), cce);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean isWrapperFor(Class iface) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;    if (&nbsp;&nbsp;&nbsp;&nbsp;"java.sql.CallableStatement".equals(iface.getName())<br />
&nbsp;&nbsp;&nbsp;&nbsp;            || "java.sql.PreparedStatement".equals(iface.getName())<br />
&nbsp;&nbsp;&nbsp;&nbsp;            || "java.sql.Statement".equals(iface.getName())<br />
&nbsp;&nbsp;&nbsp;&nbsp;            || "java.sql.Wrapper.class".equals(iface.getName())) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.isWrapperFor(iface);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public ResultSet executeQuery() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new ResultSetWrapper(this, wrappedCallableStatement.executeQuery());<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int executeUpdate() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.executeUpdate();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setNull(int parameterIndex, int sqlType) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setNull(parameterIndex, sqlType);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setBoolean(int parameterIndex, boolean x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setBoolean(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setByte(int parameterIndex, byte x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setByte(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setShort(int parameterIndex, short x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setShort(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setInt(int parameterIndex, int x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setInt(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setLong(int parameterIndex, long x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setLong(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setFloat(int parameterIndex, float x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setFloat(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setDouble(int parameterIndex, double x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setDouble(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setBigDecimal(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setString(int parameterIndex, String x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setString(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setBytes(int parameterIndex, byte[] x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setBytes(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setDate(int parameterIndex, Date x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setDate(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setTime(int parameterIndex, Time x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setTime(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setTimestamp(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setAsciiStream(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;@SuppressWarnings("deprecation")<br />
&nbsp;&nbsp;&nbsp;&nbsp;public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setUnicodeStream(parameterIndex, x, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setBinaryStream(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void clearParameters() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.clearParameters();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setObject(parameterIndex, x, targetSqlType);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setObject(int parameterIndex, Object x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setObject(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean execute() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.execute();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void addBatch() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.addBatch();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setCharacterStream(parameterIndex, reader, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setRef(int parameterIndex, Ref x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setRef(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setBlob(int parameterIndex, Blob x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setBlob(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setClob(int parameterIndex, Clob x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setClob(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setArray(int parameterIndex, Array x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setArray(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public ResultSetMetaData getMetaData() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getMetaData();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setDate(parameterIndex, x, cal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setTime(parameterIndex, x, cal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setTimestamp(parameterIndex, x, cal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setNull(parameterIndex, sqlType, typeName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setURL(int parameterIndex, URL x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setURL(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public ParameterMetaData getParameterMetaData() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getParameterMetaData();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setRowId(int parameterIndex, RowId x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setRowId(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setNString(int parameterIndex, String value) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setNString(parameterIndex, value);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setNCharacterStream(parameterIndex, value, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setNClob(int parameterIndex, NClob value) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setNClob(parameterIndex, value);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setClob(int parameterIndex, Reader reader, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setClob(parameterIndex, reader, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setBlob(parameterIndex, inputStream, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setNClob(parameterIndex, reader, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setSQLXML(parameterIndex, xmlObject);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setObject(parameterIndex, x, targetSqlType, scaleOrLength);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setAsciiStream(parameterIndex, x, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setBinaryStream(parameterIndex, x, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setCharacterStream(parameterIndex, reader, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setAsciiStream(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setBinaryStream(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setCharacterStream(parameterIndex, reader);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setNCharacterStream(parameterIndex, value);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setClob(int parameterIndex, Reader reader) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setClob(parameterIndex, reader);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setBlob(parameterIndex, inputStream);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setNClob(int parameterIndex, Reader reader) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setNClob(parameterIndex, reader);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public ResultSet executeQuery(String sql) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new ResultSetWrapper(this, wrappedCallableStatement.executeQuery(sql));<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int executeUpdate(String sql) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return  wrappedCallableStatement.executeUpdate(sql);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void close() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getMaxFieldSize() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getMaxFieldSize();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setMaxFieldSize(int max) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setMaxFieldSize(max);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getMaxRows() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getMaxRows();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setMaxRows(int max) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setMaxRows(max);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setEscapeProcessing(boolean enable) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setEscapeProcessing(enable);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getQueryTimeout() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getQueryTimeout();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setQueryTimeout(int seconds) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setQueryTimeout(seconds);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void cancel() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.cancel();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public SQLWarning getWarnings() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getWarnings();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void clearWarnings() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.clearWarnings();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setCursorName(String name) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setCursorName(name);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean execute(String sql) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.execute(sql);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public ResultSet getResultSet() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new ResultSetWrapper(this, wrappedCallableStatement.getResultSet());<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getUpdateCount() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getUpdateCount();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean getMoreResults() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getMoreResults();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setFetchDirection(int direction) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setFetchDirection(direction);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getFetchDirection() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getFetchDirection();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setFetchSize(int rows) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setFetchSize(rows);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getFetchSize() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getFetchSize();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getResultSetConcurrency() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getResultSetConcurrency();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getResultSetType() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getResultSetType();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void addBatch(String sql) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.addBatch(sql);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void clearBatch() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.clearBatch();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int[] executeBatch() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.executeBatch();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Connection getConnection() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return parentConnection;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean getMoreResults(int current) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getMoreResults(current);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public ResultSet getGeneratedKeys() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new ResultSetWrapper(this, wrappedCallableStatement.getGeneratedKeys());<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.executeUpdate(sql, autoGeneratedKeys);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.executeUpdate(sql, columnIndexes);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int executeUpdate(String sql, String[] columnNames) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.executeUpdate(sql, columnNames);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.execute(sql, autoGeneratedKeys);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean execute(String sql, int[] columnIndexes) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.execute(sql, columnIndexes);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean execute(String sql, String[] columnNames) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.execute(sql, columnNames);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getResultSetHoldability() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getResultSetHoldability();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean isClosed() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.isClosed();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setPoolable(boolean poolable) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setPoolable(poolable);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean isPoolable() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.isPoolable();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void registerOutParameter(int parameterIndex, int sqlType) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.registerOutParameter(parameterIndex, sqlType);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void registerOutParameter(int parameterIndex, int sqlType, int scale) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.registerOutParameter(parameterIndex, sqlType, scale);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean wasNull() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.wasNull();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public String getString(int parameterIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getString(parameterIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean getBoolean(int parameterIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getBoolean(parameterIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public byte getByte(int parameterIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getByte(parameterIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public short getShort(int parameterIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getShort(parameterIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getInt(int parameterIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getInt(parameterIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public long getLong(int parameterIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getLong(parameterIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public float getFloat(int parameterIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getFloat(parameterIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public double getDouble(int parameterIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getDouble(parameterIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public BigDecimal getBigDecimal(int parameterIndex, int scale) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getBigDecimal(parameterIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public byte[] getBytes(int parameterIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getBytes(parameterIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Date getDate(int parameterIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getDate(parameterIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Time getTime(int parameterIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getTime(parameterIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Timestamp getTimestamp(int parameterIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getTimestamp(parameterIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Object getObject(int parameterIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getObject(parameterIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public BigDecimal getBigDecimal(int parameterIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getBigDecimal(parameterIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Object getObject(int parameterIndex, Map&lt;String, Class&gt; map) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getObject(parameterIndex, map);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Ref getRef(int parameterIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getRef(parameterIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Blob getBlob(int parameterIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getBlob(parameterIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Clob getClob(int parameterIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getClob(parameterIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Array getArray(int parameterIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getArray(parameterIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Date getDate(int parameterIndex, Calendar cal) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getDate(parameterIndex, cal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Time getTime(int parameterIndex, Calendar cal) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getTime(parameterIndex, cal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Timestamp getTimestamp(int parameterIndex, Calendar cal) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getTimestamp(parameterIndex, cal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void registerOutParameter(int parameterIndex, int sqlType, String typeName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.registerOutParameter(parameterIndex, sqlType, typeName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void registerOutParameter(String parameterName, int sqlType) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.registerOutParameter(parameterName, sqlType);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void registerOutParameter(String parameterName, int sqlType, int scale) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.registerOutParameter(parameterName, sqlType);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void registerOutParameter(String parameterName, int sqlType, String typeName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.registerOutParameter(parameterName, sqlType, typeName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public URL getURL(int parameterIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getURL(parameterIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setURL(String parameterName, URL val) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setURL(parameterName, val);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setNull(String parameterName, int sqlType) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setNull(parameterName, sqlType);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setBoolean(String parameterName, boolean x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setBoolean(parameterName, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setByte(String parameterName, byte x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setByte(parameterName, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setShort(String parameterName, short x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setShort(parameterName, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setInt(String parameterName, int x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setInt(parameterName, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setLong(String parameterName, long x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setLong(parameterName, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setFloat(String parameterName, float x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setFloat(parameterName, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setDouble(String parameterName, double x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setDouble(parameterName, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setBigDecimal(String parameterName, BigDecimal x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setBigDecimal(parameterName, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setString(String parameterName, String x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setString(parameterName, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setBytes(String parameterName, byte[] x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setBytes(parameterName, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setDate(String parameterName, Date x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setDate(parameterName, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setTime(String parameterName, Time x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setTime(parameterName, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setTimestamp(String parameterName, Timestamp x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setTimestamp(parameterName, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setAsciiStream(String parameterName, InputStream x, int length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setAsciiStream(parameterName, x, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setBinaryStream(String parameterName, InputStream x, int length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setBinaryStream(parameterName, x, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setObject(String parameterName, Object x, int targetSqlType, int scale) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setObject(parameterName, x, targetSqlType, scale);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setObject(String parameterName, Object x, int targetSqlType) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setObject(parameterName, x, targetSqlType);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setObject(String parameterName, Object x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setObject(parameterName, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setCharacterStream(String parameterName, Reader reader, int length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setCharacterStream(parameterName, reader, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setDate(String parameterName, Date x, Calendar cal) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setDate(parameterName, x, cal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setTime(String parameterName, Time x, Calendar cal) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setTime(parameterName, x, cal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setTimestamp(String parameterName, Timestamp x, Calendar cal) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setTimestamp(parameterName, x, cal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setNull(String parameterName, int sqlType, String typeName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setNull(parameterName, sqlType, typeName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public String getString(String parameterName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getString(parameterName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean getBoolean(String parameterName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getBoolean(parameterName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public byte getByte(String parameterName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getByte(parameterName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public short getShort(String parameterName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getShort(parameterName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getInt(String parameterName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getInt(parameterName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public long getLong(String parameterName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getLong(parameterName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public float getFloat(String parameterName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getFloat(parameterName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public double getDouble(String parameterName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getDouble(parameterName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public byte[] getBytes(String parameterName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getBytes(parameterName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Date getDate(String parameterName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getDate(parameterName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Time getTime(String parameterName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getTime(parameterName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Timestamp getTimestamp(String parameterName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getTimestamp(parameterName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Object getObject(String parameterName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getObject(parameterName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public BigDecimal getBigDecimal(String parameterName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getBigDecimal(parameterName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Object getObject(String parameterName, Map&lt;String, Class&gt; map) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getObject(parameterName, map);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Ref getRef(String parameterName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getRef(parameterName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Blob getBlob(String parameterName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getBlob(parameterName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Clob getClob(String parameterName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getClob(parameterName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Array getArray(String parameterName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getArray(parameterName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Date getDate(String parameterName, Calendar cal) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getDate(parameterName, cal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Time getTime(String parameterName, Calendar cal) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getTime(parameterName, cal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Timestamp getTimestamp(String parameterName, Calendar cal) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getTimestamp(parameterName, cal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public URL getURL(String parameterName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getURL(parameterName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public RowId getRowId(int parameterIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getRowId(parameterIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public RowId getRowId(String parameterName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getRowId(parameterName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setRowId(String parameterName, RowId x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setRowId(parameterName, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setNString(String parameterName, String value) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setNString(parameterName, value);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setNCharacterStream(String parameterName, Reader value, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setNCharacterStream(parameterName, value, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setNClob(String parameterName, NClob value) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setNClob(parameterName, value);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setClob(String parameterName, Reader reader, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setClob(parameterName, reader, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setBlob(String parameterName, InputStream inputStream, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setBlob(parameterName, inputStream, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setNClob(String parameterName, Reader reader, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setNClob(parameterName, reader, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public NClob getNClob(int parameterIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getNClob(parameterIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public NClob getNClob(String parameterName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getNClob(parameterName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setSQLXML(String parameterName, SQLXML xmlObject) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setSQLXML(parameterName, xmlObject);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public SQLXML getSQLXML(int parameterIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getSQLXML(parameterIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public SQLXML getSQLXML(String parameterName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getSQLXML(parameterName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public String getNString(int parameterIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getNString(parameterIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public String getNString(String parameterName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getNString(parameterName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Reader getNCharacterStream(int parameterIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getNCharacterStream(parameterIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Reader getNCharacterStream(String parameterName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getNCharacterStream(parameterName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Reader getCharacterStream(int parameterIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getCharacterStream(parameterIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Reader getCharacterStream(String parameterName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedCallableStatement.getCharacterStream(parameterName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setBlob(String parameterName, Blob x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setBlob(parameterName, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setClob(String parameterName, Clob x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setClob(parameterName, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setAsciiStream(String parameterName, InputStream x, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setAsciiStream(parameterName, x, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setBinaryStream(String parameterName, InputStream x, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setBinaryStream(parameterName, x, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setCharacterStream(String parameterName, Reader reader, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setCharacterStream(parameterName, reader, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setAsciiStream(String parameterName, InputStream x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setAsciiStream(parameterName, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setBinaryStream(String parameterName, InputStream x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setBinaryStream(parameterName, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setCharacterStream(String parameterName, Reader reader) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setCharacterStream(parameterName, reader);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setNCharacterStream(String parameterName, Reader value) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setNCharacterStream(parameterName, value);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setClob(String parameterName, Reader reader) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setClob(parameterName, reader);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setBlob(String parameterName, InputStream inputStream) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setBlob(parameterName, inputStream);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setNClob(String parameterName, Reader reader) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedCallableStatement.setNClob(parameterName, reader);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
}<br />
</code></p>
<p><strong>PreparedStatementWrapper.java</strong>:<br />
<code><br />
package redfin.util.jdbc;</p>
<p>import java.io.InputStream;<br />
import java.io.Reader;<br />
import java.math.BigDecimal;<br />
import java.net.URL;<br />
import java.sql.Array;<br />
import java.sql.Blob;<br />
import java.sql.Clob;<br />
import java.sql.Connection;<br />
import java.sql.Date;<br />
import java.sql.NClob;<br />
import java.sql.ParameterMetaData;<br />
import java.sql.PreparedStatement;<br />
import java.sql.Ref;<br />
import java.sql.ResultSet;<br />
import java.sql.ResultSetMetaData;<br />
import java.sql.RowId;<br />
import java.sql.SQLException;<br />
import java.sql.SQLWarning;<br />
import java.sql.SQLXML;<br />
import java.sql.Time;<br />
import java.sql.Timestamp;<br />
import java.util.Calendar;</p>
<p>import redfin.util.stats.PerfStatsManager;</p>
<p>/**<br />
 * A wrapper for PreparedStatements generated by ConnectionWrapper.  See comments in DriverWrapper.<br />
 *<br />
 */<br />
public class PreparedStatementWrapper implements PreparedStatement {<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;private Connection parentConnection;<br />
&nbsp;&nbsp;&nbsp;&nbsp;private PreparedStatement wrappedPreparedStatement;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public PreparedStatementWrapper(Connection parentConnection, PreparedStatement wrappedPreparedStatement) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.parentConnection = parentConnection;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.wrappedPreparedStatement = wrappedPreparedStatement;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (PerfStatsManager.perfStatsEnabled()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerfStatsManager.getThreadLocalJDBCPerfStats().incrementNumStatements();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;// Semi-copied from http://www.java2s.com/Open-Source/Java-Document/Database-JDBC-Connection-Pool/mysql/com/mysql/jdbc/jdbc2/optional/JDBC4PreparedStatementWrapper.java.htm<br />
&nbsp;&nbsp;&nbsp;&nbsp;public  T unwrap(Class iface) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    if (&nbsp;&nbsp;&nbsp;&nbsp;"java.sql.PreparedStatement".equals(iface.getName())<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|| "java.sql.Statement".equals(iface.getName())<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;            || "java.sql.Wrapper.class".equals(iface.getName())) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;        return iface.cast(this);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.unwrap(iface);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} catch (ClassCastException cce) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new SQLException("Unable to unwrap to " + iface.toString(), cce);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean isWrapperFor(Class iface) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;    if (&nbsp;&nbsp;&nbsp;&nbsp;"java.sql.PreparedStatement".equals(iface.getName())<br />
&nbsp;&nbsp;&nbsp;&nbsp;    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|| "java.sql.Statement".equals(iface.getName())<br />
&nbsp;&nbsp;&nbsp;&nbsp;            || "java.sql.Wrapper.class".equals(iface.getName())) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.isWrapperFor(iface);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public ResultSet executeQuery(String sql) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new ResultSetWrapper(this, wrappedPreparedStatement.executeQuery(sql));<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int executeUpdate(String sql) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.executeUpdate(sql);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void close() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getMaxFieldSize() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.getMaxFieldSize();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setMaxFieldSize(int max) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setMaxFieldSize(max);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getMaxRows() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.getMaxRows();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setMaxRows(int max) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setMaxRows(max);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setEscapeProcessing(boolean enable) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setEscapeProcessing(enable);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getQueryTimeout() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.getQueryTimeout();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setQueryTimeout(int seconds) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setQueryTimeout(seconds);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void cancel() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.cancel();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public SQLWarning getWarnings() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.getWarnings();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void clearWarnings() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.clearWarnings();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setCursorName(String name) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setCursorName(name);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean execute(String sql) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.execute(sql);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public ResultSet getResultSet() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new ResultSetWrapper(this, wrappedPreparedStatement.getResultSet());<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getUpdateCount() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.getUpdateCount();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean getMoreResults() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.getMoreResults();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setFetchDirection(int direction) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setFetchDirection(direction);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getFetchDirection() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.getFetchDirection();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setFetchSize(int rows) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setFetchSize(rows);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getFetchSize() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.getFetchSize();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getResultSetConcurrency() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.getResultSetConcurrency();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getResultSetType() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.getResultSetType();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void addBatch(String sql) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.addBatch(sql);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void clearBatch() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.clearBatch();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int[] executeBatch() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.executeBatch();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Connection getConnection() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return parentConnection;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean getMoreResults(int current) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.getMoreResults(current);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public ResultSet getGeneratedKeys() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new ResultSetWrapper(this, wrappedPreparedStatement.getGeneratedKeys());<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.executeUpdate(sql, autoGeneratedKeys);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.executeUpdate(sql, columnIndexes);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int executeUpdate(String sql, String[] columnNames) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.executeUpdate(sql, columnNames);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.execute(sql, autoGeneratedKeys);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean execute(String sql, int[] columnIndexes) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.execute(sql, columnIndexes);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean execute(String sql, String[] columnNames) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.execute(sql, columnNames);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getResultSetHoldability() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.getResultSetHoldability();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean isClosed() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.isClosed();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setPoolable(boolean poolable) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setPoolable(poolable);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean isPoolable() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.isPoolable();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public ResultSet executeQuery() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return new ResultSetWrapper(this, wrappedPreparedStatement.executeQuery());<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int executeUpdate() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.executeUpdate();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setNull(int parameterIndex, int sqlType) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setNull(parameterIndex, sqlType);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setBoolean(int parameterIndex, boolean x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setBoolean(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setByte(int parameterIndex, byte x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setByte(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setShort(int parameterIndex, short x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setShort(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setInt(int parameterIndex, int x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setInt(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setLong(int parameterIndex, long x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setLong(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setFloat(int parameterIndex, float x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setFloat(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setDouble(int parameterIndex, double x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setDouble(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setBigDecimal(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setString(int parameterIndex, String x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setString(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setBytes(int parameterIndex, byte[] x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setBytes(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setDate(int parameterIndex, Date x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setDate(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setTime(int parameterIndex, Time x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setTime(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setTimestamp(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setAsciiStream(parameterIndex, x, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;@SuppressWarnings("deprecation")<br />
&nbsp;&nbsp;&nbsp;&nbsp;public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setUnicodeStream(parameterIndex, x, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setBinaryStream(parameterIndex, x, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void clearParameters() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.clearParameters();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setObject(parameterIndex, x, targetSqlType);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setObject(int parameterIndex, Object x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setObject(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean execute() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.execute();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void addBatch() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.addBatch();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setCharacterStream(parameterIndex, reader, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setRef(int parameterIndex, Ref x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setRef(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setBlob(int parameterIndex, Blob x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setBlob(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setClob(int parameterIndex, Clob x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setClob(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setArray(int parameterIndex, Array x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setArray(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public ResultSetMetaData getMetaData() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.getMetaData();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setDate(parameterIndex, x, cal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setTime(parameterIndex, x, cal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setTimestamp(parameterIndex, x, cal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setNull(parameterIndex, sqlType, typeName);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setURL(int parameterIndex, URL x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setURL(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public ParameterMetaData getParameterMetaData() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedPreparedStatement.getParameterMetaData();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setRowId(int parameterIndex, RowId x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setRowId(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setNString(int parameterIndex, String value) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setNString(parameterIndex, value);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setNCharacterStream(parameterIndex, value, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setNClob(int parameterIndex, NClob value) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setNClob(parameterIndex, value);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setClob(int parameterIndex, Reader reader, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setClob(parameterIndex, reader, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setBlob(parameterIndex, inputStream, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setNClob(parameterIndex, reader, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setSQLXML(parameterIndex, xmlObject);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setObject(parameterIndex, x, targetSqlType, scaleOrLength);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setAsciiStream(parameterIndex, x, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setBinaryStream(parameterIndex, x, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setCharacterStream(parameterIndex, reader, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setAsciiStream(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setBinaryStream(parameterIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setCharacterStream(parameterIndex, reader);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setNCharacterStream(parameterIndex, value);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setClob(int parameterIndex, Reader reader) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setClob(parameterIndex, reader);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setBlob(parameterIndex, inputStream);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setNClob(int parameterIndex, Reader reader) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedPreparedStatement.setNClob(parameterIndex, reader);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
</code></p>
<p><strong>ResultSetWrapper.java</strong>:<br />
<code><br />
package redfin.util.jdbc;</p>
<p>import java.io.InputStream;<br />
import java.io.Reader;<br />
import java.math.BigDecimal;<br />
import java.net.URL;<br />
import java.sql.Array;<br />
import java.sql.Blob;<br />
import java.sql.Clob;<br />
import java.sql.Date;<br />
import java.sql.NClob;<br />
import java.sql.Ref;<br />
import java.sql.ResultSet;<br />
import java.sql.ResultSetMetaData;<br />
import java.sql.RowId;<br />
import java.sql.SQLException;<br />
import java.sql.SQLWarning;<br />
import java.sql.SQLXML;<br />
import java.sql.Statement;<br />
import java.sql.Time;<br />
import java.sql.Timestamp;<br />
import java.util.Calendar;<br />
import java.util.Map;</p>
<p>/**<br />
 * A wrapper for ResultSets generated by ConnectionWrapper.  See comments in DriverWrapper.<br />
 *<br />
 */<br />
public class ResultSetWrapper implements ResultSet {<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;private Statement parentStatement;<br />
&nbsp;&nbsp;&nbsp;&nbsp;private ResultSet wrappedResultSet;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;public ResultSetWrapper(Statement parentStatement, ResultSet wrappedResultSet) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.parentStatement = parentStatement;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.wrappedResultSet = wrappedResultSet;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;// Semi-copied from http://www.java2s.com/Open-Source/Java-Document/Database-JDBC-Connection-Pool/mysql/com/mysql/jdbc/jdbc2/optional/JDBC4PreparedStatementWrapper.java.htm<br />
&nbsp;&nbsp;&nbsp;&nbsp;public  T unwrap(Class iface) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    if (&nbsp;&nbsp;&nbsp;&nbsp;"java.sql.ResultSet".equals(iface.getName())<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;            || "java.sql.Wrapper.class".equals(iface.getName())) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;        return iface.cast(this);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.unwrap(iface);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} catch (ClassCastException cce) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new SQLException("Unable to unwrap to " + iface.toString(), cce);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean isWrapperFor(Class iface) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;    if (&nbsp;&nbsp;&nbsp;&nbsp;"java.sql.ResultSet".equals(iface.getName())<br />
&nbsp;&nbsp;&nbsp;&nbsp;            || "java.sql.Wrapper.class".equals(iface.getName())) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return true;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.isWrapperFor(iface);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean next() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.next();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void close() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean wasNull() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.wasNull();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public String getString(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getString(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean getBoolean(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getBoolean(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public byte getByte(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getByte(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public short getShort(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getShort(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getInt(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getInt(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public long getLong(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getLong(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public float getFloat(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getFloat(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public double getDouble(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getDouble(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;@SuppressWarnings("deprecation")<br />
&nbsp;&nbsp;&nbsp;&nbsp;public BigDecimal getBigDecimal(int columnIndex, int scale)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getBigDecimal(columnIndex, scale);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public byte[] getBytes(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getBytes(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Date getDate(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getDate(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Time getTime(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getTime(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Timestamp getTimestamp(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getTimestamp(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public InputStream getAsciiStream(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getAsciiStream(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;@SuppressWarnings("deprecation")<br />
&nbsp;&nbsp;&nbsp;&nbsp;public InputStream getUnicodeStream(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getUnicodeStream(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public InputStream getBinaryStream(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getBinaryStream(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public String getString(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getString(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean getBoolean(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getBoolean(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public byte getByte(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getByte(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public short getShort(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getShort(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getInt(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getInt(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public long getLong(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getLong(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public float getFloat(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getFloat(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public double getDouble(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getDouble(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;@SuppressWarnings("deprecation")<br />
&nbsp;&nbsp;&nbsp;&nbsp;public BigDecimal getBigDecimal(String columnLabel, int scale) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getBigDecimal(columnLabel, scale);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public byte[] getBytes(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getBytes(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Date getDate(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getDate(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Time getTime(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getTime(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Timestamp getTimestamp(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getTimestamp(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public InputStream getAsciiStream(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getAsciiStream(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;@SuppressWarnings("deprecation")<br />
&nbsp;&nbsp;&nbsp;&nbsp;public InputStream getUnicodeStream(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getUnicodeStream(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public InputStream getBinaryStream(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getBinaryStream(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public SQLWarning getWarnings() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getWarnings();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void clearWarnings() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.clearWarnings();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public String getCursorName() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getCursorName();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public ResultSetMetaData getMetaData() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getMetaData();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Object getObject(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getObject(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Object getObject(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getObject(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int findColumn(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.findColumn(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Reader getCharacterStream(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getCharacterStream(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Reader getCharacterStream(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getCharacterStream(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public BigDecimal getBigDecimal(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getBigDecimal(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public BigDecimal getBigDecimal(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getBigDecimal(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean isBeforeFirst() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.isBeforeFirst();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean isAfterLast() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.isAfterLast();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean isFirst() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.isFirst();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean isLast() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.isLast();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void beforeFirst() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.beforeFirst();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void afterLast() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.afterLast();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean first() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.first();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean last() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.last();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getRow() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getRow();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean absolute(int row) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.absolute(row);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean relative(int rows) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.relative(rows);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean previous() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.previous();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setFetchDirection(int direction) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.setFetchDirection(direction);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getFetchDirection() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getFetchDirection();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void setFetchSize(int rows) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.setFetchSize(rows);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getFetchSize() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getFetchSize();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getType() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getType();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getConcurrency() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getConcurrency();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean rowUpdated() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.rowUpdated();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean rowInserted() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.rowInserted();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean rowDeleted() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.rowDeleted();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateNull(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateNull(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateBoolean(int columnIndex, boolean x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateBoolean(columnIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateByte(int columnIndex, byte x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateByte(columnIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateShort(int columnIndex, short x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateShort(columnIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateInt(int columnIndex, int x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateInt(columnIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateLong(int columnIndex, long x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateLong(columnIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateFloat(int columnIndex, float x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateFloat(columnIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateDouble(int columnIndex, double x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateDouble(columnIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateBigDecimal(columnIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateString(int columnIndex, String x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateString(columnIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateBytes(int columnIndex, byte[] x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateBytes(columnIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateDate(int columnIndex, Date x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateDate(columnIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateTime(int columnIndex, Time x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateTime(columnIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateTimestamp(columnIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateAsciiStream(int columnIndex, InputStream x, int length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateAsciiStream(columnIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateBinaryStream(int columnIndex, InputStream x, int length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateBinaryStream(columnIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateCharacterStream(int columnIndex, Reader x, int length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateCharacterStream(columnIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateObject(int columnIndex, Object x, int scaleOrLength) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateObject(columnIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateObject(int columnIndex, Object x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateObject(columnIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateNull(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateNull(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateBoolean(String columnLabel, boolean x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateBoolean(columnLabel, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateByte(String columnLabel, byte x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateByte(columnLabel, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateShort(String columnLabel, short x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateShort(columnLabel, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateInt(String columnLabel, int x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateInt(columnLabel, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateLong(String columnLabel, long x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateLong(columnLabel, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateFloat(String columnLabel, float x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateFloat(columnLabel, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateDouble(String columnLabel, double x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateDouble(columnLabel, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateBigDecimal(String columnLabel, BigDecimal x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateBigDecimal(columnLabel, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateString(String columnLabel, String x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateString(columnLabel, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateBytes(String columnLabel, byte[] x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateBytes(columnLabel, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateDate(String columnLabel, Date x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateDate(columnLabel, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateTime(String columnLabel, Time x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateTime(columnLabel, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateTimestamp(String columnLabel, Timestamp x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateTimestamp(columnLabel, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateAsciiStream(String columnLabel, InputStream x, int length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateAsciiStream(columnLabel, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateBinaryStream(String columnLabel, InputStream x, int length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateBinaryStream(columnLabel, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateCharacterStream(String columnLabel, Reader reader,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateCharacterStream(columnLabel, reader, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateObject(String columnLabel, Object x, int scaleOrLength) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateObject(columnLabel, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateObject(String columnLabel, Object x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateObject(columnLabel, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void insertRow() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.insertRow();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateRow() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateRow();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void deleteRow() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.deleteRow();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void refreshRow() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.refreshRow();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void cancelRowUpdates() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.cancelRowUpdates();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void moveToInsertRow() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.moveToInsertRow();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void moveToCurrentRow() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.moveToCurrentRow();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Statement getStatement() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return parentStatement;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Object getObject(int columnIndex, Map&lt;String, Class&gt; map) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getObject(columnIndex, map);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Ref getRef(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getRef(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Blob getBlob(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getBlob(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Clob getClob(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getClob(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Array getArray(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getArray(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Object getObject(String columnLabel, Map&lt;String, Class&gt; map)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getObject(columnLabel, map);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Ref getRef(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getRef(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Blob getBlob(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getBlob(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Clob getClob(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getClob(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Array getArray(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getArray(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Date getDate(int columnIndex, Calendar cal) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getDate(columnIndex, cal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Date getDate(String columnLabel, Calendar cal) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getDate(columnLabel, cal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Time getTime(int columnIndex, Calendar cal) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getTime(columnIndex, cal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Time getTime(String columnLabel, Calendar cal) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getTime(columnLabel, cal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getTimestamp(columnIndex, cal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Timestamp getTimestamp(String columnLabel, Calendar cal) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getTimestamp(columnLabel, cal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public URL getURL(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getURL(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public URL getURL(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getURL(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateRef(int columnIndex, Ref x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateRef(columnIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateRef(String columnLabel, Ref x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateRef(columnLabel, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateBlob(int columnIndex, Blob x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateBlob(columnIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateBlob(String columnLabel, Blob x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateBlob(columnLabel, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateClob(int columnIndex, Clob x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateClob(columnIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateClob(String columnLabel, Clob x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateClob(columnLabel, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateArray(int columnIndex, Array x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateArray(columnIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateArray(String columnLabel, Array x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateArray(columnLabel, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public RowId getRowId(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getRowId(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public RowId getRowId(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getRowId(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateRowId(int columnIndex, RowId x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateRowId(columnIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateRowId(String columnLabel, RowId x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateRowId(columnLabel, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public int getHoldability() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getHoldability();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public boolean isClosed() throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.isClosed();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateNString(int columnIndex, String nString) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateNString(columnIndex, nString);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateNString(String columnLabel, String nString) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateNString(columnLabel, nString);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateNClob(int columnIndex, NClob nClob) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateNClob(columnIndex, nClob);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateNClob(String columnLabel, NClob nClob) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateNClob(columnLabel, nClob);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public NClob getNClob(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getNClob(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public NClob getNClob(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getNClob(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public SQLXML getSQLXML(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getSQLXML(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public SQLXML getSQLXML(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getSQLXML(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateSQLXML(columnIndex, xmlObject);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateSQLXML(String columnLabel, SQLXML xmlObject) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateSQLXML(columnLabel, xmlObject);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public String getNString(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getNString(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public String getNString(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getNString(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Reader getNCharacterStream(int columnIndex) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getNCharacterStream(columnIndex);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public Reader getNCharacterStream(String columnLabel) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return wrappedResultSet.getNCharacterStream(columnLabel);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateNCharacterStream(int columnIndex, Reader x, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateNCharacterStream(columnIndex, x, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateNCharacterStream(String columnLabel, Reader reader, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateNCharacterStream(columnLabel, reader, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateAsciiStream(int columnIndex, InputStream x, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateAsciiStream(columnIndex, x, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateBinaryStream(int columnIndex, InputStream x, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateBinaryStream(columnIndex, x, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateCharacterStream(columnIndex, x, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateAsciiStream(String columnLabel, InputStream x, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateAsciiStream(columnLabel, x, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateBinaryStream(String columnLabel, InputStream x, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateBinaryStream(columnLabel, x, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateCharacterStream(String columnLabel, Reader reader, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateCharacterStream(columnLabel, reader, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateBlob(int columnIndex, InputStream inputStream, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateBlob(columnIndex, inputStream, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateBlob(String columnLabel, InputStream inputStream, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateBlob(columnLabel, inputStream, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateClob(int columnIndex, Reader reader, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateClob(columnIndex, reader, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateClob(String columnLabel, Reader reader, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateClob(columnLabel, reader, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateNClob(columnIndex, reader, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateNClob(columnLabel, reader, length);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateNCharacterStream(columnIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateNCharacterStream(String columnLabel, Reader reader) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateNCharacterStream(columnLabel, reader);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateAsciiStream(int columnIndex, InputStream x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateAsciiStream(columnIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateBinaryStream(int columnIndex, InputStream x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateBinaryStream(columnIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateCharacterStream(int columnIndex, Reader x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateCharacterStream(columnIndex, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateAsciiStream(columnLabel, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateBinaryStream(columnLabel, x);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateCharacterStream(String columnLabel, Reader reader) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateCharacterStream(columnLabel, reader);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateBlob(columnIndex, inputStream);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateBlob(columnLabel, inputStream);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateClob(int columnIndex, Reader reader) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateClob(columnIndex, reader);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateClob(String columnLabel, Reader reader) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateClob(columnLabel, reader);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateNClob(int columnIndex, Reader reader) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateNClob(columnIndex, reader);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;public void updateNClob(String columnLabel, Reader reader) throws SQLException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wrappedResultSet.updateNClob(columnLabel, reader);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
</code></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.redfin.com/devblog/2011/03/boilerplate_jdbc_wrapper.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Service Oriented Architecture with Varnish and Edge Side Includes</title>
		<link>http://blog.redfin.com/devblog/2010/06/service_oriented_architecture_with_varnish_and_edge_side_includes.html</link>
		<comments>http://blog.redfin.com/devblog/2010/06/service_oriented_architecture_with_varnish_and_edge_side_includes.html#comments</comments>
		<pubDate>Tue, 15 Jun 2010 00:02:26 +0000</pubDate>
		<dc:creator>Michael Smedberg</dc:creator>
				<category><![CDATA[Performance]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[ESI]]></category>
		<category><![CDATA[Service Oriented Architecture]]></category>
		<category><![CDATA[SOA]]></category>
		<category><![CDATA[Varnish]]></category>
		<category><![CDATA[VCL]]></category>

		<guid isPermaLink="false">http://blog.redfin.com/devblog/?p=385</guid>
		<description><![CDATA[The Varnish HTTP Accelerator can be used to implement a Service Oriented Architecture by using Edge Side Includes]]></description>
			<content:encoded><![CDATA[<p>As <a href='http://blog.redfin.com/devblog/2010/05/esi_and_caching_trickery_in_varnish.html'>we talked about before</a>, Redfin uses <a href='http://www.varnish-cache.org/' target='_new'>Varnish</a> to implement <a href='http://en.wikipedia.org/wiki/Edge_Side_Includes' target='_new'>Edge Side Includes</a> (ESI.)  This involved breaking a single big (and expensive) page into individual chunks; each chunk would be generated by separate code, and would be cached on a different schedule.</p>
<p>Once we broke our expensive page into chunks that could be individually cached, it seemed pretty easy to have those chunks served up by different backend servers.  Voilà, a monolithic app became &#8220;<a href='http://en.wikipedia.org/wiki/Service-oriented_architecture' target='_new'>service oriented</a>&#8220;!  This would let us run the different software components on different machines (with different performance characteristics, different <a href='http://en.wikipedia.org/wiki/Service_level_agreement' target='_new'>SLAs</a>, even implementations in different languages/environments!)</p>
<p>Of course, nothing is actually that easy, and we made a number of mis-steps before we figured out how to do it.</p>
<p><a href='http://www.flickr.com/photos/dnorman/3732851541/' target='_new'><img src='http://blog.redfin.com/devblog/files/2010/06/soa_with_esi_difficult.jpg' title='more difficult than you would think' alt="soa with esi difficult Service Oriented Architecture with Varnish and Edge Side Includes" /></a></p>
<h1>How To</h1>
<p>Varnish allows you to define multiple backends in your <a href='http://www.varnish-cache.org/wiki/Introduction#TheVarnishConfigurationLanguage' target='_new'>VCL</a>.  And in your vcl_recv function, you can decide which backend should handle a particular request.  At Redfin, we added a new Varnish backend for each of our ESI endpoints, and we added logic to choose the relevant backend by URI.  In practice, we actually only have one pool of machines handling our ESI requests, so all of our Varnish backends actually point to the same place.</p>
<p>So the first piece of the puzzle is on our main web servers.  On the main web servers, requests go through Varnish.  Requests for &#8220;normal&#8221; pages are sent through to Tomcat, but requests for ESIs are sent to one of the SOA backends.  Here&#8217;s an example of what the VCL file might look like:</p>
<p><code><br />
backend default {<br />
&nbsp;&nbsp;.host = "localhost";<br />
&nbsp;&nbsp;.port = "8080";<br />
}<br />
backend similars {<br />
&nbsp;&nbsp;.host = "similars.redfin.com";<br />
&nbsp;&nbsp;.port = "6081";<br />
}<br />
backend relevantlinks {<br />
&nbsp;&nbsp;.host = "relevantlinks.redfin.com";<br />
&nbsp;&nbsp;.port = "6081";<br />
}</p>
<p>...</p>
<p>sub vcl_recv {<br />
&nbsp;&nbsp;if (req.url ~ "^/esi-listing-similars" || req.url ~ "^/esi-property-similars") {<br />
&nbsp;&nbsp;&nbsp;&nbsp;set req.backend = similars;<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;else if (req.url ~ "^/esi-listing-trackbacks") {<br />
&nbsp;&nbsp;&nbsp;&nbsp;set req.backend = relevantlinks;<br />
&nbsp;&nbsp;}<br />
</code></p>
<p>You might have noticed that the &#8220;localhost&#8221; backend is associated with port 8080 (where Tomcat is running), but the ESI backends are associated with port 6081 (where Varnish is running on those remote machines.)</p>
<p>We want the instance of Varnish on the main web server to cache content from the main web server, and the instances of Varnish on the ESI backends to cache the content from those backends.  This has a few benefits:</p>
<ul>
<li>Our effective cache is bigger, since we have caches on multiple machines, each of which has fixed memory</li>
<li>Having independent caches prevents one set of items from pushing another set out of the cache.  If all the data were in a single cache, then cache entries holding similars information (which is small, but expensive to recreate) could be pushed out of the cache by cache entries of &#8220;main page&#8221; content (which is big and relatively cheap to recreate, but we&#8217;d still like to cache.)</li>
<li>It&#8217;s easy to flush individual caches without having to worry about performance problems with other parts of the site</li>
</ul>
<p>We have another design goal: we&#8217;d like to have a single distribution of our software.  We&#8217;d like to have a single WAR that we can put on any machine; we do NOT want to have to deal with multiple builds, with figuring out which build has been installed on which machine, etc.  We&#8217;d like to be able to switch a single machine from being a standard web server to being an ESI endpoint without having to redeploy or reconfigure.</p>
<p>This creates a conundrum.  We want our main web servers and our ESI servers to be identical, but we also want them to act different.  In particular, when an instance of Varnish on a web server gets a request for an ESI fragment, it should redirect that request to an ESI server (more precisely: to the Varnish instance running on an ESI server.)  But when an instance of Varnish on an ESI server gets a request for an ESI fragment, it should forward the request to the local Tomcat instance.  It should NOT forward the request to ITSELF.  Forwarding port 6081 to port 6081 creates an infinite loop- not good.</p>
<p>We want to break the symmetry between the standard web servers and the ESI servers, and we do that by messing with the URIs.</p>
<p>We prepend our ESI URIs with a known prefix, which means &#8220;forward this to the ESI server.&#8221;  But when we process the URI (while forwarding it), we strip off that prefix, so that the ESI server does not also forward it to itself.  That&#8217;s harder to say than it is to code.  The VCL code looks like this:</p>
<p><code><br />
sub vcl_recv {<br />
&nbsp;&nbsp;if (req.url ~ "^/backend/") {<br />
&nbsp;&nbsp;&nbsp;&nbsp;set req.url = regsub(req.url, "^/backend/", "/"); </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;if (req.url ~ "^/esi-listing-similars" || req.url ~ "^/esi-property-similars") {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set req.backend = similars;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;else if (req.url ~ "^/esi-listing-trackbacks") {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set req.backend = relevantlinks;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
</code></p>
<p>This breaks the circularity.  The path of requests looks like:</p>
<ol>
<li>A requests comes into Varnish on the standard web server for /path/to/a/page</li>
<li>Varnish forwards the request to the local Tomcat instance</li>
<li>Tomcat responds with HTML that includes &lt;esi:include src=&#8221;/backend/esi-listing-similars&#8221; /&gt;</li>
<li>Varnish processes the ESI, and must make a request for /backend/esi-listing-similars</li>
<li>The Varnish instance on the standard web server strips off &#8220;/backend&#8221;, and sends a request for &#8220;/esi-listing-similars&#8221; to the ESI server</li>
<li>The Varnish instance on the ESI server gets the request for &#8220;/esi-listing-similars&#8221;</li>
<li>Since there&#8217;s no &#8220;/backend&#8221; prefix, the Varnish instance on the ESI server forwards the request to its local Tomcat instance</li>
<li>The Tomcat instance on the ESI server processes the request, and responds with the relevant HTML fragment</li>
<li>The Varnish instance on the ESI server caches the HTML fragment and returns it</li>
<li>The Varnish instance on the standard web server parses the HTML fragment into the main page content and returns it to the browser</li>
</ol>
<p>This example points out another tricky bit- how do we assure that the HTML fragment is cached by the Varnish service on the ESI server, but not by the Varnish service on the standard web server?  To handle this correctly, we add a header to the response which indicates if it&#8217;s already been cached:</p>
<p><code><br />
sub vcl_fetch {<br />
&nbsp;&nbsp;if (req.url ~ "^/esi-") {<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (obj.http.X-RF-Cached ~ "true") {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pass;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;set obj.http.X-RF-Cached = "true";<br />
</code></p>
<p>This code says &#8220;If there&#8217;s an X-RF-Cached header present, then don&#8217;t attempt to cache.  If there is NOT an X-RF-Cached header present, then add one, and attempt to cache.&#8221;  With this addition, the HTML fragments will only be cached on the first Varnish instance they pass through, which is on the ESI server in our case.</p>
<h1>How NOT To</h1>
<p>The solution described above works, and meets our requirements.  But we also tried some solutions that did NOT work.  Perhaps you can learn from our failures&#8230;</p>
<h2>Putting Absolute URIs into ESI Includes</h2>
<p>Our first thought was that we&#8217;d put absolute URIs into our ESI includes in the HTML.  For instance, we tried to put &lt;esi:include src=&#8221;http://similars.redfin.com:6081/esi-listing-similars&#8221; /&gt; into the main HTML of our page.  Varnish simply (and correctly, I think) ignores the host name and port.  Including http://similars.redfin.com:6081/esi-listing-similars will cause Varnish to act as if you included /esi-listing-similars, and Varnish will use whichever backend it thinks is relevant, regardless of the host name or port in the URI.</p>
<h2>Using a Single Server as both a Standard Web Server and an ESI Server</h2>
<p>When doing testing, or when some of our servers were unavailable, we were tempted to use a single server as both the standard web server and the ESI server.  It seemed like this should work- the trick with the &#8220;/backend&#8221; prefix should prevent infinite circularity.  However, it didn&#8217;t work.  It seems that Varnish is doing its own checks for circularity, and noticing that a single request passed through the same Varnish instance multiple times (which NORMALLY would be a problematic example of circularity, but we&#8217;ve got our clever symmetry breaker in there!)  Anyway, Varnish doesn&#8217;t allow it, and causes those semi-circular requests to fail.</p>
<p><b>P.S.</b></p>
<p>Thanks to <a href='http://www.flickr.com/photos/dnorman/' target='_new'>D&#8217;Arcy Norman</a> for the photo!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.redfin.com/devblog/2010/06/service_oriented_architecture_with_varnish_and_edge_side_includes.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Synchronous/Asynchronous Switching with Varnish</title>
		<link>http://blog.redfin.com/devblog/2010/05/synchronousasynchronous_switching_with_varnish.html</link>
		<comments>http://blog.redfin.com/devblog/2010/05/synchronousasynchronous_switching_with_varnish.html#comments</comments>
		<pubDate>Fri, 07 May 2010 21:55:36 +0000</pubDate>
		<dc:creator>Michael Smedberg</dc:creator>
				<category><![CDATA[Performance]]></category>
		<category><![CDATA[UI Design]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.redfin.com/devblog/?p=302</guid>
		<description><![CDATA[When your webapp is serving up content that&#8217;s expensive to generate, you may want to serve it up asynchronously- via AJAX calls. This is particularly appealing when content is &#8220;below the fold.&#8221; However when that content is cached, you want to serve it up as quickly as possible. If you&#8217;ve already calculated the content, you&#8217;d [...]]]></description>
			<content:encoded><![CDATA[<p>When your webapp is serving up content that&#8217;s expensive to generate, you may want to serve it up asynchronously- via <a href="http://en.wikipedia.org/wiki/AJAX" target="_new">AJAX</a> calls.  This is particularly appealing when content is &#8220;below <a href="http://en.wikipedia.org/wiki/Above_the_fold" target="_new">the fold</a>.&#8221;</p>
<p>However when that content is cached, you want to serve it up as quickly as possible.  If you&#8217;ve already calculated the content, you&#8217;d like to include it inline in the page, without requiring an AJAX roundtrip.  That way, you avoid the <a href="http://en.wikipedia.org/wiki/Latency_(engineering)" target="_new">latency</a> of an unnecessary round-trip.  You also allow the page to be fully rendered (so content doesn&#8217;t jump around), etc.</p>
<p>You can optimize for the empty cache, or you can optimize for the full cache, but it seems hard to optimize both experiences.</p>
<p>Redfin faces exactly this conundrum with our listing pages (e.g. <a href="http://www.redfin.com/CA/San-Francisco/830-El-Camino-Del-Mar-94121/home/604622" target="_new">http://www.redfin.com/CA/San-Francisco/830-El-Camino-Del-Mar-94121/home/604622</a>.)  Calculating the Similar Listings and Similar Sales is expensive and performed in real time.  We cut this <a href="http://en.wikipedia.org/wiki/Gordian_Knot" target="_new">Gordian Knot</a> through the use of the <a href="http://www.varnish-cache.org/" target="_new">Varnish</a> caching reverse proxy, along with clever use of ESI (<a href="http://en.wikipedia.org/wiki/Edge_Side_Includes" target="_new">Edge Side Includes</a>.)  For an overview of how we use Varnish at Redfin, see our <a href="http://blog.redfin.com/devblog/2010/05/esi_and_caching_trickery_in_varnish.html" target="_new">previous post</a>.</p>
<p><a href="http://en.wikipedia.org/wiki/Gordian_knot" target="_new"><img src="http://upload.wikimedia.org/wikipedia/commons/b/bb/Alexander_cuts_the_Gordian_Knot.jpg" title="Synchronous/Asynchronous Switching with Varnish" alt="Alexander cuts the Gordian Knot Synchronous/Asynchronous Switching with Varnish" /></a></p>
<p>We want to say &#8220;if there&#8217;s a cache miss, then do AJAX, but if there&#8217;s a cache hit, then just include the content.&#8221;  We have to make sure that the AJAX calls will fill the cache, such that subsequent requests will see cache hits, of course!</p>
<p>I&#8217;ll outline what the requests/responses look like for us, then I&#8217;ll include some pseudocode that supports this.</p>
<p>At the beginning of time, the cache is empty, and the browser requests information on a Listing.</p>
<table border="1" cellspacing="0" cellpadding="4">
<tr bgcolor="#e7e7e3">
<th>
			Step
		</th>
<th>
			Browser
		</th>
<th>
			Varnish
		</th>
<th>
			Backend Server
		</th>
</tr>
<tr bgcolor="#f7f7f3">
<td>
			1
		</td>
<td>
			Requests <a href="http://www.redfin.com/CA/San-Francisco/830-El-Camino-Del-Mar-94121/home/604622" target="_new">http://www.redfin.com/&#8230;/home/604622</a>
		</td>
<td>
		</td>
<td>
		</td>
</tr>
<tr>
<td>
			2
		</td>
<td>
		</td>
<td>
			Passes request to server
		</td>
<td>
		</td>
</tr>
<tr bgcolor="#f7f7f3">
<td>
			3
		</td>
<td>
		</td>
<td>
		</td>
<td>
			Returns HTML including an ESI like <em>&lt;esi:include src=&#8221;/similars?property_id=604622&#8243; /&gt;</em>
		</td>
</tr>
<tr>
<td>
			4
		</td>
<td>
		</td>
<td>
			Lookup </em>/similars?property_id=604622</em> in cache
		</td>
<td>
		</td>
</tr>
<tr bgcolor="#f7f7f3">
<td>
			5
		</td>
<td>
		</td>
<td>
			Cache lookup fails
		</td>
<td>
		</td>
</tr>
<tr>
<td>
			6
		</td>
<td>
		</td>
<td>
			Makes request to <em>/similars?property_id=604622</em>
		</td>
<td>
		</td>
</tr>
<tr bgcolor="#f7f7f3">
<td>
			7
		</td>
<td>
		</td>
<td>
		</td>
<td>
			Returns HTML for AJAX for Similars (e.g. a &lt;script&gt; block with a reference to <em>http://www.redfin.com/extranet-similars?property_id=604622</em>)<br />
			Response includes &#8220;no cache&#8221; headers
		</td>
</tr>
<tr>
<td>
			8
		</td>
<td>
		</td>
<td>
			Injects the &lt;script&gt; block into the HTML to be returned<br />
			Does NOT cache the server response
		</td>
<td>
		</td>
</tr>
<tr bgcolor="#f7f7f3">
<td>
			9
		</td>
<td>
		</td>
<td>
			Returns HTML to Browser
		</td>
<td>
		</td>
</tr>
<tr>
<td>
			10
		</td>
<td>
			Displays HTML
		</td>
<td>
		</td>
<td>
		</td>
</tr>
<tr bgcolor="#f7f7f3">
<td>
			11
		</td>
<td>
			Executes &lt;script&gt; block
		</td>
<td>
		</td>
<td>
		</td>
</tr>
<tr>
<td>
			12
		</td>
<td>
			Requests <em>http://www.redfin.com/extranet-similars?property_id=604622</em>, including a special header saying &#8220;gimme the real content&#8221;
		</td>
<td>
		</td>
<td>
		</td>
</tr>
<tr bgcolor="#f7f7f3">
<td>
			13
		</td>
<td>
		</td>
<td>
			Passes <em>/extranet-similars?property_id=604622</em> request to server
		</td>
<td>
		</td>
</tr>
<tr>
<td>
			14
		</td>
<td>
		</td>
<td>
		</td>
<td>
			Returns HTML including an ESI like <em>&lt;esi:include src=&#8221;/similars?property_id=604622&#8243; /&gt;</em>
		</td>
</tr>
<tr bgcolor="#f7f7f3">
<td>
			15
		</td>
<td>
		</td>
<td>
			Lookup <em>/similars?property_id=604622</em> in cache
		</td>
<td>
		</td>
</tr>
<tr>
<td>
			16
		</td>
<td>
		</td>
<td>
			Cache lookup fails
		</td>
<td>
		</td>
</tr>
<tr bgcolor="#f7f7f3">
<td>
			17
		</td>
<td>
		</td>
<td>
			Makes request to <em>/similars?property_id=604622</em>, passing along special &#8220;gimme the real content&#8221; header
		</td>
<td>
		</td>
</tr>
<tr>
<td>
			18
		</td>
<td>
		</td>
<td>
		</td>
<td>
			Examines request, sees special &#8220;gimme the real content&#8221; header
		</td>
</tr>
<tr bgcolor="#f7f7f3">
<td>
			19
		</td>
<td>
		</td>
<td>
		</td>
<td>
			Calculates correct HTML to display Similar Listings and Similar Sales
		</td>
</tr>
<tr>
<td>
			20
		</td>
<td>
		</td>
<td>
		</td>
<td>
			Returns HTML including &#8220;please cache this&#8221; headers
		</td>
</tr>
<tr bgcolor="#f7f7f3">
<td>
			21
		</td>
<td>
		</td>
<td>
			Injects the Similars block into the HTML to be returned<br />
			DOES cache the server response
		</td>
<td>
		</td>
</tr>
<tr>
<td>
			22
		</td>
<td>
		</td>
<td>
			Returns HTML to Browser
		</td>
<td>
		</td>
</tr>
<tr bgcolor="#f7f7f3">
<td>
			23
		</td>
<td>
			Client side Javascript injects Similars HTML into page
		</td>
<td>
		</td>
<td>
		</td>
</tr>
</table>
<p>That&#8217;s all great, but we still haven&#8217;t used the cache!  The cache entry will get used for subsequent requests for the same page, like this:</p>
<table border="1" cellspacing="0" cellpadding="4">
<tr bgcolor="#e7e7e3">
<th>
			Step
		</th>
<th>
			Browser
		</th>
<th>
			Varnish
		</th>
<th>
			Backend Server
		</th>
</tr>
<tr bgcolor="#f7f7f3">
<td>
			1
		</td>
<td>
			Requests <a href="http://www.redfin.com/CA/San-Francisco/830-El-Camino-Del-Mar-94121/home/604622" target="_new">http://www.redfin.com/&#8230;/home/604622</a>
		</td>
<td>
		</td>
<td>
		</td>
</tr>
<tr>
<td>
			2
		</td>
<td>
		</td>
<td>
			Passes request to server
		</td>
<td>
		</td>
</tr>
<tr bgcolor="#f7f7f3">
<td>
			3
		</td>
<td>
		</td>
<td>
		</td>
<td>
			Returns HTML including an ESI like <em>&lt;esi:include src=&#8221;/similars?property_id=604622&#8243; /&gt;</em>
		</td>
</tr>
<tr>
<td>
			4
		</td>
<td>
		</td>
<td>
			Lookup <em>/similars?property_id=604622</em> in cache
		</td>
<td>
		</td>
</tr>
<tr bgcolor="#f7f7f3">
<td>
			5
		</td>
<td>
		</td>
<td>
			Cache lookup SUCCEEDS
		</td>
<td>
		</td>
</tr>
<tr>
<td>
			6
		</td>
<td>
		</td>
<td>
			Injects the Similars block into the HTML to be returned
		</td>
<td>
		</td>
</tr>
<tr bgcolor="#f7f7f3">
<td>
			7
		</td>
<td>
		</td>
<td>
			Returns HTML to Browser
		</td>
<td>
		</td>
</tr>
<tr>
<td>
			8
		</td>
<td>
			Displays HTML including Similars (no AJAX calls)
		</td>
<td>
		</td>
<td>
		</td>
</tr>
</table>
<p>There are two things worth noting about this exchange.</p>
<p><strong>First</strong>, when the backend server gets a request for <em>/similars?property_id=604622</em>, it has to decide if it should be returning the real HTML, or should be returning Javascript that will retrieve the HTML via AJAX.  It makes this decision based on the value of a header passed in by the client.  When the client is making an AJAX request, it knows it better NOT get back a response that generates AJAX requests (that&#8217;d be a death spiral.)  Therefore, when it makes the AJAX request, it includes the special header.  In all other cases, the special header is NOT included.  When the header is included in a request, the server will generate the real HTML.  When the header is not included, Varnish may answer the request from cache, or it may pass through to the backend server.  If the request is fulfilled by the Varnish cache, then it&#8217;s the real HTML, but if it&#8217;s fulfilled by the backend server, it&#8217;ll be the AJAXy HTML.</p>
<p><strong>Second</strong>, there are two URLs that have to do with similars.</p>
<p><em>/similars?property_id=604622</em> is an internal-use-only URL that returns the content (either the proper HTML or the AJAX code.)</p>
<p><em>/extranet-similars?property_id=604622</em> is an externally facing URL that only returns an ESI fragment (which will subsequently be filled in by Varnish.  This way, the ESI endpoints are never available to the extranet; Varnish can get to them, but extranet clients have no need for them.  This lets us be lazy with the ESI URLs.  For example, URLs that are exposed to the extranet do extra validation to check if the user is logged in, etc.  URLs for internal use only, such as the ESI URLs, can skip that work.  This also lets us change the URLs when the property changes, to facilitate cache busting (see the &#8220;Cache busting&#8221; section in <a href="http://blog.redfin.com/devblog/2010/05/esi_and_caching_trickery_in_varnish.html" target="_new">ESI and Caching Trickery in Varnish</a> for more information.</p>
<p><strong>Pseudocode</strong></p>
<p>OK, so we know what we want the interaction to look like.  What code will make this happen?  Here&#8217;s some Javaish pseudocode that illustrates how it might work:</p>
<p><code><br />
/*<br />
Invoked for requests like http://www.redfin.com/[address]/home/[property id]<br />
*/<br />
public void handlePropertyRequest(Request request, Response response, long propId) {<br />
&nbsp;&nbsp;&nbsp;Property property = getProperty(propId);<br />
&nbsp;&nbsp;&nbsp;response.write("<em>&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;</em>" +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"<em>&lt;esi:include src='/extranet-similars?property_id=</em>&quot; +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;propId +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;<em>&amp;last_mod=</em>&quot; +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;property.getLastModified() +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"<em>'/&gt;</em>" +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"<em>&lt;/body&gt;&lt;/html&gt;</em>");<br />
}<br />
</code></p>
<p><code><br />
/*<br />
Invoked for (extranet) requests like /extranet-similars?property_id=[property id]&amp;last_mod=[date]<br />
*/<br />
public void handleExtranetSimilarsRequest(Request request, Response response, long propId) {<br />
&nbsp;&nbsp;&nbsp;Property property = getProperty(propertyId);<br />
&nbsp;&nbsp;&nbsp;response.write("<em>&lt;esi:include src='/extranet-similars?property_id=</em>&quot; +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;propId +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;<em>&amp;last_mod=</em>&quot; +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;property.getLastModified() +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"<em>'/&gt;</em>");<br />
}<br />
</code></p>
<p><code><br />
/*<br />
Invoked for (intranet) requests like /similars?property_id=[property id]&amp;last_mod=[date]<br />
*/<br />
public void handleSimilarsRequest(Request request, Response response, long propId) {<br />
&nbsp;&nbsp;&nbsp;if (null == request.getHeader("full_html")) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//This request does NOT demand that we return the actual HTML.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;We will return a script block that will fetch the HTML via AJAX.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.write("<em>&lt;script&gt;</em>" +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"<em>dojo.addOnLoad(</em>" +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"<em>function() {</em>" +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"<em>dojo.xhrGet({</em>" +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"<em>url: 'http://www.redfin.com/extranet-similars?property_id=</em>" + propId + "<em>',</em>" +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"<em>load: function(response, ioArgs){</em>" +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"<em>dojo.byId('similar_homes').innerHTML = response;</em>" +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"<em>return response;</em>" +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"<em>},</em>" +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"<em>headers: {'full_html': 'true'},</em>" +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"<em>handleAs: 'text'</em>" +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"<em>});</em>" +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"<em>}</em>" +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"<em>);</em>" +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"<em>&lt;/script&gt;</em>");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Do NOT cache the script<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.setCacheable(false);<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//This request wants the actual HTML for similars<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.write(getSimilarsHTML(propId));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//The similars HTML is cacheable- that's the whole point!<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response.setCacheable(true);<br />
&nbsp;&nbsp;&nbsp;}<br />
}<br />
</code></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.redfin.com/devblog/2010/05/synchronousasynchronous_switching_with_varnish.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>ESI and Caching Trickery in Varnish</title>
		<link>http://blog.redfin.com/devblog/2010/05/esi_and_caching_trickery_in_varnish.html</link>
		<comments>http://blog.redfin.com/devblog/2010/05/esi_and_caching_trickery_in_varnish.html#comments</comments>
		<pubDate>Tue, 04 May 2010 15:40:38 +0000</pubDate>
		<dc:creator>Michael Smedberg</dc:creator>
				<category><![CDATA[Performance]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.redfin.com/devblog/?p=269</guid>
		<description><![CDATA[Varnish is a high performance, flexible, open source HTTP accelerator. We started using Varnish at Redfin in our last major release, a few weeks ago. It&#8217;s pretty much invisible to our end users, but we&#8217;re so happy with it that we wanted to give the folks who made Varnish their props in public. It has [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.varnish-cache.org/">Varnish</a> is a high performance, flexible, open source HTTP accelerator.</p>
<p>We started using Varnish at Redfin in our last major release, a few weeks ago.  It&#8217;s pretty much invisible to our end users, but we&#8217;re so happy with it that we wanted to give the folks who made Varnish their props in public.  It has really been great!</p>
<p>Varnish combines three technologies that are really useful at Redfin:</p>
<ol>
<li>A <a href="http://en.wikipedia.org/wiki/Reverse_proxy">caching reverse proxy</a> to reduce load on our backend servers</li>
<li>ESI (<a href="http://en.wikipedia.org/wiki/Edge_Side_Includes">Edge Side Includes</a>) to break a page into snippets of HTML which can each have their own caching strategy</li>
<li>VCL (<a href="http://www.varnish-cache.org/wiki/Introduction#TheVarnishConfigurationLanguage">Varnish Configuration Language</a>) which enables fine grained control of Varnish</li>
</ol>
<p>We use Varnish to accelerate the delivery of home details pages.  When you visit the page for a home (e.g. <a href="http://www.redfin.com/CA/San-Francisco/830-El-Camino-Del-Mar-94121/home/604622">http://www.redfin.com/CA/San-Francisco/830-El-Camino-Del-Mar-94121/home/604622</a>), parts of that page are cacheable but other parts can&#8217;t be easily cached.  For example, the description of the home may be available to all users, but <a href="http://en.wikipedia.org/wiki/Multiple_Listing_Service">MLSs</a> require us to hide some historical information from users who aren&#8217;t logged in.  Further, while most of the page might be highly cacheable, the &#8220;Sites Linking to 830 El Camino Del Mar&#8221; section isn&#8217;t as easy to cache- a blog post that refers to our page (via a <a href="http://en.wikipedia.org/wiki/Trackback">trackback</a>) may come in at any time.</p>
<p>ESI nesting makes it easy to accomodate these vagaries.<br />
<a href="http://www.flickr.com/photos/odalaigh/2320059944/" target="_new"><img src="http://farm4.static.flickr.com/3207/2320059944_47b4a99f23.jpg" title="ESI and Caching Trickery in Varnish" alt="2320059944 47b4a99f23 ESI and Caching Trickery in Varnish" /></a></p>
<p>Conceptually, here&#8217;s what the HTML for our main page looks like:<br />
<code><br />
&lt;html&gt;<br />
  &lt;body&gt;<br />
    Some notes about this home</p>
<p>    Sites Linking to 830 El Camino Del Mar:<br />
    &lt;esi:include src="/esi-listing-trackbacks?listing-id=123" /&gt;</p>
<p>    Median House Values:<br />
    &lt;esi:include src="/esi-listing-regions?listing-id=123" /&gt;<br />
  &lt;/body&gt;<br />
&lt;/html&gt;<br />
</code></p>
<p>Varnish will fill in the details of each of the esi:include sections with results from the &#8220;src&#8221; URL.  In this example, a single HTTP request from the browser to Varnish will cause Varnish to make three HTTP requests to the backend server (one for the main page, one for the trackbacks, and one for the similars.)</p>
<p>Turning a single request into three requests doesn&#8217;t really help per-se, but it does enable caching.  Previous to ESI, we were unable to cache the page as a whole since the &#8220;Sites Linking to&#8221; section was uncacheable.  By breaking the page into three sections, we can support caching for some of the sections, while disallowing caching of the other sections.</p>
<p>The workflow of a request that&#8217;s partially answered from cache might look something like this:</p>
<p>1. The browser requests http://www.redfin.com/CA/San-Francisco/830-El-Camino-Del-Mar-94121/home/604622<br />
2. Varnish receives that request, and looks up the URL in its cache<br />
3. Varnish finds a match in the cache, so it doesn&#8217;t send the request for /CA/San-Francisco/830-El-Camino-Del-Mar-94121/home/604622 through to the backend.  Instead it retrieves the content from the cache, and searches it for ESI tags.<br />
4. Varnish finds the ESI include for /esi-listing-trackbacks?listing-id=123<br />
5. Varnish looks up /esi-listing-trackbacks?listing-id=123 in the cache.  There&#8217;s no entry, so Varnish requests /esi-listing-trackbacks?listing-id=123 from the backend.<br />
6. The backend calculates the content for /esi-listing-trackbacks?listing-id=123 and returns it (along with <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9">cache control headers</a> specifying that the results should not be cached)<br />
7. Varnish likewise retrieves the results for /esi-listing-regions?listing-id=123<br />
8. Varnish knits the three HTML snippets together and returns the results to the browser</p>
<p>The big win here is that ESI allows us to cache the main body of the page, even though the trackbacks cannot be cached.  This is a tricky bit, so I&#8217;ll repeat it.  The &#8220;outer&#8221; HTML, which is the main body of the page, is cached.  But the &#8220;inner&#8221; HTML, the HTML for trackbacks, is NOT cached.  The cache of the outer content doesn&#8217;t include the inner content- it just includes a token saying &#8220;fill in this inner content before you use this cache entry.&#8221;</p>
<p>Of course, that&#8217;s just the simplest case.  In practice, we faced a number of minor challenges while implementing this.</p>
<p>1. Recording every hit</p>
<p>We have two conflicting goals.  On the one hand, we&#8217;d like to serve content up from cache as often as reasonable- users get the content faster, and our backend systems scale better.  On the other hand, we&#8217;d like to record every page hit.  Whenever a user views a page describing a listing, we record various information.  We would like every request to get through Varnish and into our backend, so that we can record this information.<br />
As with nearly every problem in Computer Science, this is solved by adding a layer of code.  In this case, the &#8220;outer&#8221; request is NEVER cached, but all it does is record the hit and generate an ESI include.  The &#8220;inner&#8221; request does the heavy lifting, but responses are cached.  For example, the user might request <a href="http://www.redfin.com/CA/San-Francisco/830-El-Camino-Del-Mar-94121/home/604622">http://www.redfin.com/CA/San-Francisco/830-El-Camino-Del-Mar-94121/home/604622</a> which would result in this &#8220;outer&#8221; response:<br />
<code><br />
Cache-Control: max-age=0</p>
<p>&lt;esi:include src="/esi-display-listing?cache-for-logged-out&amp;listing-id=604622" /&gt;<br />
</code><br />
which would in turn generate a cache lookup for /esi-display-listing?cache-for-logged-out&amp;listing-id=123.  If that&#8217;s cached, it&#8217;s fast.  If it&#8217;s not cached, we gotta do all the work.</p>
<p>2. Caching public content without caching user-specific content</p>
<p>The main page content for a home (e.g. <a href="http://www.redfin.com/CA/San-Francisco/830-El-Camino-Del-Mar-94121/home/604622">http://www.redfin.com/CA/San-Francisco/830-El-Camino-Del-Mar-94121/home/604622</a>) is the same for all anonymous users.  However, users that are logged in will see additional details, such as whether or not that home is a &#8220;favorite.&#8221;  Thus, it&#8217;s easy to cache for anonymous users, but harder to cache for logged in users (we don&#8217;t cache the main page content for logged in users.)  It&#8217;s easy enough to set the cache-control response headers such that Varnish won&#8217;t cache content for logged in users.  But we wanted to optimize a bit more- we wanted to avoid even attempting cache lookups when the user is logged in.  We did this by adding VCL which examines the incoming request.  If the request includes cookies that indicate the user is logged in, we skip the cache lookup.  We also put a special token into the URL to make it easy for the VCL logic to know that it should do this magic for the request (since the URLs are ESI URLs, they&#8217;re not visible to the extranet.)  Here&#8217;s what the VCL looks like:<br />
<code><br />
sub vcl_recv {<br />
&nbsp;&nbsp;&nbsp;&nbsp;...<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (req.http.Cookie ~ "RF_AUTH") {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set req.http._rf_login = regsub( req.http.Cookie, "^.*?RF_PARTY_ID=([^;]*?);*.*$", "\1" );<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;# cookies by default make requests in Varnish uncacheable<br />
&nbsp;&nbsp;&nbsp;&nbsp;unset req.http.Cookie;<br />
&nbsp;&nbsp;&nbsp;&nbsp;...<br />
&nbsp;&nbsp;&nbsp;&nbsp;if (req.url ~ "cache-for-logged-out") {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#Directive says to use cache for logged out users, but not for logged in users<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (req.http._rf_login) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#Since there's an RF_AUTH, the user is logged in- do not use cache<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pass;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#The user is NOT logged in- use cache (but do not look up based on cookies)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lookup;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;...<br />
}<br />
</code></p>
<p>3. Cache busting</p>
<p>We&#8217;d like to cache HTML describing a listing for a long time (24 hours), but when we get new listing data, we want to show that to users immediately.</p>
<p>One approach is to explicitly invalidate any cache entries that refer to the listing.  We could identify all Varnish instances that might cache the data and individually invalidate the content in each one.  However, that&#8217;s a little difficult to do from Java, it may be unreliable (it requires that we keep good records about all Varnish instances), and it&#8217;s generally a PITA.</p>
<p>Instead, we include the last modified time of the listing in the URL.  Again, the ESI URLs are internal, so this doesn&#8217;t dirty our extranet URLs.  My earlier example was incomplete.  A request for http://www.redfin.com/CA/San-Francisco/830-El-Camino-Del-Mar-94121/home/604622 might generate a response that looks like this:<br />
<code><br />
&lt;esi:include src="/esi-display-listing?cache-for-logged-out&amp;listing-id=604622&amp;<strong>last-mod=1272651333452</strong>" /&gt;<br />
</code><br />
(note the &#8220;last-mod&#8221; argument, which represents that last modification date of the Listing.)  That way, whenever the listing changes, the URL to the main ESI fragment will change- stale cache entries will be orphaned.</p>
<p>4. Tuning Varnish</p>
<p>When we initially deployed Varnish, we were seeing 503 errors- Varnish was returning 503 Service Unavailable errors.  Michael Young (our intrepid CTO) changed many of the Varnish settings, including connect_timeout, sess_workspace, thread_pool_min, and thread_pool_max.  The most important thing he did was match the Varnish threads to our expected traffic, and the 503 errors went away (pretty much.)</p>
<p>P.S.  Thanks to <a href="http://www.flickr.com/photos/odalaigh/">Odalaigh</a> for the gorgeous image</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.redfin.com/devblog/2010/05/esi_and_caching_trickery_in_varnish.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Laziness (in proxies) is a virtue</title>
		<link>http://blog.redfin.com/devblog/2009/12/laziness_in_proxies_is_a_virtue.html</link>
		<comments>http://blog.redfin.com/devblog/2009/12/laziness_in_proxies_is_a_virtue.html#comments</comments>
		<pubDate>Tue, 29 Dec 2009 16:52:06 +0000</pubDate>
		<dc:creator>Michael Smedberg</dc:creator>
				<category><![CDATA[Performance]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.redfin.com/devblog/?p=218</guid>
		<description><![CDATA[In Hibernate, when you indicate that a domain object should not support lazy proxies, you make it hard for DAO writers to get their code to perform well. Worse, you disable a capability that they may be counting on, and they may not notice until there are major performance problems. Unless you have a good reason to, use “@Proxy(lazy = true)” on your domain objects.]]></description>
			<content:encoded><![CDATA[<p>We use <a href="https://www.hibernate.org/" target="_new">Hibernate</a> for object-relational mapping (ORM) and organize our code into <a href="http://en.wikipedia.org/wiki/Business_object_%28computer_science%29" target="_new">domain objects</a> and <a href="http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html" target="_new">data access objects</a>.</p>
<p>Historically many of our domain objects have been marked with the &#8220;<a href="http://docs.jboss.org/hibernate/stable/annotations/api/org/hibernate/annotations/Proxy.html" target="_new">@Proxy(lazy = false)</a>&#8221; Hibernate annotation.  This annotation tells Hibernate that it should NOT create lazy proxies for the annotated class.</p>
<p>At Redfin, these were almost all bugs.  We should never use &#8220;@Proxy(lazy = false)&#8221; without a big comment explaining why it&#8217;s necessary.  Our default should be &#8220;@Proxy(lazy = true)&#8221;.  Laziness is good!</p>
<p><a href="http://www.carloneworld.it/" target="_new"><img src="http://blog.redfin.com/devblog/files/2009/12/lazy-cat5.jpg" alt="Lazy" width="700" height="525" class="size-full wp-image-249" title="Laziness (in proxies) is a virtue" /></a></p>
<p>Here&#8217;s my quick understanding of the effects of the @Proxy annotation.  As with everything in Hibernate, each individual piece seems simple, but when you consider all the features that Hibernate exposes, and how they interact, it can become pretty complicated.</p>
<p><strong>Hibernate Load Options</strong></p>
<p>When Hibernate loads objects that refer to other objects (i.e. have member objects), it needs to do something about the associated objects.  For example, suppose that Cat objects contain (optional) references to Owner objects.  When Hibernate is loading a Cat object into memory, it has to decide what to do about the Owner member variable.  There are a number of things it COULD do:</p>
<ol>
<li>When it constructs SQL to load the Cat, it could include the Owner table and columns in the SELECT clause, so that all the data is loaded at once</li>
<li>It could load the Cat object, and subsequently load the Owner object (via a second SQL statement)</li>
<li>It could load the Cat object, and set the Owner member to a placeholder (a proxy), which can be filled in later when the Owner information is needed</li>
</ol>
<p>Note that it CANNOT simply do nothing about the Owner- if it instantiates a Cat and leaves the Owner member null when the DB says that the Cat DOES have an Owner, then consumers of the Cat will be misinformed- they&#8217;ll think that the Cat has no Owner, which is false.</p>
<p>Option 1 (get all the info in 1 SQL statement) is efficient when loading multiple Cats for which the Owner information is needed.  For example, if some code needed to iterate over 1000 Cats, and get Owner information for each one, this approach would be efficient.</p>
<p>However, option 1 is inefficient in cases where the secondary information is not needed.  E.g. if some code needed to iterate over 1000 Cats but did NOT need to get Owner information, then loading the Owner information is an obvious inefficiency.</p>
<p>Worse, taking option 1 to the extreme can cause an explosion in the data load.  For example, a Cat might have an Owner, the Owner might have a Home, the Home might have a Address, which might have a City, which might have a State, etc.  Loading the whole object graph into memory via SQL could be very inefficient.  Further, every change to domain objects could cause many SQL statements to get hairier (e.g. adding a Country member to the State object would effectively add to the SQL needed to load Cat objects.)</p>
<p>Option 2 (load the Cat, then load the Owner) is simple, and often not bad, but never optimal (if you know you&#8217;ll need the Owner info, it&#8217;s more efficient to load it in a single SQL statement; if you know you won&#8217;t use it you should never load it; if you won&#8217;t know until later, delaying the load is better.)</p>
<p>However, option 2 is particularly bad when bulk operations are being performed.  For instance, if some code were to load up every Cat object in the database to do some processing, this could be accomplished via a single SQL statement (though it&#8217;d probably be better to break it into chunks of, say, 10,000 Cat objects.)  However, Hibernate would run a &#8220;SELECT * FROM owners&#8221; type statement for every Cat object that has an Owner- potentially millions of SQL statements.</p>
<p>Option 3 (load the Cat and set it&#8217;s Owner member variable to a proxy- load the Owner info on demand) is a compromise.  It allows code to do bulk operations without loading the ancillary information (e.g. load all Cat objects without ever loading any Owner objects.)  However, it requires additional SQL statements to load the secondary information IF that info is needed (e.g. if code loaded all Cat objects, then accessed the Owner for each Cat, option 3 would result in potentially millions of SQL statements.)  Note that if the Owner information is never needed, then option 3 is most efficient- the information is never loaded.</p>
<p>Hibernate allows programmers to influence which strategy it will take.  It offers (at least) two types of control: direct control over the SQL it generates, and control over the proxies.</p>
<p>See <a href="https://www.hibernate.org/315.html" target="_new">https://www.hibernate.org/315.html</a> and <a href="https://www.hibernate.org/162.html" target="_new">https://www.hibernate.org/162.html</a> for information on Hibernate fetching strategies and lazy loading.</p>
<p><strong>Controlling SQL</strong></p>
<p>When you&#8217;re implementing a DAO method, you can tell Hibernate whether it should proactively fetch information about member objects.</p>
<p>Under the <a href="http://docs.jboss.org/hibernate/core/3.3/reference/en/html/querycriteria.html" target="_new">Criteria API</a>, Hibernate lets you call <a href="http://docs.jboss.org/hibernate/core/3.3/reference/en/html/querycriteria.html#querycriteria-dynamicfetching" target="_new">criteria.setFetchMode</a> to tell Hibernate that it should load the additional info immediately, or should defer it.  Hibernate uses the term &#8220;eager&#8221; to mean &#8220;load immediately&#8221;, and &#8220;lazy&#8221; to mean &#8220;defer loading.&#8221;</p>
<p>When using <a href="http://docs.jboss.org/hibernate/core/3.3/reference/en/html/queryhql.html" target="_new">HQL</a>, you can use the <a href="http://docs.jboss.org/hibernate/core/3.3/reference/en/html/queryhql.html#queryhql-joins" target="_new">FETCH</a> keyword to specify the fetch mode, which is equivalent.</p>
<p>When using SQL, you can use the <a href="http://docs.jboss.org/hibernate/core/3.3/reference/en/html/querysql.html#d0e13732" target="_new">query.addJoin</a> method to tell Hibernate that you&#8217;ve written SQL which retrieves information for member objects.  In this case, you&#8217;ll be responsible for writing the joins, etc., yourself.</p>
<p><strong>Controlling Proxies</strong></p>
<p>Hibernate also lets you control the existence and behavior of proxies via the tags mentioned above.  Annotating a class with &#8220;@Proxy(lazy = false)&#8221; tells Hibernate to NOT support lazy proxies for that type of object (of course &#8220;@Proxy(lazy = true)&#8221; tells Hibernate to support lazy proxies.)  This allows the writer of the domain object to essentially override the wishes of the writer of the DAO.  If the DAO writer would like to load members in a lazy manner, but the domain object in question doesn&#8217;t support lazy loading, then Hibernate will NOT lazy load the object (since it cannot.)</p>
<p>If you&#8217;re writing a class for which lazy loading would be dangerous, then you SHOULD disallow lazy proxies, since DAO writers probably won&#8217;t understand the detailed load requirements of your class.  However, this is unusual.  In most cases, lazy proxies are safe.</p>
<p>Since the writer of the domain object can control what choices are available to the writer of the DAO object, they need to use that power judiciously.  You CAN code all of your domain objects to disallow lazy loading, which will force all writers of DAOs to use load options 1 or 2 (load all members via fancy SQL, or load all members via secondary SQL statements.)  But you generally should not.  DAO writers often rely on option 3 (lazy loading), particularly when they know that the member objects will never be accessed (or when they&#8217;re not sure.)  If you specify &#8220;@Proxy(lazy = false)&#8221;, you&#8217;ve made it impossible for DAO writers to use option 3, which means it may be difficult for them to get their code to perform well.  Worse, the writer of the DAO may not realize that you did that, or may not understand the implications.  Hibernate queries are actually kinda hard to view, so the writer of the DAO may have created a huge performance problem and not even known it (until you go into production.)</p>
<p><strong>Only the client really knows</strong></p>
<p>Even the writer of the DAO doesn&#8217;t know how the client will use the objects it returns.  If you&#8217;re implementing the CatDAO, you might add a method like <a href="http://en.wikipedia.org/wiki/Basement_Cat#Ceiling_Cat_and_Basement_Cat" target="_new">getBasementCatsAndOwners</a>, which would return all black cats and pre-fetch the corresponding owners.  You think you&#8217;re clever because you&#8217;ve avoided a major performance problem, but a caller might try to get the Home for each Owner, defeating your pre-fetching strategy.  The DAO writer should do their best to anticipate the needs of their callers, and to name and document their methods such that callers can understand what they do, but ultimately the caller is in control, and can (unintentionally) defeat the optimizations of the DAO writer.  If your database were large and you knew that you had clients that sometimes needed Owners, sometimes needed Owners and Homes, etc., you might make three methods: CatDAO.getBasementCats, CatDAO.getBasementCatsAndOwners, and CatDAO.getBasementCatsAndOwnersAndHomes.</p>
<p><strong>Conclusion: <a href="http://docs.jboss.org/hibernate/stable/annotations/api/org/hibernate/annotations/Proxy.html" target="_new">@Proxy(lazy = false)</a> is generally evil</strong></p>
<p>As mentioned above, when you indicate that a domain object should not support lazy proxies, you make it hard for DAO writers to get their code to perform well.  Worse, you disable a capability that they may be counting on, and they may not notice until there are major performance problems.  Unless you have a good reason to, use &#8220;<a href="http://docs.jboss.org/hibernate/stable/annotations/api/org/hibernate/annotations/Proxy.html" target="_new">@Proxy(lazy = true)</a>&#8221; on your domain objects.</p>
<p><strong>P.S.</strong></p>
<p>Lazy proxies do have some known problems.</p>
<p>First, the lazy proxy is NOT the same as the actual object.  If you depend on the datatype of the object, <a href="http://blog.xebia.com/2008/03/08/advanced-hibernate-proxy-pitfalls/" target="_new">you may have problems</a>, since the type of the proxy isn&#8217;t the same as the type of the actual object (e.g. a proxy for an Owner is not actually an Owner- it&#8217;s a subclass.)</p>
<p>Second, you may have to think carefully about methods like equals() or hashCode(), since the proxies <a href="http://windhood.spaces.live.com/blog/cns!452FEE7EB6C195AD!146.entry" target="_new">may not do what you expect</a>.</p>
<p><strong>P.P.S</strong><br />
Thanks to <a href="http://www.carloneworld.it/" target="_new">carloneworld</a> for the great lazy kitty photo!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.redfin.com/devblog/2009/12/laziness_in_proxies_is_a_virtue.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>How to search Redfin directly from IE and Firefox</title>
		<link>http://blog.redfin.com/devblog/2008/03/how_to_search_redfin_directly_from_ie_and_firefox.html</link>
		<comments>http://blog.redfin.com/devblog/2008/03/how_to_search_redfin_directly_from_ie_and_firefox.html#comments</comments>
		<pubDate>Wed, 05 Mar 2008 00:37:04 +0000</pubDate>
		<dc:creator>Michael Smedberg</dc:creator>
				<category><![CDATA[Browsers]]></category>

		<guid isPermaLink="false">http://blog.redfin.com/devblog/2008/03/how_to_search_redfin_directly_from_ie_and_firefox.html</guid>
		<description><![CDATA[I recently heard that some loyal Redfin customers were using Google to do address searches. That&#8217;s a shame, since Redfin does a pretty decent job of searching for addresses, MLS IDs, cities, etc. I wanted to see if I could help those power users get to Redfin search results with fewer clicks. Naturally, I wanted [...]]]></description>
			<content:encoded><![CDATA[<p>I recently heard that some loyal Redfin customers were using Google to do address searches.  That&#8217;s a shame, since Redfin does a pretty decent job of searching for addresses, MLS IDs, cities, etc.  I wanted to see if I could help those power users get to Redfin search results with fewer clicks.</p>
<p>Naturally, I wanted to see if I could make a Redfin search available.  It was surprisingly easy- I didn&#8217;t have to change any Redfin code.  I just wrote <a href="http://developer.mozilla.org/en/docs/Creating_OpenSearch_plugins_for_Firefox">an XML file</a>, hosted it on <a href="http://devblog.redfin.com/wp-content/uploads/misc/opensearch.xml">a Web server</a>, and put a link into an HTML page (this page, in fact!)</p>
<p>If you&#8217;re using Firefox or Internet Explorer 7, you should be able to enable Redfin search by choosing the relevant option in the search dropdown while viewing this page.  Here&#8217;s a screenshot of Firefox:</p>
<p><a href='http://blog.redfin.com/devblog/2008/03/how_to_search_redfin_directly_from_ie_and_firefox.html/add_redfin_firefox/' rel='attachment wp-att-71' title='add_redfin_firefox'><img src='http://blog.redfin.com/devblog/files/2008/02/add_redfin.bmp' alt='add redfin search to firefox' title="How to search Redfin directly from IE and Firefox" /></a></p>
<p>Here&#8217;s how it looks in IE7:</p>
<p><a href='http://blog.redfin.com/devblog/?attachment_id=72' rel='attachment wp-att-72' title='add_redfin_ie7'><img src='http://blog.redfin.com/devblog/files/2008/02/add_redfin_ie7.bmp' alt='add redfin search to ie7' title="How to search Redfin directly from IE and Firefox" /></a></p>
<p>Once you&#8217;ve added Redfin, you can do address searches on Redfin using the search control:<br />
<a href='http://blog.redfin.com/devblog/2008/03/how_to_search_redfin_directly_from_ie_and_firefox.html/search_with_redfin/' rel='attachment wp-att-73' title='search_with_redfin'><img src='http://blog.redfin.com/devblog/files/2008/02/search_with_redfin.bmp' alt='search with redfin' title="How to search Redfin directly from IE and Firefox" /></a></p>
<p>Another way to do searches in Redfin is to use a <a href="http://www.mozilla.org/docs/end-user/keywords.html">keyword bookmark</a>.  In Firefox, make a new bookmark, and edit it to look like this:</p>
<p><a href='http://blog.redfin.com/devblog/2008/03/how_to_search_redfin_directly_from_ie_and_firefox.html/redfin_keyword_bookmark/' rel='attachment wp-att-74' title='redfin_keyword_bookmark'><img src='http://blog.redfin.com/devblog/files/2008/02/redfin_keyword_bookmark.bmp' alt='redfin keyword bookmark' title="How to search Redfin directly from IE and Firefox" /></a></p>
<p>The important parts are the location and the keyword.  The location got cut off in my screenshot, but it should be <code>http://www.redfin.com/stingray/do/listings-search#search_location=%s</code></p>
<p>(the only tricky part is the &#8220;%s&#8221; part, which will get replaced with whatever you search for.)</p>
<p>To use it, you type the keyword and the search terms into your location bar, like this:</p>
<p><a href='http://blog.redfin.com/devblog/2008/03/how_to_search_redfin_directly_from_ie_and_firefox.html/search_for_hq/' rel='attachment wp-att-75' title='search_for_hq'><img src='http://blog.redfin.com/devblog/files/2008/02/search_for_hq.bmp' alt='search for headquarters' title="How to search Redfin directly from IE and Firefox" /></a></p>
<p>or this (for an MLS):</p>
<p><a href='http://blog.redfin.com/devblog/2008/03/how_to_search_redfin_directly_from_ie_and_firefox.html/search_for_mls/' rel='attachment wp-att-76' title='search_for_mls'><img src='http://blog.redfin.com/devblog/files/2008/02/search_for_mls.bmp' alt='search for mls' title="How to search Redfin directly from IE and Firefox" /></a></p>
<link rel="search" type="application/opensearchdescription+xml" title="Redfin" href="http://devblog.redfin.com/wp-content/uploads/misc/opensearch.xml">
]]></content:encoded>
			<wfw:commentRss>http://blog.redfin.com/devblog/2008/03/how_to_search_redfin_directly_from_ie_and_firefox.html/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Elephant versus Dolphin: Which is Faster?  Which is Smarter?</title>
		<link>http://blog.redfin.com/devblog/2007/11/elephant_versus_dolphin_which_is_faster_which_is_smarter.html</link>
		<comments>http://blog.redfin.com/devblog/2007/11/elephant_versus_dolphin_which_is_faster_which_is_smarter.html#comments</comments>
		<pubDate>Mon, 05 Nov 2007 17:09:23 +0000</pubDate>
		<dc:creator>Michael Smedberg</dc:creator>
				<category><![CDATA[Performance]]></category>

		<guid isPermaLink="false">http://blog.redfin.com/devblog/2007/11/elephant_versus_dolphin_which_is_faster_which_is_smarter.html</guid>
		<description><![CDATA[vs. Redfin recently switched some of our backend DB infrastructure from MySQL to Postgres, and we plan to wholly switch to Postgres in the near future. This wasn’t an easy decision; MySQL has a lot going for it, and switching has been a lot of work. However, we’ve already seen major benefits from choosing Postgres, [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.postgresql.org/"><img src="http://blog.redfin.com/devblog/files/2007/11/elephant2.png" alt="Elephant" title="Elephant versus Dolphin: Which is Faster?  Which is Smarter?" /></a> vs.<a href="http://www.mysql.com/"><img src="http://blog.redfin.com/devblog/files/2007/11/dolphin.gif" alt="MySQL" title="Elephant versus Dolphin: Which is Faster?  Which is Smarter?" /></a></p>
<p>Redfin recently switched some of our backend DB infrastructure from <a href="http://dev.mysql.com/doc/refman/5.1/en/index.html">MySQL</a> to <a href="http://www.postgresql.org/docs/8.2/static/index.html">Postgres</a>, and we plan to wholly switch to Postgres in the near future. This wasn’t an easy decision; MySQL has a lot going for it, and switching has been a lot of work.  However, we’ve already seen major benefits from choosing Postgres, and we expect to see more as we complete our transition.  In particular, performance on certain geographic queries has improved dramatically.<br />
A <a href="http://www.google.com/search?q=postgres%20mysql">simple Google search</a> shows that a lot of people have already opined about MySQL versus Postgres (e.g. <a href="http://articles.techrepublic.com.com/5100-22-1050671.html">here</a>, <a href="http://www.devx.com/dbzone/Article/20743">here</a>, <a href="http://www-css.fnal.gov/dsg/external/freeware/pgsql-vs-mysql.html">here</a>, <a href="http://www.postgresql.org/docs/techdocs.83">here</a>, <a href="http://lists.mysql.com/mysql/14915">here</a>, and <a href="http://www.suite101.com/article.cfm/oracle/115560">here</a>) but we weren&#8217;t able to find much information that applied directly to the problem we were having.  Specifically, we were having some major performance problems with queries that were constrained by both spatial and numeric columns, and all of our attempts to squeeze more performance out of MySQL (including hiring expensive outside consultants) had come to naught.</p>
<h2>GIS Indexes</h2>
<p>Redfin is an online real estate company, and our map based UI is the most-used part of our web site (as well as being the biggest performance hog.) When a user views the map, we use SQL to find the relevant listings or past sales.  Users typically constrain a search by numerous criteria, such as maximum price or minimum square footage.  Since the UI is map based, users are ALWAYS constraining by geography, though that constraint might be weak.</p>
<h3>How We Did It In MySQL</h3>
<p>In MySQL, the queries might look something like:</p>
<p><code>SELECT</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;*</code><br />
<code>FROM</code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;listings</code><br />
<code>WHERE </code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;price &lt;= 400000 AND<br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;num_bedrooms &gt;= 2 AND </code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;num_bathrooms &gt;= 1.5 AND </code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;type = 'condo' AND </code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;MBRContains(GeomFromText('POLYGON((X1 Y1,X1 Y2,X2 Y2,X2 Y1,X1 Y1))'), centroid_col) </code><br />
<code>LIMIT </code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;101</code></p>
<p>where X1/Y1 and X2/Y2 are lat/long pairs that describe the region to be searched. To improve performance, we create indexes on the relevant columns. In MySQL, a <a href="http://dev.mysql.com/doc/refman/5.1/en/create-index.html">normal index</a> cannot include spatial columns, and spatial indexes cannot include normal columns.  In this example, we might have one multi-column index on price, num_bedrooms, and num_bathrooms, and another single-column index on centroid_col. In many cases, this performs great.  Examples include: </p>
<ul>
<li>When the table is small (we have hundreds of thousands of listings, but tens of millions of past sales records)</li>
<li>When the geographic constraint is very selective (i.e. when the map is zoomed very far in)</li>
<li>When the geographic constraint is the only constraint (i.e. the user doesn’t care about price, bedrooms, etc.)</li>
<li>When the constraints are poor, but the LIMIT amount is hit quickly (e.g. search for all listings in the the world; MySQL can quickly find the first 101 rows in the table, and once it's found 101, it can give up)</li>
</ul>
<p>However, there were also cases where it performed terribly, particularly when the table was big, the geographic constraints were relatively weak, and other constraints were relatively strong.  For example, a search for all past sales in the San Francisco Bay Area that had 1 bedroom, but sold for over $10,000,000 resulted in a “killer” query.  This is a little counterintuitive, but was definitely a problem for our customers (though my example is a very extreme case.) The problem with this query is that:</p>
<ul>
<li>The table is large (tens of millions of rows)</li>
<li>The geographic index is the best index to use, but still isn’t great (might return 500,000 rows, or ~1% of the table)</li>
<li>MySQL would “short circuit” the query when 101 records were found, but the query returns less than 101 records (there are few 1 bedroom condos that sold for more than $10M), so MySQL examines all 500,000 rows that match the geographic constraint</li>
</ul>
<p>This does happen in real life.<br />
For example, a user might be looking at homes in a small neighborhood.  She's looking for a 2 bedroom condo between $350k and $375k with a view (a fairly heavily constrainted query.) Then she zooms the map out a few levels (maybe she wants to see a lot of the map to pick out other neighborhoods of interest.)  She has just unwittingly made a killer query- she's searching a large geography with tight constraints on other attributes.<br />
Another example is an investor- someone who wants to search large geographic areas for "fixer" properties that have a low asking price and large living area.  Again, this results in a query that's tightly constrained by some criteria, but relatively loosely constrained by geography.</p>
<h3>Postgres and PostGIS</h3>
<p>Jeff Yee, our intrepid head of QA, pointed out that geographic indexes in Postgres are supported through the feature-rich <a href="http://postgis.refractions.net/docs/">PostGIS</a> plug-in.  PostGIS supports all sorts of <a href="http://postgis.refractions.net/docs/ch06.html#id2809019">goodies</a> (such as polygon containment, distance calculations, projection conversion, etc.), but the biggest gain is support for <a href="http://postgis.refractions.net/docs/ch04.html#id2807089">indexes on multiple, mixed-type columns</a>.  Using PostGIS, we could create an index on centroid_col, price, and num_bedrooms.  These indexes turned many of our “killer” queries into pussycats.  It was immediately obvious that for Redfin, PostGIS is a Very Good Thing. PostGIS offers us more than just a huge performance improvement and robust, sophisticated geographic functionality.  It also offers an active community- there are lots of users available to answer <a href="http://postgis.refractions.net/pipermail/postgis-users/2007-August/016732.html">silly newbie questions</a>, and the software is being actively developed.  On top of that, there’s a great Windows installer.</p>
<h2>Other Considerations</h2>
<h3>MyISAM and Data Corruption</h3>
<p>In MySQL, our tables were <a href="http://dev.mysql.com/doc/refman/5.1/en/myisam-storage-engine.html">MyISAM</a>, since the geometric indexes we used were only supported on MyISAM tables.  MyISAM generally offers very good performance, but unfortunately we’ve experienced data corruption on our production systems a number of times.  It’s VERY painful, but we can live with occasional corruption if that’s the only way to deliver the performance we seek.  PostGIS has given us another option, and we expect the advanced locking and data protection in Postgres to make data corruption a thing of the past.</p>
<h3>Replication</h3>
<p>We use a “single master-multiple slave” configuration in production, which requires data replication. The MySQL replication options are not super flexible, but they did exactly what we needed them to do, and they did it really well.  Replication was easy to set up, easy to monitor, and proved to be very reliable. In Postgres, we had more options, and more confusion.  It took us a while to work out exactly how we would do replication; validating and implementing that plan took considerable effort.  It’s in production now, and it is working fine, but it was certainly a lot more effort than in MySQL.  There’s also an ongoing cost- replicating DDL changes is more complicated under Postgres than it was under MySQL.</p>
<h3>Advanced Features</h3>
<p>Advanced PostGIS features such as polygon matching and distance calculation have already helped us move much more quickly on Redfin features.  Most of these things CAN be done in MySQL (e.g. by post-processing query results in Java using the excellent <a href="http://www.vividsolutions.com/jts/jtshome.htm">JTS Topology Suite</a> library from Vivid Solutions), but it’s significantly more work, and in some cases would degrade performance.  Hopefully, you’ll see new Redfin features in the near future, and think to yourself “Aah, they’re making PostGIS do the heavy lifting- the lazy bastards.” Postgres also contains advanced features that we were able to immediately benefit from.  In particular, we use the <a href="http://www.postgresql.org/docs/8.2/static/sql-cluster.html">CLUSTER</a> command to optimize our table for access via the multicolumn geographic index.</p>
<h2>Conclusion</h2>
<p>Switching to Postgres was a lot of work.  This was compounded by the fact that we chose to “toe-dip” into Postgres- most of our tables are still in MySQL- so our Java code is cluttered with logic to choose the correct DB connection for each query, to construct the “correct” SQL for each DB (most Redfin developers were not required to use Postgres during the development cycle, and we wanted to be able to fall back to MySQL if Postgres turned out to be a disaster), etc.  We use <a href="http://www.hibernate.org/">Hibernate</a> for persistence, which added another layer of complexity. However, when I see the performance gains we’ve made, I know it’s all worth while.  The best cases probably aren’t much better, but the worst cases are startlingly better.  Postgres and PostGIS let me feel good about telling my friends to use “past sales” searches on Redfin- I’m confident they won’t be waiting long for their results!<br />
Dolphins may be smarter than elephants, but in the end, elephants are domesticable and can carry a heavy load.<br />
<a href='http://www.flickr.com/photos/autanex/300488148/' title='elephant_lift'><img src='http://blog.redfin.com/devblog/files/2007/11/elephant_lift.jpg' alt='elephant_lift' title="Elephant versus Dolphin: Which is Faster?  Which is Smarter?" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.redfin.com/devblog/2007/11/elephant_versus_dolphin_which_is_faster_which_is_smarter.html/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Getting the Time Zone from a Web Browser</title>
		<link>http://blog.redfin.com/devblog/2007/08/getting_the_time_zone_from_a_web_browser.html</link>
		<comments>http://blog.redfin.com/devblog/2007/08/getting_the_time_zone_from_a_web_browser.html#comments</comments>
		<pubDate>Fri, 31 Aug 2007 17:27:53 +0000</pubDate>
		<dc:creator>Michael Smedberg</dc:creator>
				<category><![CDATA[Browsers]]></category>

		<guid isPermaLink="false">http://blog.redfin.com/devblog/2007/08/getting_the_time_zone_from_a_web_browser.html</guid>
		<description><![CDATA[Writing rich date/time features in a web app can be a pain. Apps (such as schedulers) that do math on times (e.g. ordering times) should pay attention to time zones for those times, but it&#8217;s difficult to know which time zone should be used to display the times to the user. Asking the user to [...]]]></description>
			<content:encoded><![CDATA[<p>Writing rich date/time features in a web app can be a pain.  Apps (such as schedulers) that do math on times (e.g. ordering times) should pay attention to time zones for those times, but it&#8217;s difficult to know which time zone should be used to display the times to the user.  Asking the user to explicitly choose a time zone is natural and often necessary, but a long list of time zone choices can be intimidating to the user.  I&#8217;ll discuss one method you can use to detect the probable time zone of a browser.  It&#8217;s not perfect, but it offers a good default (and it&#8217;s easy to code.)</p>
<p><a href="http://www.flickr.com/photos/80651083@N00/930289018/" title="Time zones"><img src="http://blog.redfin.com/devblog/files/2007/08/spaceball.jpg" alt="Time zones" title="Getting the Time Zone from a Web Browser" /></a></p>
<p>For apps that don&#8217;t have rich date/time functionality, times can be represented as simple numbers or strings.  For example, if I wanted to meet you in San Francisco to go to the late showing of The Bourne Ultimatum at the Metreon theater, it&#8217;s probaby fine to say &#8220;let&#8217;s meet at the theater at 11:15 PM on Friday; the show starts at 11:30 PM.&#8221;  Since we&#8217;re in the same time zone as each other, and as the theater, we don&#8217;t really care about time zones.  An application that&#8217;s facilitating this interaction could store and display the times &#8220;11:15 PM&#8221; and &#8220;11:30 PM&#8221; without regard to time zones.</p>
<p><a href="http://westfield.com/metreon/" title="Metreon"><img src="http://blog.redfin.com/devblog/files/2007/08/180px-metreon.jpg" alt="Metreon" title="Getting the Time Zone from a Web Browser" /></a></p>
<p>If we want to do date/time processing on the back end (e.g. ordering events in time), it&#8217;s more general to store absolute times in the database.  For example, instead of storing something like &#8220;hour =&gt; 11, minute =&gt; 15&#8243;, which might mean different absolute times to different users, it is  convenient to store a canonical time such as the number of seconds since January 1, 1970 in GMT.  That way, we can compare all of the times in our database without having to worry about the time zone for each.</p>
<p><a href="http://www.rolex.com/en/collection/extraordinary-watches/gmt-master/index.jsp" title="GMT"><img src="http://blog.redfin.com/devblog/files/2007/08/rolex-gmt.jpg" alt="GMT" title="Getting the Time Zone from a Web Browser" /></a></p>
<p>If we store &#8220;absolute&#8221; times in the database, then displaying times to users becomes a localization issue.  It&#8217;s pretty similar to localizing web site content into the language of the user.  You start with a notion of what you want to present to the user, then you identify how the user wants to receive it (i.e. their language/locale), and then you localize the content at runtime (i.e. you show them the content in their language.)</p>
<p>As with language, you need to know about the user.  The HTTP protocol specifies that the <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4" title="RFC 2626 section 14">&#8220;Accept-Language&#8221; header</a> can be used by servers to find out which language(s) the user prefers.  The &#8220;Accept-Language&#8221; header is nice because it lets websites show content in the &#8220;correct&#8221; language without having to explicitly ask the user.  A user who only speaks French doesn&#8217;t have to puzzle through an English language page that says &#8220;click here for French&#8221; somewhere in a footer- they just see the content in French.  Even better, it&#8217;s one less setting that the server has to manage, and that the user has to set and keep up-to-date.</p>
<p>Unfortunately, there is no corresponding &#8220;Accept-Timezone&#8221; header- the HTTP standard does not contain any facility to allow the browser to automatically tell the server what time zone the user cares about.</p>
<p>There are two standard ways for developers to deal with this.</p>
<p>First, they can ignore it.  For many apps, this is a decent approach- just store &#8220;11:30 PM&#8221;, and don&#8217;t worry about the time zone.  As long as all the users who care about that time know what time zone it&#8217;s in, then the app doesn&#8217;t have to keep track of it.</p>
<p>Second, they can ask the user to make an explicit choice.  For example, when setting up Google Calendar, you are asked to choose a time zone.  That&#8217;s fine for the developer, but finding the &#8220;right&#8221; time zone in a long list can be a pain for the user.</p>
<p>I wanted to let users choose a time zone on my site, but I also wanted to have an intelligent default- for most users, they shouldn&#8217;t have to take any action; the choice I make for them should be correct.</p>
<p>This calls for Javascript on the client.  I wanted to write some Javascript that would choose the right option in a time zone dropdown.</p>
<p>This is slightly harder than it seems because Javascript ALSO does not contain a way to get the time zone of the user.  Javascript DOES, however, provide a way to get the offset from GMT for any particular time.  A time zone can be thought of as a rule that says what the GMT offset is for different times.  We can therefore do a reverse mapping- if we know the GMT offset for a few times, we can figure out the time zone for the user.  Time zones can be quite complicated (some include Daylight Savings Time, some start or end DST on different dates than others, sometimes the DST offset isn&#8217;t a full hour, etc.  There are even time zones that are identical for all FUTURE times, but had differences in the PAST.)</p>
<p>In theory, we could deal with all of these cases by doing many probes- we could check the GMT offset for many times, and get an exact time zone match.  In practice, this really isn&#8217;t necessary- most users are in the more populous time zones, and the cost of failure (defaulting to a time zone that&#8217;s similar but not quite right) is not terribly high.  Instead, we can probe two times (one in the summer and one in the winter) to find out the normal GMT offset, whether the time zone has Daylight Savings Time, and the DST offset.</p>
<p>In terms of implementation, I wanted to basically make a list of recognized offsets.  That is, a list that says &#8220;if the summer offset is -7 hours, and the winter offset is -8 hours, then the time zone is probably US/Pacific.&#8221;</p>
<p>I like hacking in Ruby, so I grabbed the <a href="http://tzinfo.rubyforge.org/" title="TZInfo library">TZInfo Ruby library</a>, and wrote some code to run through the known time zones, figuring out the winter and summer offsets for each.  After grouping by offsets, I had to choose a winner in the case of duplicates.  When multiple time zones had the same summer and winter offsets, I searched for each of them on Google.  I figured that the time zone with the most hits was probably the most popular one, so I chose that one.  Here&#8217;s the Javascript code that I came up with:</p>
<pre>
function getTimezoneName() {
	tmSummer = new Date(Date.UTC(2005, 6, 30, 0, 0, 0, 0));
	so = -1 * tmSummer.getTimezoneOffset();
	tmWinter = new Date(Date.UTC(2005, 12, 30, 0, 0, 0, 0));
	wo = -1 * tmWinter.getTimezoneOffset();

	if (-660 == so &amp;&amp; -660 == wo) return 'Pacific/Midway';
	if (-600 == so &amp;&amp; -600 == wo) return 'Pacific/Tahiti';
	if (-570 == so &amp;&amp; -570 == wo) return 'Pacific/Marquesas';
	if (-540 == so &amp;&amp; -600 == wo) return 'America/Adak';
	if (-540 == so &amp;&amp; -540 == wo) return 'Pacific/Gambier';
	if (-480 == so &amp;&amp; -540 == wo) return 'US/Alaska';
	if (-480 == so &amp;&amp; -480 == wo) return 'Pacific/Pitcairn';
	if (-420 == so &amp;&amp; -480 == wo) return 'US/Pacific';
	if (-420 == so &amp;&amp; -420 == wo) return 'US/Arizona';
	if (-360 == so &amp;&amp; -420 == wo) return 'US/Mountain';
	if (-360 == so &amp;&amp; -360 == wo) return 'America/Guatemala';
	if (-360 == so &amp;&amp; -300 == wo) return 'Pacific/Easter';
	if (-300 == so &amp;&amp; -360 == wo) return 'US/Central';
	if (-300 == so &amp;&amp; -300 == wo) return 'America/Bogota';
	if (-240 == so &amp;&amp; -300 == wo) return 'US/Eastern';
	if (-240 == so &amp;&amp; -240 == wo) return 'America/Caracas';
	if (-240 == so &amp;&amp; -180 == wo) return 'America/Santiago';
	if (-180 == so &amp;&amp; -240 == wo) return 'Canada/Atlantic';
	if (-180 == so &amp;&amp; -180 == wo) return 'America/Montevideo';
	if (-180 == so &amp;&amp; -120 == wo) return 'America/Sao_Paulo';
	if (-150 == so &amp;&amp; -210 == wo) return 'America/St_Johns';
	if (-120 == so &amp;&amp; -180 == wo) return 'America/Godthab';
	if (-120 == so &amp;&amp; -120 == wo) return 'America/Noronha';
	if (-60 == so &amp;&amp; -60 == wo) return 'Atlantic/Cape_Verde';
	if (0 == so &amp;&amp; -60 == wo) return 'Atlantic/Azores';
	if (0 == so &amp;&amp; 0 == wo) return 'Africa/Casablanca';
	if (60 == so &amp;&amp; 0 == wo) return 'Europe/London';
	if (60 == so &amp;&amp; 60 == wo) return 'Africa/Algiers';
	if (60 == so &amp;&amp; 120 == wo) return 'Africa/Windhoek';
	if (120 == so &amp;&amp; 60 == wo) return 'Europe/Amsterdam';
	if (120 == so &amp;&amp; 120 == wo) return 'Africa/Harare';
	if (180 == so &amp;&amp; 120 == wo) return 'Europe/Athens';
	if (180 == so &amp;&amp; 180 == wo) return 'Africa/Nairobi';
	if (240 == so &amp;&amp; 180 == wo) return 'Europe/Moscow';
	if (240 == so &amp;&amp; 240 == wo) return 'Asia/Dubai';
	if (270 == so &amp;&amp; 210 == wo) return 'Asia/Tehran';
	if (270 == so &amp;&amp; 270 == wo) return 'Asia/Kabul';
	if (300 == so &amp;&amp; 240 == wo) return 'Asia/Baku';
	if (300 == so &amp;&amp; 300 == wo) return 'Asia/Karachi';
	if (330 == so &amp;&amp; 330 == wo) return 'Asia/Calcutta';
	if (345 == so &amp;&amp; 345 == wo) return 'Asia/Katmandu';
	if (360 == so &amp;&amp; 300 == wo) return 'Asia/Yekaterinburg';
	if (360 == so &amp;&amp; 360 == wo) return 'Asia/Colombo';
	if (390 == so &amp;&amp; 390 == wo) return 'Asia/Rangoon';
	if (420 == so &amp;&amp; 360 == wo) return 'Asia/Almaty';
	if (420 == so &amp;&amp; 420 == wo) return 'Asia/Bangkok';
	if (480 == so &amp;&amp; 420 == wo) return 'Asia/Krasnoyarsk';
	if (480 == so &amp;&amp; 480 == wo) return 'Australia/Perth';
	if (540 == so &amp;&amp; 480 == wo) return 'Asia/Irkutsk';
	if (540 == so &amp;&amp; 540 == wo) return 'Asia/Tokyo';
	if (570 == so &amp;&amp; 570 == wo) return 'Australia/Darwin';
	if (570 == so &amp;&amp; 630 == wo) return 'Australia/Adelaide';
	if (600 == so &amp;&amp; 540 == wo) return 'Asia/Yakutsk';
	if (600 == so &amp;&amp; 600 == wo) return 'Australia/Brisbane';
	if (600 == so &amp;&amp; 660 == wo) return 'Australia/Sydney';
	if (630 == so &amp;&amp; 660 == wo) return 'Australia/Lord_Howe';
	if (660 == so &amp;&amp; 600 == wo) return 'Asia/Vladivostok';
	if (660 == so &amp;&amp; 660 == wo) return 'Pacific/Guadalcanal';
	if (690 == so &amp;&amp; 690 == wo) return 'Pacific/Norfolk';
	if (720 == so &amp;&amp; 660 == wo) return 'Asia/Magadan';
	if (720 == so &amp;&amp; 720 == wo) return 'Pacific/Fiji';
	if (720 == so &amp;&amp; 780 == wo) return 'Pacific/Auckland';
	if (765 == so &amp;&amp; 825 == wo) return 'Pacific/Chatham';
	if (780 == so &amp;&amp; 780 == wo) return 'Pacific/Enderbury'
	if (840 == so &amp;&amp; 840 == wo) return 'Pacific/Kiritimati';
	return 'US/Pacific';
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.redfin.com/devblog/2007/08/getting_the_time_zone_from_a_web_browser.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

