<?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>Davey Shafik &#187; database</title>
	<atom:link href="http://daveyshafik.com/archives/tag/database/feed" rel="self" type="application/rss+xml" />
	<link>http://daveyshafik.com</link>
	<description>As close to my brain as you can safely get...</description>
	<lastBuildDate>Tue, 02 Feb 2010 05:48:39 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Debugging PDO Prepared Statements</title>
		<link>http://daveyshafik.com/archives/605-debugging-pdo-prepared-statements.html</link>
		<comments>http://daveyshafik.com/archives/605-debugging-pdo-prepared-statements.html#comments</comments>
		<pubDate>Sat, 16 May 2009 17:02:28 +0000</pubDate>
		<dc:creator>Davey Shafik</dc:creator>
				<category><![CDATA[tagged]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[databases]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[debugging]]></category>
		<category><![CDATA[pdo]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[prepared queries]]></category>
		<category><![CDATA[prepared statements]]></category>
		<category><![CDATA[rdbms]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://pixelated-dreams.com/?p=605</guid>
		<description><![CDATA[<p>Something that has always bugged me about using prepared statements, is that you can really only get the query sent to the database by catching it in the logs.</p>
<p>Today, a friend asking me if it was possible to get a prepared statement back from PDO with the values placeholders replaced, finally caught me in a moment where I could do something about it.</p>
<p>I wrote a thin PDO wrapper class that will [imperfectly, I'm sure] return the completed query.…</p>]]></description>
			<content:encoded><![CDATA[<p>Something that has always bugged me about using prepared statements, is that you can really only get the query sent to the database by catching it in the logs.</p>
<p>Today, a friend asking me if it was possible to get a prepared statement back from PDO with the values placeholders replaced, finally caught me in a moment where I could do something about it.</p>
<p>I wrote a thin PDO wrapper class that will [imperfectly, I'm sure] return the completed query.</p>
<p>It supports bound parameters, values and the array key-&gt;value methods of passing in values to prepared queries. You can see the code and examples below:</p>
<pre class="brush: php">
&lt;?php
class PDOTester extends PDO {
	public function __construct($dsn, $username = null, $password = null, $driver_options = array())
	{
		parent::__construct($dsn, $username, $password, $driver_options);
		$this-&gt;setAttribute(PDO::ATTR_STATEMENT_CLASS, array(&#039;PDOStatementTester&#039;, array($this)));
	}
}

class PDOStatementTester extends PDOStatement {
	const NO_MAX_LENGTH = -1;

	protected $connection;
	protected $bound_params = array();

	protected function __construct(PDO $connection)
	{
		$this-&gt;connection = $connection;
	}

	public function bindParam($paramno, &amp;$param, $type = PDO::PARAM_STR, $maxlen = null, $driverdata = null)
	{
		$this-&gt;bound_params[$paramno] = array(
			&#039;value&#039; =&gt; &amp;$param,
			&#039;type&#039; =&gt; $type,
			&#039;maxlen&#039; =&gt; (is_null($maxlen)) ? self::NO_MAX_LENGTH : $maxlen,
			// ignore driver data
		);

		$result = parent::bindParam($paramno, $param, $type, $maxlen, $driverdata);
	}

	public function bindValue($parameter, $value, $data_type = PDO::PARAM_STR)
	{
		$this-&gt;bound_params[$parameter] = array(
			&#039;value&#039; =&gt; $value,
			&#039;type&#039; =&gt; $data_type,
			&#039;maxlen&#039; =&gt; self::NO_MAX_LENGTH
		);
		parent::bindValue($parameter, $value, $data_type);
	}

	public function getSQL($values = array())
	{
		$sql = $this-&gt;queryString;

		if (sizeof($values) &gt; 0) {
			foreach ($values as $key =&gt; $value) {
				$sql = str_replace($key, $this-&gt;connection-&gt;quote($value), $sql);
			}
		}

		if (sizeof($this-&gt;bound_params)) {
			foreach ($this-&gt;bound_params as $key =&gt; $param) {
				$value = $param[&#039;value&#039;];
				if (!is_null($param[&#039;type&#039;])) {
					$value = self::cast($value, $param[&#039;type&#039;]);
				}
				if ($param[&#039;maxlen&#039;] &amp;&amp; $param[&#039;maxlen&#039;] != self::NO_MAX_LENGTH) {
					$value = self::truncate($value, $param[&#039;maxlen&#039;]);
				}
				if (!is_null($value)) {
					$sql = str_replace($key, $this-&gt;connection-&gt;quote($value), $sql);
				} else {
					$sql = str_replace($key, &#039;NULL&#039;, $sql);
				}
			}
		}
		return $sql;
	}

	static protected function cast($value, $type)
	{
		switch ($type) {
			case PDO::PARAM_BOOL:
				return (bool) $value;
				break;
			case PDO::PARAM_NULL:
				return null;
				break;
			case PDO::PARAM_INT:
				return (int) $value;
			case PDO::PARAM_STR:
			default:
				return $value;
		}
	}

	static protected function truncate($value, $length)
	{
		return substr($value, 0, $length);
	}
}

$pdo = new PDOTester(&#039;sqlite::memory:&#039;);
$pdo-&gt;query(&#039;CREATE TABLE foo (bar TEXT, baz TEXT, num NUMERIC, empty TEXT)&#039;);
$query = $pdo-&gt;prepare(&#039;SELECT * FROM foo WHERE bar = :bar AND baz = :baz&#039;);

// Test with passed in array
echo $query-&gt;getSQL(array(&#039;:bar&#039; =&gt; &#039;foo&#039;, &#039;:baz&#039; =&gt; &#039;bat&#039;)) . PHP_EOL;

$query = $pdo-&gt;prepare(&#039;SELECT * FROM foo WHERE bar = :bar AND baz = :baz AND num = :num AND empty=:empty&#039;);

// Test with bound params and values
$bar = &#039;bar&#039;;
$baz = &#039;baz&#039;;
$num = &#039;0.1&#039;;
$empty = &#039;empty!!&#039;;

// Bind Param
$query-&gt;bindParam(&#039;:bar&#039;, $bar);

// Bind Value
$query-&gt;bindValue(&#039;:baz&#039;, $baz);

// Bind With types
$query-&gt;bindParam(&#039;:num&#039;, $num, PDO::PARAM_INT);
$query-&gt;bindParam(&#039;:empty&#039;, $empty, PDO::PARAM_NULL);

echo $query-&gt;getSQL() . PHP_EOL;

// Change the vars
$bar = &#039;foo&#039;;
$baz = &#039;bat&#039;;
$num = &#039;2.6&#039;;
$empty = &#039;blah!&#039;;

echo $query-&gt;getSQL() . PHP_EOL;

// Bind with length
$query-&gt;bindParam(&#039;:bar&#039;, $bar, PDO::PARAM_STR, 2);

echo $query-&gt;getSQL() . PHP_EOL;
?&gt;
</pre>
<p>This results in the following output:</p>
<pre class="brush: sql">
SELECT * FROM foo WHERE bar = &#039;foo&#039; AND baz = &#039;bat&#039;
SELECT * FROM foo WHERE bar = &#039;bar&#039; AND baz = &#039;baz&#039; AND num = &#039;0&#039; AND empty=NULL
SELECT * FROM foo WHERE bar = &#039;foo&#039; AND baz = &#039;baz&#039; AND num = &#039;2&#039; AND empty=NULL
SELECT * FROM foo WHERE bar = &#039;fo&#039; AND baz = &#039;baz&#039; AND num = &#039;2&#039; AND empty=NULL
</pre>
<p>Hopefully, this will help you get a somewhat better idea of what&#8217;s going on <img src='http://daveyshafik.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>- Davey</p>
]]></content:encoded>
			<wfw:commentRss>http://daveyshafik.com/archives/605-debugging-pdo-prepared-statements.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
