Skip to content

Commit

Permalink
Merge pull request propelorm#775 from thedave80/DebugPDO-fix
Browse files Browse the repository at this point in the history
DebugPDO executedQueryString - quoting
  • Loading branch information
willdurand committed Oct 18, 2013
2 parents 4dde6da + 067dad2 commit ae7bb75
Show file tree
Hide file tree
Showing 3 changed files with 212 additions and 4 deletions.
14 changes: 11 additions & 3 deletions runtime/lib/connection/DebugPDOStatement.php
Expand Up @@ -74,7 +74,14 @@ public function getExecutedQueryString(array $values = array())
$size = count($matches[1]);
for ($i = $size - 1; $i >= 0; $i--) {
$pos = $matches[1][$i];
$sql = str_replace($pos, $boundValues[$pos], $sql);

// trimming extra quotes, making sure value is properly quoted afterwards
$boundValue = $boundValues[$pos];
if (is_string($boundValue)) { // quoting only needed for string values
$boundValue = trim($boundValue, "'");
$boundValue = $this->pdo->quote($boundValue);
}
$sql = str_replace($pos, $boundValue, $sql);
}
}

Expand Down Expand Up @@ -120,7 +127,7 @@ public function bindValue($pos, $value, $type = PDO::PARAM_STR)
$valuestr = $type == PDO::PARAM_LOB ? '[LOB value]' : var_export($value, true);
$msg = sprintf('Binding %s at position %s w/ PDO type %s', $valuestr, $pos, $typestr);

$this->boundValues[$pos] = $valuestr;
$this->boundValues[$pos] = $value;

$this->pdo->log($msg, null, __METHOD__, $debug);

Expand All @@ -143,13 +150,14 @@ public function bindValue($pos, $value, $type = PDO::PARAM_STR)
*/
public function bindParam($pos, &$value, $type = PDO::PARAM_STR, $length = 0, $driver_options = null)
{
$originalValue = $value;
$debug = $this->pdo->getDebugSnapshot();
$typestr = isset(self::$typeMap[$type]) ? self::$typeMap[$type] : '(default)';
$return = parent::bindParam($pos, $value, $type, $length, $driver_options);
$valuestr = $length > 100 ? '[Large value]' : var_export($value, true);
$msg = sprintf('Binding %s at position %s w/ PDO type %s', $valuestr, $pos, $typestr);

$this->boundValues[$pos] = $valuestr;
$this->boundValues[$pos] = $originalValue;

$this->pdo->log($msg, null, __METHOD__, $debug);

Expand Down
200 changes: 200 additions & 0 deletions test/testsuite/runtime/connection/PropelPDOTest.php
Expand Up @@ -457,6 +457,206 @@ public function testDebugLog()
$con->setLogger($logger);
$config->setParameter("debugpdo.logging.methods", array('PropelPDO::exec', 'PropelPDO::query', 'DebugPDOStatement::execute'));
}

