Unverified Commit 37cce803 authored by Marco Pivetta's avatar Marco Pivetta Committed by Sergei Morozov

Merge pull request #3488 from morozov/quote-only-string

Connection::quote() can only quote strings
parents 94b6980f c7d7722f
# Upgrade to 3.0
## BC BREAK `Statement::quote()` only accepts strings.
`Statement::quote()` and `ExpressionBuilder::literal()` no longer accept arguments of an arbitrary type and and don't implement type-specific handling. Only strings can be quoted.
## BC BREAK `Statement` and `Connection` methods return `void`.
`Connection::connect()`, `Statement::bindParam()`, `::bindValue()`, `::execute()`, `ResultStatement::setFetchMode()` and `::closeCursor()` no longer return a boolean value. They will throw an exception in case of failure.
......
......@@ -817,13 +817,9 @@ class Connection implements DriverConnection
/**
* {@inheritDoc}
*/
public function quote($input, $type = null)
public function quote(string $input) : string
{
$connection = $this->getWrappedConnection();
[$value, $bindingType] = $this->getBindingInfo($input, $type);
return $connection->quote($value, $bindingType);
return $this->getWrappedConnection()->quote($input);
}
/**
......
......@@ -3,7 +3,6 @@
namespace Doctrine\DBAL\Driver;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\ParameterType;
/**
* Connection interface.
......@@ -27,13 +26,8 @@ interface Connection
/**
* Quotes a string for use in a query.
*
* @param mixed $input
* @param int $type
*
* @return mixed
*/
public function quote($input, $type = ParameterType::STRING);
public function quote(string $input) : string;
/**
* Executes an SQL statement and return the number of affected rows.
......
......@@ -6,7 +6,6 @@ use Doctrine\DBAL\Driver\Connection;
use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
use Doctrine\DBAL\Driver\Statement as DriverStatement;
use Doctrine\DBAL\ParameterType;
use stdClass;
use const DB2_AUTOCOMMIT_OFF;
use const DB2_AUTOCOMMIT_ON;
......@@ -101,15 +100,9 @@ class DB2Connection implements Connection, ServerInfoAwareConnection
/**
* {@inheritdoc}
*/
public function quote($input, $type = ParameterType::STRING)
public function quote(string $input) : string
{
$input = db2_escape_string($input);
if ($type === ParameterType::INTEGER) {
return $input;
}
return "'" . $input . "'";
return "'" . db2_escape_string($input) . "'";
}
/**
......
......@@ -7,7 +7,6 @@ use Doctrine\DBAL\Driver\PingableConnection;
use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
use Doctrine\DBAL\Driver\Statement as DriverStatement;
use Doctrine\DBAL\ParameterType;
use mysqli;
use const MYSQLI_INIT_COMMAND;
use const MYSQLI_OPT_CONNECT_TIMEOUT;
......@@ -146,7 +145,7 @@ class MysqliConnection implements Connection, PingableConnection, ServerInfoAwar
/**
* {@inheritdoc}
*/
public function quote($input, $type = ParameterType::STRING)
public function quote(string $input) : string
{
return "'" . $this->conn->escape_string($input) . "'";
}
......
......@@ -6,14 +6,11 @@ use Doctrine\DBAL\Driver\Connection;
use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
use Doctrine\DBAL\Driver\Statement as DriverStatement;
use Doctrine\DBAL\ParameterType;
use UnexpectedValueException;
use const OCI_COMMIT_ON_SUCCESS;
use const OCI_DEFAULT;
use const OCI_NO_AUTO_COMMIT;
use function addcslashes;
use function is_float;
use function is_int;
use function oci_commit;
use function oci_connect;
use function oci_error;
......@@ -123,14 +120,9 @@ class OCI8Connection implements Connection, ServerInfoAwareConnection
/**
* {@inheritdoc}
*/
public function quote($value, $type = ParameterType::STRING)
public function quote(string $input) : string
{
if (is_int($value) || is_float($value)) {
return $value;
}
$value = str_replace("'", "''", $value);
return "'" . addcslashes($value, "\000\n\r\\\032") . "'";
return "'" . addcslashes(str_replace("'", "''", $input), "\000\n\r\\\032") . "'";
}
/**
......
......@@ -2,7 +2,6 @@
namespace Doctrine\DBAL\Driver;
use Doctrine\DBAL\ParameterType;
use PDO;
use function assert;
......@@ -86,9 +85,9 @@ class PDOConnection implements Connection, ServerInfoAwareConnection
/**
* {@inheritdoc}
*/
public function quote($input, $type = ParameterType::STRING)
public function quote(string $input) : string
{
return $this->connection->quote($input, $type);
return $this->connection->quote($input);
}
/**
......
......@@ -4,7 +4,6 @@ namespace Doctrine\DBAL\Driver\PDOSqlsrv;
use Doctrine\DBAL\Driver\PDOConnection;
use Doctrine\DBAL\Driver\PDOStatement;
use Doctrine\DBAL\ParameterType;
use function strpos;
use function substr;
......@@ -31,9 +30,9 @@ class Connection extends PDOConnection
/**
* {@inheritDoc}
*/
public function quote($value, $type = ParameterType::STRING)
public function quote(string $input) : string
{
$val = parent::quote($value, $type);
$val = parent::quote($input);
// Fix for a driver version terminating all values with null byte
if (strpos($val, "\0") !== false) {
......
......@@ -6,10 +6,7 @@ use Doctrine\DBAL\Driver\Connection;
use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
use Doctrine\DBAL\Driver\Statement as DriverStatement;
use Doctrine\DBAL\ParameterType;
use function assert;
use function is_float;
use function is_int;
use function is_resource;
use function is_string;
use function sasql_affected_rows;
......@@ -159,12 +156,8 @@ class SQLAnywhereConnection implements Connection, ServerInfoAwareConnection
/**
* {@inheritdoc}
*/
public function quote($input, $type = ParameterType::STRING)
public function quote(string $input) : string
{
if (is_int($input) || is_float($input)) {
return $input;
}
return "'" . sasql_escape_string($this->connection, $input) . "'";
}
......
......@@ -6,11 +6,7 @@ use Doctrine\DBAL\Driver\Connection;
use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
use Doctrine\DBAL\Driver\Statement as DriverStatement;
use Doctrine\DBAL\ParameterType;
use const SQLSRV_ERR_ERRORS;
use function is_float;
use function is_int;
use function sprintf;
use function sqlsrv_begin_transaction;
use function sqlsrv_commit;
use function sqlsrv_configure;
......@@ -95,17 +91,9 @@ class SQLSrvConnection implements Connection, ServerInfoAwareConnection
/**
* {@inheritDoc}
*/
public function quote($value, $type = ParameterType::STRING)
public function quote(string $input) : string
{
if (is_int($value)) {
return $value;
}
if (is_float($value)) {
return sprintf('%F', $value);
}
return "'" . str_replace("'", "''", $value) . "'";
return "'" . str_replace("'", "''", $input) . "'";
}
/**
......
......@@ -284,15 +284,10 @@ class ExpressionBuilder
}
/**
* Quotes a given input parameter.
*
* @param mixed $input The parameter to be quoted.
* @param int|null $type The type of the parameter.
*
* @return string
* Creates an SQL literal expression from the string.
*/
public function literal($input, $type = null)
public function literal(string $input)
{
return $this->connection->quote($input, $type);
return $this->connection->quote($input);
}
}
......@@ -836,12 +836,11 @@ abstract class AbstractSchemaManager
/**
* Aggregates and groups the index results according to the required data result.
*
* @param mixed[][] $tableIndexRows
* @param string|null $tableName
* @param mixed[][] $tableIndexRows
*
* @return Index[]
*/
protected function _getPortableTableIndexesList($tableIndexRows, $tableName = null)
protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array
{
$result = [];
foreach ($tableIndexRows as $tableIndex) {
......
......@@ -6,7 +6,9 @@ use Doctrine\DBAL\Platforms\DB2Platform;
use Doctrine\DBAL\Types\Type;
use const CASE_LOWER;
use function array_change_key_case;
use function assert;
use function is_resource;
use function is_string;
use function preg_match;
use function str_replace;
use function strpos;
......@@ -24,12 +26,14 @@ class DB2SchemaManager extends AbstractSchemaManager
* Apparently creator is the schema not the user who created it:
* {@link http://publib.boulder.ibm.com/infocenter/dzichelp/v2r2/index.jsp?topic=/com.ibm.db29.doc.sqlref/db2z_sysibmsystablestable.htm}
*/
public function listTableNames()
public function listTableNames() : array
{
$sql = $this->_platform->getListTablesSQL();
$sql .= ' AND CREATOR = UPPER(' . $this->_conn->quote($this->_conn->getUsername()) . ')';
$username = $this->_conn->getUsername();
assert(is_string($username));
$tables = $this->_conn->fetchAll($sql);
$sql = $this->_platform->getListTablesSQL() . ' AND CREATOR = UPPER(?)';
$tables = $this->_conn->fetchAll($sql, [$username]);
return $this->filterAssetNames($this->_getPortableTablesList($tables));
}
......@@ -123,7 +127,7 @@ class DB2SchemaManager extends AbstractSchemaManager
/**
* {@inheritdoc}
*/
protected function _getPortableTableIndexesList($tableIndexRows, $tableName = null)
protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array
{
foreach ($tableIndexRows as &$tableIndexRow) {
$tableIndexRow = array_change_key_case($tableIndexRow, CASE_LOWER);
......
......@@ -73,9 +73,9 @@ class MySqlSchemaManager extends AbstractSchemaManager
/**
* {@inheritdoc}
*/
protected function _getPortableTableIndexesList($tableIndexes, $tableName = null)
protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array
{
foreach ($tableIndexes as $k => $v) {
foreach ($tableIndexRows as $k => $v) {
$v = array_change_key_case($v, CASE_LOWER);
if ($v['key_name'] === 'PRIMARY') {
$v['primary'] = true;
......@@ -89,10 +89,10 @@ class MySqlSchemaManager extends AbstractSchemaManager
}
$v['length'] = isset($v['sub_part']) ? (int) $v['sub_part'] : null;
$tableIndexes[$k] = $v;
$tableIndexRows[$k] = $v;
}
return parent::_getPortableTableIndexesList($tableIndexes, $tableName);
return parent::_getPortableTableIndexesList($tableIndexRows, $tableName);
}
/**
......
......@@ -90,10 +90,10 @@ class OracleSchemaManager extends AbstractSchemaManager
*
* @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html
*/
protected function _getPortableTableIndexesList($tableIndexes, $tableName = null)
protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array
{
$indexBuffer = [];
foreach ($tableIndexes as $tableIndex) {
foreach ($tableIndexRows as $tableIndex) {
$tableIndex = array_change_key_case($tableIndex, CASE_LOWER);
$keyName = strtolower($tableIndex['name']);
......
......@@ -209,10 +209,10 @@ class PostgreSqlSchemaManager extends AbstractSchemaManager
*
* @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html
*/
protected function _getPortableTableIndexesList($tableIndexes, $tableName = null)
protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array
{
$buffer = [];
foreach ($tableIndexes as $row) {
foreach ($tableIndexRows as $row) {
$colNumbers = array_map('intval', explode(' ', $row['indkey']));
$columnNameSql = sprintf(
'SELECT attnum, attname FROM pg_attribute WHERE attrelid=%d AND attnum IN (%s) ORDER BY attnum ASC',
......
......@@ -194,7 +194,7 @@ class SQLAnywhereSchemaManager extends AbstractSchemaManager
/**
* {@inheritdoc}
*/
protected function _getPortableTableIndexesList($tableIndexRows, $tableName = null)
protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array
{
foreach ($tableIndexRows as &$tableIndex) {
$tableIndex['primary'] = (bool) $tableIndex['primary'];
......
......@@ -176,7 +176,7 @@ class SQLServerSchemaManager extends AbstractSchemaManager
/**
* {@inheritdoc}
*/
protected function _getPortableTableIndexesList($tableIndexRows, $tableName = null)
protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array
{
foreach ($tableIndexRows as &$tableIndex) {
$tableIndex['non_unique'] = (bool) $tableIndex['non_unique'];
......
......@@ -163,7 +163,7 @@ class SqliteSchemaManager extends AbstractSchemaManager
*
* @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html
*/
protected function _getPortableTableIndexesList($tableIndexes, $tableName = null)
protected function _getPortableTableIndexesList(array $tableIndexRows, string $tableName) : array
{
$indexBuffer = [];
......@@ -195,7 +195,7 @@ class SqliteSchemaManager extends AbstractSchemaManager
}
// fetch regular indexes
foreach ($tableIndexes as $tableIndex) {
foreach ($tableIndexRows as $tableIndex) {
// Ignore indexes with reserved names, e.g. autoindexes
if (strpos($tableIndex['name'], 'sqlite_') === 0) {
continue;
......
......@@ -202,7 +202,7 @@ class SQLAzureShardManager implements ShardManager
$sql = 'ALTER FEDERATION ' . $this->getFederationName() . ' ' .
'SPLIT AT (' . $this->getDistributionKey() . ' = ' .
$this->conn->quote($splitDistributionValue, $type->getBindingType()) . ')';
$this->conn->quote($splitDistributionValue) . ')';
$this->conn->exec($sql);
}
}
......@@ -6,9 +6,7 @@ use Doctrine\DBAL\Connection;
use Doctrine\DBAL\ConnectionException;
use Doctrine\DBAL\Driver\Connection as DriverConnection;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\Types;
use Doctrine\Tests\DbalFunctionalTestCase;
use Error;
use Exception;
......@@ -287,8 +285,8 @@ class ConnectionTest extends DbalFunctionalTestCase
public function testQuote() : void
{
self::assertEquals(
$this->connection->quote('foo', Types::STRING),
$this->connection->quote('foo', ParameterType::STRING)
$this->connection->quote('foo'),
$this->connection->quote('foo')
);
}
......
......@@ -177,9 +177,9 @@ class DataAccessTest extends DbalFunctionalTestCase
$paramStr = 'foo';
$stmt = $this->connection->prepare(sprintf(
'SELECT test_int, test_string FROM %s WHERE test_int = %s AND test_string = %s',
'SELECT test_int, test_string FROM %s WHERE test_int = %d AND test_string = %s',
$this->connection->quoteIdentifier($table),
$this->connection->quote($paramInt),
$paramInt,
$this->connection->quote($paramStr)
));
self::assertInstanceOf(Statement::class, $stmt);
......
......@@ -46,7 +46,7 @@ class WriteTest extends DbalFunctionalTestCase
public function testExecuteUpdate() : void
{
$sql = 'INSERT INTO write_table (test_int) VALUES ( ' . $this->connection->quote(1) . ')';
$sql = 'INSERT INTO write_table (test_int) VALUES (1)';
$affected = $this->connection->executeUpdate($sql);
self::assertEquals(1, $affected, 'executeUpdate() should return the number of affected rows!');
......
......@@ -25,14 +25,19 @@ final class DB2SchemaManagerTest extends TestCase
protected function setUp() : void
{
$eventManager = new EventManager();
$driverMock = $this->createMock(Driver::class);
$platform = $this->createMock(DB2Platform::class);
$this->conn = $this
$eventManager = new EventManager();
$driverMock = $this->createMock(Driver::class);
$platform = $this->createMock(DB2Platform::class);
$this->conn = $this
->getMockBuilder(Connection::class)
->onlyMethods(['fetchAll', 'quote'])
->onlyMethods(['fetchAll', 'getUsername'])
->setConstructorArgs([['platform' => $platform], $driverMock, new Configuration(), $eventManager])
->getMock();
$this->conn->expects($this->any())
->method('getUsername')
->willReturn('db2inst1');
$this->manager = new DB2SchemaManager($this->conn);
}
......@@ -95,7 +100,7 @@ final class DB2SchemaManagerTest extends TestCase
$this->conn->getConfiguration()->setSchemaAssetsFilter(static function ($assetName) use ($accepted) {
return in_array($assetName, $accepted);
});
$this->conn->expects($this->any())->method('quote');
$this->conn->expects($this->once())->method('fetchAll')->will($this->returnValue([
['name' => 'FOO'],
['name' => 'T_FOO'],
......@@ -120,7 +125,7 @@ final class DB2SchemaManagerTest extends TestCase
$this->conn->getConfiguration()->setSchemaAssetsFilter(static function ($assetName) use ($accepted) {
return in_array($assetName, $accepted);
});
$this->conn->expects($this->any())->method('quote');
$this->conn->expects($this->atLeastOnce())->method('fetchAll')->will($this->returnValue([
['name' => 'FOO'],
['name' => 'T_FOO'],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment