diff --git a/runtime/lib/connection/DebugPDOStatement.php b/runtime/lib/connection/DebugPDOStatement.php index 003e3d634..5773a6c47 100644 --- a/runtime/lib/connection/DebugPDOStatement.php +++ b/runtime/lib/connection/DebugPDOStatement.php @@ -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); } } @@ -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); @@ -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); diff --git a/test/testsuite/runtime/connection/PropelPDOTest.php b/test/testsuite/runtime/connection/PropelPDOTest.php index 19e1e25d2..bf86cd933 100644 --- a/test/testsuite/runtime/connection/PropelPDOTest.php +++ b/test/testsuite/runtime/connection/PropelPDOTest.php @@ -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 diff --git a/test/testsuite/runtime/query/ModelCriteriaTest.php b/test/testsuite/runtime/query/ModelCriteriaTest.php index 10d9616dc..0c23967b6 100644 --- a/test/testsuite/runtime/query/ModelCriteriaTest.php +++ b/test/testsuite/runtime/query/ModelCriteriaTest.php @@ -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()); }