/**
* Testing if string values will be quoted correctly by DebugPDOStatement::getExecutedQueryString
*/
public function testDebugExecutedQueryStringValue()
{

/**
* @var DebugPDO $con
*/
$con = Propel::getConnection(BookPeer::DATABASE_NAME);

// different method must all result in this given querystring, using a string value
$bindParamStringValue = "%Harry%";
$expectedQuery = "SELECT book.id FROM `book` WHERE book.title LIKE '{$bindParamStringValue}'";

// simple statement without params
$prepStmt = $con->prepare($expectedQuery);
$prepStmt->execute();
$this->assertEquals($expectedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');

// statement with named placeholder
$prepStmt = $con->prepare("SELECT book.id FROM `book` WHERE book.title LIKE :p1");
$prepStmt->bindValue(':p1', '%Harry%'); // bind value variant
$prepStmt->execute();
$this->assertEquals($expectedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');

$prepStmt->bindParam(':p1', $bindParamStringValue); // bind param variant
$prepStmt->execute();
$this->assertEquals($expectedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');

// passing params directly
$prepStmt->execute(array(':p1' => '%Harry%'));
$this->assertEquals($expectedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');


// statement with named placeholder, this one won't get substituted
$expectedNotSubstitutedQuery = "SELECT book.id FROM `book` WHERE book.title LIKE :name";
$prepStmt = $con->prepare($expectedNotSubstitutedQuery);
$prepStmt->bindValue(':name', '%Harry%'); // bind value variant
$prepStmt->execute();
$this->assertEquals($expectedNotSubstitutedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');

$prepStmt->bindParam(':name', $bindParamStringValue); // bind param variant
$prepStmt->execute();
$this->assertEquals($expectedNotSubstitutedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');

// passing params directly
$prepStmt->execute(array(':name' => '%Harry%'));
$this->assertEquals($expectedNotSubstitutedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');


// statement with positional placeholder, this one won't get substituted either
$expectedNotSubstitutedQuery = "SELECT book.id FROM `book` WHERE book.title LIKE ?";
$prepStmt = $con->prepare($expectedNotSubstitutedQuery);
$prepStmt->bindValue(1, '%Harry%');
$prepStmt->execute();
$this->assertEquals($expectedNotSubstitutedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');

$prepStmt->bindParam(1, $bindParamStringValue);
$prepStmt->execute();
$this->assertEquals($expectedNotSubstitutedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');

// passing params directly
$prepStmt->execute(array('%Harry%'));
$this->assertEquals($expectedNotSubstitutedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');
}

/**
* Testing if integer values will be quoted correctly by DebugPDOStatement::getExecutedQueryString
*/
public function testDebugExecutedQueryIntegerValue() {

/**
* @var DebugPDO $con
*/
$con = Propel::getConnection(BookPeer::DATABASE_NAME);

// different method must all result in this given querystring, using an integer value
$bindParamIntegerValue = 123;
$expectedQuery = "SELECT book.title FROM `book` WHERE book.id = {$bindParamIntegerValue}";

// simple statement without params
$prepStmt = $con->prepare($expectedQuery);
$prepStmt->execute();
$this->assertEquals($expectedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');

// statement with named placeholder
$prepStmt = $con->prepare("SELECT book.title FROM `book` WHERE book.id = :p1");
$prepStmt->bindValue(':p1', 123); // bind value variant
$prepStmt->execute();
$this->assertEquals($expectedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');

$prepStmt->bindParam(':p1', $bindParamIntegerValue); // bind param variant
$prepStmt->execute();
$this->assertEquals($expectedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');

// passing params directly
$prepStmt->execute(array(':p1' => 123));
$this->assertEquals($expectedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');


// statement with named placeholder, this one won't get substituted
$expectedNotSubstitutedQuery = "SELECT book.title FROM `book` WHERE book.id = :name";
$prepStmt = $con->prepare($expectedNotSubstitutedQuery);
$prepStmt->bindValue(':name', 123); // bind value variant
$prepStmt->execute();
$this->assertEquals($expectedNotSubstitutedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');

$prepStmt->bindParam(':name', $bindParamIntegerValue); // bind param variant
$prepStmt->execute();
$this->assertEquals($expectedNotSubstitutedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');

// passing params directly
$prepStmt->execute(array(':name' => 123));
$this->assertEquals($expectedNotSubstitutedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');


// statement with positional placeholder, this one won't get substituted either
$expectedNotSubstitutedQuery = "SELECT book.title FROM `book` WHERE book.id = ?";
$prepStmt = $con->prepare($expectedNotSubstitutedQuery);
$prepStmt->bindValue(1, 123);
$prepStmt->execute();
$this->assertEquals($expectedNotSubstitutedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');

$prepStmt->bindParam(1, $bindParamIntegerValue);
$prepStmt->execute();
$this->assertEquals($expectedNotSubstitutedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');

// passing params directly
$prepStmt->execute(array(123));
$this->assertEquals($expectedNotSubstitutedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');
}

/**
* Testing if numeric values will be quoted correctly by DebugPDOStatement::getExecutedQueryString
* Numeric values sometimes will get handled differently, since there are numeric values which are non-integer
*/
public function testDebugExecutedQueryNumericValue() {

/**
* @var DebugPDO $con
*/
$con = Propel::getConnection(BookPeer::DATABASE_NAME);

// different method must all result in this given querystring, using an integer value
$bindParamNumericValue = 0002000;
$expectedQuery = "SELECT book.title FROM `book` WHERE book.id = {$bindParamNumericValue}";

// simple statement without params
$prepStmt = $con->prepare($expectedQuery);
$prepStmt->execute();
$this->assertEquals($expectedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');

// statement with named placeholder
$prepStmt = $con->prepare("SELECT book.title FROM `book` WHERE book.id = :p1");
$prepStmt->bindValue(':p1', 0002000); // bind value variant
$prepStmt->execute();
$this->assertEquals($expectedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');

$prepStmt->bindParam(':p1', $bindParamNumericValue); // bind param variant
$prepStmt->execute();
$this->assertEquals($expectedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');

// passing params directly
$prepStmt->execute(array(':p1' => 0002000));
$this->assertEquals($expectedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');


// statement with named placeholder, this one won't get substituted
$expectedNotSubstitutedQuery = "SELECT book.title FROM `book` WHERE book.id = :name";
$prepStmt = $con->prepare($expectedNotSubstitutedQuery);
$prepStmt->bindValue(':name', 0002000); // bind value variant
$prepStmt->execute();
$this->assertEquals($expectedNotSubstitutedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');

$prepStmt->bindParam(':name', $bindParamNumericValue); // bind param variant
$prepStmt->execute();
$this->assertEquals($expectedNotSubstitutedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');

// passing params directly
$prepStmt->execute(array(':name' => 0002000));
$this->assertEquals($expectedNotSubstitutedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');


// statement with positional placeholder, this one won't get substituted either
$expectedNotSubstitutedQuery = "SELECT book.title FROM `book` WHERE book.id = ?";
$prepStmt = $con->prepare($expectedNotSubstitutedQuery);
$prepStmt->bindValue(1, 0002000);
$prepStmt->execute();
$this->assertEquals($expectedNotSubstitutedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');

$prepStmt->bindParam(1, $bindParamNumericValue);
$prepStmt->execute();
$this->assertEquals($expectedNotSubstitutedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');

// passing params directly
$prepStmt->execute(array(0002000));
$this->assertEquals($expectedNotSubstitutedQuery, $con->getLastExecutedQuery(), 'DebugPDO failed to quote prepared statement on execute properly');
}
}

class myLogger
Expand Down
2 changes: 1 addition & 1 deletion test/testsuite/runtime/query/ModelCriteriaTest.php
Expand Up @@ -326,7 +326,7 @@ public function testWhereTypeValue()
);
$this->assertCriteriaTranslation($c, $sql, $params, 'where() accepts a complex calculation');
$c->find($this->con);
$expected = "SELECT book.id, book.title, book.isbn, book.price, book.publisher_id, book.author_id FROM `book` WHERE LOCATE('foo', book.title) = true";
$expected = "SELECT book.id, book.title, book.isbn, book.price, book.publisher_id, book.author_id FROM `book` WHERE LOCATE('foo', book.title) = 1";
$this->assertEquals($expected, $this->con->getLastExecutedQuery());
}

Expand Down

0 comments on commit ae7bb75

Please sign in to comment.