Unverified Commit 228b18bd authored by Sergei Morozov's avatar Sergei Morozov Committed by GitHub

Merge pull request #3803 from morozov/issues/3798

Backport PDO-related changes from master to 3.0.x
parents 683438c8 dcc3f2d4
# Upgrade to 3.0
## BC BREAK User-provided `PDO` instance is no longer supported
In order to share the same `PDO` instances between DBAL and other components, initialize the connection in DBAL and access it using `Connection::getWrappedConnection()->getWrappedConnection()`.
## BC BREAK: the PDO symbols are no longer part of the DBAL API
1. The support of `PDO::PARAM_*`, `PDO::FETCH_*`, `PDO::CASE_*` and `PDO::PARAM_INPUT_OUTPUT` constants in the DBAL API is removed.
2. `\Doctrine\DBAL\Driver\PDOConnection` does not extend `\PDO` anymore. Please use `\Doctrine\DBAL\Driver\PDOConnection::getWrappedConnection()` to access the underlying `PDO` object.
3. `\Doctrine\DBAL\Driver\PDOStatement` does not extend `\PDOStatement` anymore.
Before:
use Doctrine\DBAL\Portability\Connection;
$params = array(
'wrapperClass' => Connection::class,
'fetch_case' => PDO::CASE_LOWER,
);
$stmt->bindValue(1, 1, PDO::PARAM_INT);
$stmt->fetchAll(PDO::FETCH_COLUMN);
After:
use Doctrine\DBAL\ColumnCase;
use Doctrine\DBAL\FetchMode;
use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Portability\Connection;
$params = array(
'wrapperClass' => Connection::class,
'fetch_case' => ColumnCase::LOWER,
);
$stmt->bindValue(1, 1, ParameterType::INTEGER);
$stmt->fetchAll(FetchMode::COLUMN);
## BC BREAK: Removed dbal:import CLI command
The `dbal:import` CLI command has been removed since it only worked with PDO-based drivers by relying on a non-documented behavior of the extension, and it was impossible to make it work with other drivers.
Please use other database client applications for import, e.g.:
* For MySQL and MariaDB: `mysql [dbname] < data.sql`.
* For PostgreSQL: `psql [dbname] < data.sql`.
* For SQLite: `sqlite3 /path/to/file.db < data.sql`.
# Upgrade to 2.10 # Upgrade to 2.10
## Deprecated `Doctrine\DBAL\Event\ConnectionEventArgs` methods ## Deprecated `Doctrine\DBAL\Event\ConnectionEventArgs` methods
......
...@@ -33,7 +33,6 @@ ...@@ -33,7 +33,6 @@
], ],
"require": { "require": {
"php": "^7.2", "php": "^7.2",
"ext-pdo": "*",
"doctrine/cache": "^1.0", "doctrine/cache": "^1.0",
"doctrine/event-manager": "^1.0" "doctrine/event-manager": "^1.0"
}, },
......
...@@ -7,7 +7,6 @@ use Doctrine\DBAL\Driver\ResultStatement; ...@@ -7,7 +7,6 @@ use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\FetchMode;
use InvalidArgumentException; use InvalidArgumentException;
use IteratorAggregate; use IteratorAggregate;
use PDO;
use function array_merge; use function array_merge;
use function array_values; use function array_values;
use function count; use function count;
...@@ -59,9 +58,9 @@ class ArrayStatement implements IteratorAggregate, ResultStatement ...@@ -59,9 +58,9 @@ class ArrayStatement implements IteratorAggregate, ResultStatement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) public function setFetchMode($fetchMode, ...$args)
{ {
if ($arg2 !== null || $arg3 !== null) { if (count($args) > 0) {
throw new InvalidArgumentException('Caching layer does not support 2nd/3rd argument to setFetchMode()'); throw new InvalidArgumentException('Caching layer does not support 2nd/3rd argument to setFetchMode()');
} }
...@@ -83,7 +82,7 @@ class ArrayStatement implements IteratorAggregate, ResultStatement ...@@ -83,7 +82,7 @@ class ArrayStatement implements IteratorAggregate, ResultStatement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) public function fetch($fetchMode = null, ...$args)
{ {
if (! isset($this->data[$this->num])) { if (! isset($this->data[$this->num])) {
return false; return false;
...@@ -114,10 +113,10 @@ class ArrayStatement implements IteratorAggregate, ResultStatement ...@@ -114,10 +113,10 @@ class ArrayStatement implements IteratorAggregate, ResultStatement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) public function fetchAll($fetchMode = null, ...$args)
{ {
$rows = []; $rows = [];
while ($row = $this->fetch($fetchMode)) { while ($row = $this->fetch($fetchMode, ...$args)) {
$rows[] = $row; $rows[] = $row;
} }
......
...@@ -9,7 +9,6 @@ use Doctrine\DBAL\Driver\Statement; ...@@ -9,7 +9,6 @@ use Doctrine\DBAL\Driver\Statement;
use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\FetchMode;
use InvalidArgumentException; use InvalidArgumentException;
use IteratorAggregate; use IteratorAggregate;
use PDO;
use function array_merge; use function array_merge;
use function array_values; use function array_values;
use function assert; use function assert;
...@@ -105,7 +104,7 @@ class ResultCacheStatement implements IteratorAggregate, ResultStatement ...@@ -105,7 +104,7 @@ class ResultCacheStatement implements IteratorAggregate, ResultStatement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) public function setFetchMode($fetchMode, ...$args)
{ {
$this->defaultFetchMode = $fetchMode; $this->defaultFetchMode = $fetchMode;
...@@ -125,7 +124,7 @@ class ResultCacheStatement implements IteratorAggregate, ResultStatement ...@@ -125,7 +124,7 @@ class ResultCacheStatement implements IteratorAggregate, ResultStatement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) public function fetch($fetchMode = null, ...$args)
{ {
if ($this->data === null) { if ($this->data === null) {
$this->data = []; $this->data = [];
...@@ -165,9 +164,9 @@ class ResultCacheStatement implements IteratorAggregate, ResultStatement ...@@ -165,9 +164,9 @@ class ResultCacheStatement implements IteratorAggregate, ResultStatement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) public function fetchAll($fetchMode = null, ...$args)
{ {
$data = $this->statement->fetchAll($fetchMode, $fetchArgument, $ctorArgs); $data = $this->statement->fetchAll($fetchMode, ...$args);
if ($fetchMode === FetchMode::COLUMN) { if ($fetchMode === FetchMode::COLUMN) {
foreach ($data as $key => $value) { foreach ($data as $key => $value) {
...@@ -203,7 +202,7 @@ class ResultCacheStatement implements IteratorAggregate, ResultStatement ...@@ -203,7 +202,7 @@ class ResultCacheStatement implements IteratorAggregate, ResultStatement
* *
* @return int The number of rows. * @return int The number of rows.
*/ */
public function rowCount() public function rowCount() : int
{ {
assert($this->statement instanceof Statement); assert($this->statement instanceof Statement);
......
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
namespace Doctrine\DBAL; namespace Doctrine\DBAL;
use PDO;
/** /**
* Contains portable column case conversions. * Contains portable column case conversions.
*/ */
...@@ -14,14 +12,14 @@ final class ColumnCase ...@@ -14,14 +12,14 @@ final class ColumnCase
* *
* @see \PDO::CASE_UPPER * @see \PDO::CASE_UPPER
*/ */
public const UPPER = PDO::CASE_UPPER; public const UPPER = 1;
/** /**
* Convert column names to lower case. * Convert column names to lower case.
* *
* @see \PDO::CASE_LOWER * @see \PDO::CASE_LOWER
*/ */
public const LOWER = PDO::CASE_LOWER; public const LOWER = 2;
/** /**
* This class cannot be instantiated. * This class cannot be instantiated.
......
...@@ -23,7 +23,6 @@ use Exception; ...@@ -23,7 +23,6 @@ use Exception;
use Throwable; use Throwable;
use function array_key_exists; use function array_key_exists;
use function assert; use function assert;
use function func_get_args;
use function implode; use function implode;
use function is_int; use function is_int;
use function is_string; use function is_string;
...@@ -188,12 +187,6 @@ class Connection implements DriverConnection ...@@ -188,12 +187,6 @@ class Connection implements DriverConnection
$this->_driver = $driver; $this->_driver = $driver;
$this->params = $params; $this->params = $params;
if (isset($params['pdo'])) {
$this->_conn = $params['pdo'];
$this->isConnected = true;
unset($this->params['pdo']);
}
if (isset($params['platform'])) { if (isset($params['platform'])) {
if (! $params['platform'] instanceof Platforms\AbstractPlatform) { if (! $params['platform'] instanceof Platforms\AbstractPlatform) {
throw DBALException::invalidPlatformType($params['platform']); throw DBALException::invalidPlatformType($params['platform']);
...@@ -847,18 +840,16 @@ class Connection implements DriverConnection ...@@ -847,18 +840,16 @@ class Connection implements DriverConnection
/** /**
* Prepares an SQL statement. * Prepares an SQL statement.
* *
* @param string $statement The SQL statement to prepare. * @param string $sql The SQL statement to prepare.
*
* @return DriverStatement The prepared statement.
* *
* @throws DBALException * @throws DBALException
*/ */
public function prepare($statement) public function prepare(string $sql) : DriverStatement
{ {
try { try {
$stmt = new Statement($statement, $this); $stmt = new Statement($sql, $this);
} catch (Throwable $ex) { } catch (Throwable $ex) {
throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $statement); throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $sql);
} }
$stmt->setFetchMode($this->defaultFetchMode); $stmt->setFetchMode($this->defaultFetchMode);
...@@ -881,7 +872,7 @@ class Connection implements DriverConnection ...@@ -881,7 +872,7 @@ class Connection implements DriverConnection
* *
* @throws DBALException * @throws DBALException
*/ */
public function executeQuery($query, array $params = [], $types = [], ?QueryCacheProfile $qcp = null) public function executeQuery(string $query, array $params = [], $types = [], ?QueryCacheProfile $qcp = null) : ResultStatement
{ {
if ($qcp !== null) { if ($qcp !== null) {
return $this->executeCacheQuery($query, $params, $types, $qcp); return $this->executeCacheQuery($query, $params, $types, $qcp);
...@@ -929,11 +920,9 @@ class Connection implements DriverConnection ...@@ -929,11 +920,9 @@ class Connection implements DriverConnection
* @param int[]|string[] $types The types the previous parameters are in. * @param int[]|string[] $types The types the previous parameters are in.
* @param QueryCacheProfile $qcp The query cache profile. * @param QueryCacheProfile $qcp The query cache profile.
* *
* @return ResultStatement
*
* @throws CacheException * @throws CacheException
*/ */
public function executeCacheQuery($query, $params, $types, QueryCacheProfile $qcp) public function executeCacheQuery($query, $params, $types, QueryCacheProfile $qcp) : ResultStatement
{ {
$resultCache = $qcp->getResultCacheDriver() ?? $this->_config->getResultCacheImpl(); $resultCache = $qcp->getResultCacheDriver() ?? $this->_config->getResultCacheImpl();
...@@ -994,27 +983,21 @@ class Connection implements DriverConnection ...@@ -994,27 +983,21 @@ class Connection implements DriverConnection
} }
/** /**
* Executes an SQL statement, returning a result set as a Statement object. * {@inheritDoc}
*
* @return \Doctrine\DBAL\Driver\Statement
*
* @throws DBALException
*/ */
public function query() public function query(string $sql) : ResultStatement
{ {
$connection = $this->getWrappedConnection(); $connection = $this->getWrappedConnection();
$args = func_get_args();
$logger = $this->_config->getSQLLogger(); $logger = $this->_config->getSQLLogger();
if ($logger) { if ($logger) {
$logger->startQuery($args[0]); $logger->startQuery($sql);
} }
try { try {
$statement = $connection->query(...$args); $statement = $connection->query($sql);
} catch (Throwable $ex) { } catch (Throwable $ex) {
throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $args[0]); throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $sql);
} }
$statement->setFetchMode($this->defaultFetchMode); $statement->setFetchMode($this->defaultFetchMode);
...@@ -1036,11 +1019,9 @@ class Connection implements DriverConnection ...@@ -1036,11 +1019,9 @@ class Connection implements DriverConnection
* @param mixed[] $params The query parameters. * @param mixed[] $params The query parameters.
* @param int[]|string[] $types The parameter types. * @param int[]|string[] $types The parameter types.
* *
* @return int The number of affected rows.
*
* @throws DBALException * @throws DBALException
*/ */
public function executeUpdate($query, array $params = [], array $types = []) public function executeUpdate(string $query, array $params = [], array $types = []) : int
{ {
$connection = $this->getWrappedConnection(); $connection = $this->getWrappedConnection();
...@@ -1077,15 +1058,9 @@ class Connection implements DriverConnection ...@@ -1077,15 +1058,9 @@ class Connection implements DriverConnection
} }
/** /**
* Executes an SQL statement and return the number of affected rows. * {@inheritDoc}
*
* @param string $statement
*
* @return int The number of affected rows.
*
* @throws DBALException
*/ */
public function exec($statement) public function exec(string $statement) : int
{ {
$connection = $this->getWrappedConnection(); $connection = $this->getWrappedConnection();
...@@ -1527,13 +1502,11 @@ class Connection implements DriverConnection ...@@ -1527,13 +1502,11 @@ class Connection implements DriverConnection
* @internal Duck-typing used on the $stmt parameter to support driver statements as well as * @internal Duck-typing used on the $stmt parameter to support driver statements as well as
* raw PDOStatement instances. * raw PDOStatement instances.
* *
* @param \Doctrine\DBAL\Driver\Statement $stmt The statement to bind the values to. * @param DriverStatement $stmt The statement to bind the values to.
* @param mixed[] $params The map/list of named/positional parameters. * @param mixed[] $params The map/list of named/positional parameters.
* @param int[]|string[] $types The parameter types (PDO binding types or DBAL mapping types). * @param int[]|string[] $types The parameter types (PDO binding types or DBAL mapping types).
*
* @return void
*/ */
private function _bindTypedValues($stmt, array $params, array $types) private function _bindTypedValues(DriverStatement $stmt, array $params, array $types) : void
{ {
// Check whether parameters are positional or named. Mixing is not allowed, just like in PDO. // Check whether parameters are positional or named. Mixing is not allowed, just like in PDO.
if (is_int(key($params))) { if (is_int(key($params))) {
......
...@@ -7,13 +7,14 @@ use Doctrine\DBAL\Configuration; ...@@ -7,13 +7,14 @@ use Doctrine\DBAL\Configuration;
use Doctrine\DBAL\Connection; use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver; use Doctrine\DBAL\Driver;
use Doctrine\DBAL\Driver\Connection as DriverConnection; use Doctrine\DBAL\Driver\Connection as DriverConnection;
use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\DBAL\Driver\Statement;
use Doctrine\DBAL\Event\ConnectionEventArgs; use Doctrine\DBAL\Event\ConnectionEventArgs;
use Doctrine\DBAL\Events; use Doctrine\DBAL\Events;
use InvalidArgumentException; use InvalidArgumentException;
use function array_rand; use function array_rand;
use function assert; use function assert;
use function count; use function count;
use function func_get_args;
/** /**
* Master-Slave Connection * Master-Slave Connection
...@@ -219,7 +220,7 @@ class MasterSlaveConnection extends Connection ...@@ -219,7 +220,7 @@ class MasterSlaveConnection extends Connection
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public function executeUpdate($query, array $params = [], array $types = []) public function executeUpdate(string $query, array $params = [], array $types = []) : int
{ {
$this->connect('master'); $this->connect('master');
...@@ -302,7 +303,7 @@ class MasterSlaveConnection extends Connection ...@@ -302,7 +303,7 @@ class MasterSlaveConnection extends Connection
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public function exec($statement) public function exec(string $statement) : int
{ {
$this->connect('master'); $this->connect('master');
...@@ -342,19 +343,17 @@ class MasterSlaveConnection extends Connection ...@@ -342,19 +343,17 @@ class MasterSlaveConnection extends Connection
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public function query() public function query(string $sql) : ResultStatement
{ {
$this->connect('master'); $this->connect('master');
assert($this->_conn instanceof DriverConnection); assert($this->_conn instanceof DriverConnection);
$args = func_get_args();
$logger = $this->getConfiguration()->getSQLLogger(); $logger = $this->getConfiguration()->getSQLLogger();
if ($logger) { if ($logger) {
$logger->startQuery($args[0]); $logger->startQuery($sql);
} }
$statement = $this->_conn->query(...$args); $statement = $this->_conn->query($sql);
$statement->setFetchMode($this->defaultFetchMode); $statement->setFetchMode($this->defaultFetchMode);
...@@ -368,10 +367,10 @@ class MasterSlaveConnection extends Connection ...@@ -368,10 +367,10 @@ class MasterSlaveConnection extends Connection
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public function prepare($statement) public function prepare(string $sql) : Statement
{ {
$this->connect('master'); $this->connect('master');
return parent::prepare($statement); return parent::prepare($sql);
} }
} }
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
namespace Doctrine\DBAL\Driver; namespace Doctrine\DBAL\Driver;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\ParameterType;
/** /**
...@@ -14,19 +15,15 @@ interface Connection ...@@ -14,19 +15,15 @@ interface Connection
{ {
/** /**
* Prepares a statement for execution and returns a Statement object. * Prepares a statement for execution and returns a Statement object.
*
* @param string $prepareString
*
* @return Statement
*/ */
public function prepare($prepareString); public function prepare(string $sql) : Statement;
/** /**
* Executes an SQL statement, returning a result set as a Statement object. * Executes an SQL statement, returning a result set as a Statement object.
* *
* @return Statement * @throws DBALException
*/ */
public function query(); public function query(string $sql) : ResultStatement;
/** /**
* Quotes a string for use in a query. * Quotes a string for use in a query.
...@@ -41,11 +38,9 @@ interface Connection ...@@ -41,11 +38,9 @@ interface Connection
/** /**
* Executes an SQL statement and return the number of affected rows. * Executes an SQL statement and return the number of affected rows.
* *
* @param string $statement * @throws DBALException
*
* @return int
*/ */
public function exec($statement); public function exec(string $statement) : int;
/** /**
* Returns the ID of the last inserted row or sequence value. * Returns the ID of the last inserted row or sequence value.
......
...@@ -3,7 +3,9 @@ ...@@ -3,7 +3,9 @@
namespace Doctrine\DBAL\Driver\IBMDB2; namespace Doctrine\DBAL\Driver\IBMDB2;
use Doctrine\DBAL\Driver\Connection; use Doctrine\DBAL\Driver\Connection;
use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\DBAL\Driver\ServerInfoAwareConnection; use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
use Doctrine\DBAL\Driver\Statement as DriverStatement;
use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\ParameterType;
use stdClass; use stdClass;
use const DB2_AUTOCOMMIT_OFF; use const DB2_AUTOCOMMIT_OFF;
...@@ -22,7 +24,6 @@ use function db2_prepare; ...@@ -22,7 +24,6 @@ use function db2_prepare;
use function db2_rollback; use function db2_rollback;
use function db2_server_info; use function db2_server_info;
use function db2_stmt_errormsg; use function db2_stmt_errormsg;
use function func_get_args;
class DB2Connection implements Connection, ServerInfoAwareConnection class DB2Connection implements Connection, ServerInfoAwareConnection
{ {
...@@ -76,7 +77,7 @@ class DB2Connection implements Connection, ServerInfoAwareConnection ...@@ -76,7 +77,7 @@ class DB2Connection implements Connection, ServerInfoAwareConnection
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function prepare($sql) public function prepare(string $sql) : DriverStatement
{ {
$stmt = @db2_prepare($this->conn, $sql); $stmt = @db2_prepare($this->conn, $sql);
if (! $stmt) { if (! $stmt) {
...@@ -89,10 +90,8 @@ class DB2Connection implements Connection, ServerInfoAwareConnection ...@@ -89,10 +90,8 @@ class DB2Connection implements Connection, ServerInfoAwareConnection
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function query() public function query(string $sql) : ResultStatement
{ {
$args = func_get_args();
$sql = $args[0];
$stmt = $this->prepare($sql); $stmt = $this->prepare($sql);
$stmt->execute(); $stmt->execute();
...@@ -116,7 +115,7 @@ class DB2Connection implements Connection, ServerInfoAwareConnection ...@@ -116,7 +115,7 @@ class DB2Connection implements Connection, ServerInfoAwareConnection
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function exec($statement) public function exec(string $statement) : int
{ {
$stmt = @db2_exec($this->conn, $statement); $stmt = @db2_exec($this->conn, $statement);
......
...@@ -7,7 +7,6 @@ use Doctrine\DBAL\Driver\StatementIterator; ...@@ -7,7 +7,6 @@ use Doctrine\DBAL\Driver\StatementIterator;
use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\FetchMode;
use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\ParameterType;
use IteratorAggregate; use IteratorAggregate;
use PDO;
use ReflectionClass; use ReflectionClass;
use ReflectionObject; use ReflectionObject;
use ReflectionProperty; use ReflectionProperty;
...@@ -19,6 +18,7 @@ use const DB2_LONG; ...@@ -19,6 +18,7 @@ use const DB2_LONG;
use const DB2_PARAM_FILE; use const DB2_PARAM_FILE;
use const DB2_PARAM_IN; use const DB2_PARAM_IN;
use function array_change_key_case; use function array_change_key_case;
use function count;
use function db2_bind_param; use function db2_bind_param;
use function db2_execute; use function db2_execute;
use function db2_fetch_array; use function db2_fetch_array;
...@@ -32,8 +32,6 @@ use function db2_stmt_error; ...@@ -32,8 +32,6 @@ use function db2_stmt_error;
use function db2_stmt_errormsg; use function db2_stmt_errormsg;
use function error_get_last; use function error_get_last;
use function fclose; use function fclose;
use function func_get_args;
use function func_num_args;
use function fwrite; use function fwrite;
use function gettype; use function gettype;
use function is_object; use function is_object;
...@@ -229,11 +227,17 @@ class DB2Statement implements IteratorAggregate, Statement ...@@ -229,11 +227,17 @@ class DB2Statement implements IteratorAggregate, Statement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) public function setFetchMode($fetchMode, ...$args)
{ {
$this->defaultFetchMode = $fetchMode; $this->defaultFetchMode = $fetchMode;
$this->defaultFetchClass = $arg2 ?: $this->defaultFetchClass;
$this->defaultFetchClassCtorArgs = $arg3 ? (array) $arg3 : $this->defaultFetchClassCtorArgs; if (isset($args[0])) {
$this->defaultFetchClass = $args[0];
}
if (isset($args[1])) {
$this->defaultFetchClassCtorArgs = (array) $args[1];
}
return true; return true;
} }
...@@ -249,7 +253,7 @@ class DB2Statement implements IteratorAggregate, Statement ...@@ -249,7 +253,7 @@ class DB2Statement implements IteratorAggregate, Statement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) public function fetch($fetchMode = null, ...$args)
{ {
// do not try fetching from the statement if it's not expected to contain result // do not try fetching from the statement if it's not expected to contain result
// in order to prevent exceptional situation // in order to prevent exceptional situation
...@@ -272,10 +276,9 @@ class DB2Statement implements IteratorAggregate, Statement ...@@ -272,10 +276,9 @@ class DB2Statement implements IteratorAggregate, Statement
$className = $this->defaultFetchClass; $className = $this->defaultFetchClass;
$ctorArgs = $this->defaultFetchClassCtorArgs; $ctorArgs = $this->defaultFetchClassCtorArgs;
if (func_num_args() >= 2) { if (count($args) > 0) {
$args = func_get_args(); $className = $args[0];
$className = $args[1]; $ctorArgs = $args[1] ?? [];
$ctorArgs = $args[2] ?? [];
} }
$result = db2_fetch_object($this->stmt); $result = db2_fetch_object($this->stmt);
...@@ -300,13 +303,13 @@ class DB2Statement implements IteratorAggregate, Statement ...@@ -300,13 +303,13 @@ class DB2Statement implements IteratorAggregate, Statement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) public function fetchAll($fetchMode = null, ...$args)
{ {
$rows = []; $rows = [];
switch ($fetchMode) { switch ($fetchMode) {
case FetchMode::CUSTOM_OBJECT: case FetchMode::CUSTOM_OBJECT:
while (($row = $this->fetch(...func_get_args())) !== false) { while (($row = $this->fetch($fetchMode, ...$args)) !== false) {
$rows[] = $row; $rows[] = $row;
} }
break; break;
...@@ -341,7 +344,7 @@ class DB2Statement implements IteratorAggregate, Statement ...@@ -341,7 +344,7 @@ class DB2Statement implements IteratorAggregate, Statement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function rowCount() public function rowCount() : int
{ {
return @db2_num_rows($this->stmt) ? : 0; return @db2_num_rows($this->stmt) ? : 0;
} }
......
...@@ -4,7 +4,9 @@ namespace Doctrine\DBAL\Driver\Mysqli; ...@@ -4,7 +4,9 @@ namespace Doctrine\DBAL\Driver\Mysqli;
use Doctrine\DBAL\Driver\Connection; use Doctrine\DBAL\Driver\Connection;
use Doctrine\DBAL\Driver\PingableConnection; use Doctrine\DBAL\Driver\PingableConnection;
use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\DBAL\Driver\ServerInfoAwareConnection; use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
use Doctrine\DBAL\Driver\Statement as DriverStatement;
use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\ParameterType;
use mysqli; use mysqli;
use const MYSQLI_INIT_COMMAND; use const MYSQLI_INIT_COMMAND;
...@@ -15,7 +17,6 @@ use const MYSQLI_READ_DEFAULT_GROUP; ...@@ -15,7 +17,6 @@ use const MYSQLI_READ_DEFAULT_GROUP;
use const MYSQLI_SERVER_PUBLIC_KEY; use const MYSQLI_SERVER_PUBLIC_KEY;
use function defined; use function defined;
use function floor; use function floor;
use function func_get_args;
use function in_array; use function in_array;
use function ini_get; use function ini_get;
use function mysqli_errno; use function mysqli_errno;
...@@ -56,6 +57,11 @@ class MysqliConnection implements Connection, PingableConnection, ServerInfoAwar ...@@ -56,6 +57,11 @@ class MysqliConnection implements Connection, PingableConnection, ServerInfoAwar
$socket = $params['unix_socket'] ?? ini_get('mysqli.default_socket'); $socket = $params['unix_socket'] ?? ini_get('mysqli.default_socket');
$dbname = $params['dbname'] ?? null; $dbname = $params['dbname'] ?? null;
$host = $params['host'];
if (! empty($params['persistent'])) {
$host = 'p:' . $host;
}
$flags = $driverOptions[static::OPTION_FLAGS] ?? null; $flags = $driverOptions[static::OPTION_FLAGS] ?? null;
...@@ -67,7 +73,7 @@ class MysqliConnection implements Connection, PingableConnection, ServerInfoAwar ...@@ -67,7 +73,7 @@ class MysqliConnection implements Connection, PingableConnection, ServerInfoAwar
set_error_handler(static function () { set_error_handler(static function () {
}); });
try { try {
if (! $this->conn->real_connect($params['host'], $username, $password, $dbname, $port, $socket, $flags)) { if (! $this->conn->real_connect($host, $username, $password, $dbname, $port, $socket, $flags)) {
throw new MysqliException($this->conn->connect_error, $this->conn->sqlstate ?? 'HY000', $this->conn->connect_errno); throw new MysqliException($this->conn->connect_error, $this->conn->sqlstate ?? 'HY000', $this->conn->connect_errno);
} }
} finally { } finally {
...@@ -126,18 +132,16 @@ class MysqliConnection implements Connection, PingableConnection, ServerInfoAwar ...@@ -126,18 +132,16 @@ class MysqliConnection implements Connection, PingableConnection, ServerInfoAwar
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function prepare($prepareString) public function prepare(string $sql) : DriverStatement
{ {
return new MysqliStatement($this->conn, $prepareString); return new MysqliStatement($this->conn, $sql);
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function query() public function query(string $sql) : ResultStatement
{ {
$args = func_get_args();
$sql = $args[0];
$stmt = $this->prepare($sql); $stmt = $this->prepare($sql);
$stmt->execute(); $stmt->execute();
...@@ -155,7 +159,7 @@ class MysqliConnection implements Connection, PingableConnection, ServerInfoAwar ...@@ -155,7 +159,7 @@ class MysqliConnection implements Connection, PingableConnection, ServerInfoAwar
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function exec($statement) public function exec(string $statement) : int
{ {
if ($this->conn->query($statement) === false) { if ($this->conn->query($statement) === false) {
throw new MysqliException($this->conn->error, $this->conn->sqlstate, $this->conn->errno); throw new MysqliException($this->conn->error, $this->conn->sqlstate, $this->conn->errno);
......
...@@ -10,7 +10,6 @@ use Doctrine\DBAL\ParameterType; ...@@ -10,7 +10,6 @@ use Doctrine\DBAL\ParameterType;
use IteratorAggregate; use IteratorAggregate;
use mysqli; use mysqli;
use mysqli_stmt; use mysqli_stmt;
use PDO;
use function array_combine; use function array_combine;
use function array_fill; use function array_fill;
use function assert; use function assert;
...@@ -303,7 +302,7 @@ class MysqliStatement implements IteratorAggregate, Statement ...@@ -303,7 +302,7 @@ class MysqliStatement implements IteratorAggregate, Statement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) public function fetch($fetchMode = null, ...$args)
{ {
// do not try fetching from the statement if it's not expected to contain result // do not try fetching from the statement if it's not expected to contain result
// in order to prevent exceptional situation // in order to prevent exceptional situation
...@@ -353,7 +352,7 @@ class MysqliStatement implements IteratorAggregate, Statement ...@@ -353,7 +352,7 @@ class MysqliStatement implements IteratorAggregate, Statement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) public function fetchAll($fetchMode = null, ...$args)
{ {
$fetchMode = $fetchMode ?: $this->_defaultFetchMode; $fetchMode = $fetchMode ?: $this->_defaultFetchMode;
...@@ -416,7 +415,7 @@ class MysqliStatement implements IteratorAggregate, Statement ...@@ -416,7 +415,7 @@ class MysqliStatement implements IteratorAggregate, Statement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function rowCount() public function rowCount() : int
{ {
if ($this->_columnNames === false) { if ($this->_columnNames === false) {
return $this->_stmt->affected_rows; return $this->_stmt->affected_rows;
...@@ -436,7 +435,7 @@ class MysqliStatement implements IteratorAggregate, Statement ...@@ -436,7 +435,7 @@ class MysqliStatement implements IteratorAggregate, Statement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) public function setFetchMode($fetchMode, ...$args)
{ {
$this->_defaultFetchMode = $fetchMode; $this->_defaultFetchMode = $fetchMode;
......
...@@ -3,14 +3,15 @@ ...@@ -3,14 +3,15 @@
namespace Doctrine\DBAL\Driver\OCI8; namespace Doctrine\DBAL\Driver\OCI8;
use Doctrine\DBAL\Driver\Connection; use Doctrine\DBAL\Driver\Connection;
use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\DBAL\Driver\ServerInfoAwareConnection; use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
use Doctrine\DBAL\Driver\Statement as DriverStatement;
use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\ParameterType;
use UnexpectedValueException; use UnexpectedValueException;
use const OCI_COMMIT_ON_SUCCESS; use const OCI_COMMIT_ON_SUCCESS;
use const OCI_DEFAULT; use const OCI_DEFAULT;
use const OCI_NO_AUTO_COMMIT; use const OCI_NO_AUTO_COMMIT;
use function addcslashes; use function addcslashes;
use function func_get_args;
use function is_float; use function is_float;
use function is_int; use function is_int;
use function oci_commit; use function oci_commit;
...@@ -103,19 +104,16 @@ class OCI8Connection implements Connection, ServerInfoAwareConnection ...@@ -103,19 +104,16 @@ class OCI8Connection implements Connection, ServerInfoAwareConnection
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function prepare($prepareString) public function prepare(string $sql) : DriverStatement
{ {
return new OCI8Statement($this->dbh, $prepareString, $this); return new OCI8Statement($this->dbh, $sql, $this);
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function query() public function query(string $sql) : ResultStatement
{ {
$args = func_get_args();
$sql = $args[0];
//$fetchMode = $args[1];
$stmt = $this->prepare($sql); $stmt = $this->prepare($sql);
$stmt->execute(); $stmt->execute();
...@@ -138,7 +136,7 @@ class OCI8Connection implements Connection, ServerInfoAwareConnection ...@@ -138,7 +136,7 @@ class OCI8Connection implements Connection, ServerInfoAwareConnection
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function exec($statement) public function exec(string $statement) : int
{ {
$stmt = $this->prepare($statement); $stmt = $this->prepare($statement);
$stmt->execute(); $stmt->execute();
......
...@@ -8,7 +8,6 @@ use Doctrine\DBAL\FetchMode; ...@@ -8,7 +8,6 @@ use Doctrine\DBAL\FetchMode;
use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\ParameterType;
use InvalidArgumentException; use InvalidArgumentException;
use IteratorAggregate; use IteratorAggregate;
use PDO;
use const OCI_ASSOC; use const OCI_ASSOC;
use const OCI_B_BIN; use const OCI_B_BIN;
use const OCI_B_BLOB; use const OCI_B_BLOB;
...@@ -407,7 +406,7 @@ class OCI8Statement implements IteratorAggregate, Statement ...@@ -407,7 +406,7 @@ class OCI8Statement implements IteratorAggregate, Statement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) public function setFetchMode($fetchMode, ...$args)
{ {
$this->_defaultFetchMode = $fetchMode; $this->_defaultFetchMode = $fetchMode;
...@@ -425,7 +424,7 @@ class OCI8Statement implements IteratorAggregate, Statement ...@@ -425,7 +424,7 @@ class OCI8Statement implements IteratorAggregate, Statement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) public function fetch($fetchMode = null, ...$args)
{ {
// do not try fetching from the statement if it's not expected to contain result // do not try fetching from the statement if it's not expected to contain result
// in order to prevent exceptional situation // in order to prevent exceptional situation
...@@ -456,7 +455,7 @@ class OCI8Statement implements IteratorAggregate, Statement ...@@ -456,7 +455,7 @@ class OCI8Statement implements IteratorAggregate, Statement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) public function fetchAll($fetchMode = null, ...$args)
{ {
$fetchMode = $fetchMode ?: $this->_defaultFetchMode; $fetchMode = $fetchMode ?: $this->_defaultFetchMode;
...@@ -530,7 +529,7 @@ class OCI8Statement implements IteratorAggregate, Statement ...@@ -530,7 +529,7 @@ class OCI8Statement implements IteratorAggregate, Statement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function rowCount() public function rowCount() : int
{ {
return oci_num_rows($this->_sth) ?: 0; return oci_num_rows($this->_sth) ?: 0;
} }
......
...@@ -5,14 +5,17 @@ namespace Doctrine\DBAL\Driver; ...@@ -5,14 +5,17 @@ namespace Doctrine\DBAL\Driver;
use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\ParameterType;
use PDO; use PDO;
use function assert; use function assert;
use function func_get_args;
/** /**
* PDO implementation of the Connection interface. * PDO implementation of the Connection interface.
*
* Used by all PDO-based drivers. * Used by all PDO-based drivers.
*/ */
class PDOConnection extends PDO implements Connection, ServerInfoAwareConnection class PDOConnection implements Connection, ServerInfoAwareConnection
{ {
/** @var PDO */
private $connection;
/** /**
* @param string $dsn * @param string $dsn
* @param string|null $user * @param string|null $user
...@@ -24,9 +27,8 @@ class PDOConnection extends PDO implements Connection, ServerInfoAwareConnection ...@@ -24,9 +27,8 @@ class PDOConnection extends PDO implements Connection, ServerInfoAwareConnection
public function __construct($dsn, $user = null, $password = null, ?array $options = null) public function __construct($dsn, $user = null, $password = null, ?array $options = null)
{ {
try { try {
parent::__construct($dsn, (string) $user, (string) $password, (array) $options); $this->connection = new PDO($dsn, (string) $user, (string) $password, (array) $options);
$this->setAttribute(PDO::ATTR_STATEMENT_CLASS, [PDOStatement::class, []]); $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (\PDOException $exception) { } catch (\PDOException $exception) {
throw new PDOException($exception); throw new PDOException($exception);
} }
...@@ -35,10 +37,10 @@ class PDOConnection extends PDO implements Connection, ServerInfoAwareConnection ...@@ -35,10 +37,10 @@ class PDOConnection extends PDO implements Connection, ServerInfoAwareConnection
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function exec($statement) public function exec(string $statement) : int
{ {
try { try {
return parent::exec($statement); return $this->connection->exec($statement);
} catch (\PDOException $exception) { } catch (\PDOException $exception) {
throw new PDOException($exception); throw new PDOException($exception);
} }
...@@ -49,16 +51,18 @@ class PDOConnection extends PDO implements Connection, ServerInfoAwareConnection ...@@ -49,16 +51,18 @@ class PDOConnection extends PDO implements Connection, ServerInfoAwareConnection
*/ */
public function getServerVersion() public function getServerVersion()
{ {
return PDO::getAttribute(PDO::ATTR_SERVER_VERSION); return $this->connection->getAttribute(PDO::ATTR_SERVER_VERSION);
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function prepare($prepareString, $driverOptions = []) public function prepare(string $sql) : Statement
{ {
try { try {
return parent::prepare($prepareString, $driverOptions); return $this->createStatement(
$this->connection->prepare($sql)
);
} catch (\PDOException $exception) { } catch (\PDOException $exception) {
throw new PDOException($exception); throw new PDOException($exception);
} }
...@@ -67,15 +71,13 @@ class PDOConnection extends PDO implements Connection, ServerInfoAwareConnection ...@@ -67,15 +71,13 @@ class PDOConnection extends PDO implements Connection, ServerInfoAwareConnection
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function query() public function query(string $sql) : ResultStatement
{ {
$args = func_get_args();
try { try {
$stmt = parent::query(...$args); $stmt = $this->connection->query($sql);
assert($stmt instanceof \PDOStatement); assert($stmt instanceof \PDOStatement);
return $stmt; return $this->createStatement($stmt);
} catch (\PDOException $exception) { } catch (\PDOException $exception) {
throw new PDOException($exception); throw new PDOException($exception);
} }
...@@ -86,7 +88,7 @@ class PDOConnection extends PDO implements Connection, ServerInfoAwareConnection ...@@ -86,7 +88,7 @@ class PDOConnection extends PDO implements Connection, ServerInfoAwareConnection
*/ */
public function quote($input, $type = ParameterType::STRING) public function quote($input, $type = ParameterType::STRING)
{ {
return parent::quote($input, $type); return $this->connection->quote($input, $type);
} }
/** /**
...@@ -96,10 +98,10 @@ class PDOConnection extends PDO implements Connection, ServerInfoAwareConnection ...@@ -96,10 +98,10 @@ class PDOConnection extends PDO implements Connection, ServerInfoAwareConnection
{ {
try { try {
if ($name === null) { if ($name === null) {
return parent::lastInsertId(); return $this->connection->lastInsertId();
} }
return parent::lastInsertId($name); return $this->connection->lastInsertId($name);
} catch (\PDOException $exception) { } catch (\PDOException $exception) {
throw new PDOException($exception); throw new PDOException($exception);
} }
...@@ -112,4 +114,57 @@ class PDOConnection extends PDO implements Connection, ServerInfoAwareConnection ...@@ -112,4 +114,57 @@ class PDOConnection extends PDO implements Connection, ServerInfoAwareConnection
{ {
return false; return false;
} }
/**
* Creates a wrapped statement
*/
protected function createStatement(\PDOStatement $stmt) : PDOStatement
{
return new PDOStatement($stmt);
}
/**
* {@inheritDoc}
*/
public function beginTransaction()
{
return $this->connection->beginTransaction();
}
/**
* {@inheritDoc}
*/
public function commit()
{
return $this->connection->commit();
}
/**
* {@inheritDoc}
*/
public function rollBack()
{
return $this->connection->rollBack();
}
/**
* {@inheritDoc}
*/
public function errorCode()
{
return $this->connection->errorCode();
}
/**
* {@inheritDoc}
*/
public function errorInfo()
{
return $this->connection->errorInfo();
}
public function getWrappedConnection() : PDO
{
return $this->connection;
}
} }
...@@ -5,6 +5,7 @@ namespace Doctrine\DBAL\Driver\PDOMySql; ...@@ -5,6 +5,7 @@ namespace Doctrine\DBAL\Driver\PDOMySql;
use Doctrine\DBAL\DBALException; use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver\AbstractMySQLDriver; use Doctrine\DBAL\Driver\AbstractMySQLDriver;
use Doctrine\DBAL\Driver\PDOConnection; use Doctrine\DBAL\Driver\PDOConnection;
use PDO;
use PDOException; use PDOException;
/** /**
...@@ -17,6 +18,10 @@ class Driver extends AbstractMySQLDriver ...@@ -17,6 +18,10 @@ class Driver extends AbstractMySQLDriver
*/ */
public function connect(array $params, $username = null, $password = null, array $driverOptions = []) public function connect(array $params, $username = null, $password = null, array $driverOptions = [])
{ {
if (! empty($params['persistent'])) {
$driverOptions[PDO::ATTR_PERSISTENT] = true;
}
try { try {
$conn = new PDOConnection( $conn = new PDOConnection(
$this->constructPdoDsn($params), $this->constructPdoDsn($params),
......
...@@ -5,6 +5,7 @@ namespace Doctrine\DBAL\Driver\PDOOracle; ...@@ -5,6 +5,7 @@ namespace Doctrine\DBAL\Driver\PDOOracle;
use Doctrine\DBAL\DBALException; use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver\AbstractOracleDriver; use Doctrine\DBAL\Driver\AbstractOracleDriver;
use Doctrine\DBAL\Driver\PDOConnection; use Doctrine\DBAL\Driver\PDOConnection;
use PDO;
use PDOException; use PDOException;
/** /**
...@@ -22,6 +23,10 @@ class Driver extends AbstractOracleDriver ...@@ -22,6 +23,10 @@ class Driver extends AbstractOracleDriver
*/ */
public function connect(array $params, $username = null, $password = null, array $driverOptions = []) public function connect(array $params, $username = null, $password = null, array $driverOptions = [])
{ {
if (! empty($params['persistent'])) {
$driverOptions[PDO::ATTR_PERSISTENT] = true;
}
try { try {
return new PDOConnection( return new PDOConnection(
$this->constructPdoDsn($params), $this->constructPdoDsn($params),
......
...@@ -19,8 +19,12 @@ class Driver extends AbstractPostgreSQLDriver ...@@ -19,8 +19,12 @@ class Driver extends AbstractPostgreSQLDriver
*/ */
public function connect(array $params, $username = null, $password = null, array $driverOptions = []) public function connect(array $params, $username = null, $password = null, array $driverOptions = [])
{ {
if (! empty($params['persistent'])) {
$driverOptions[PDO::ATTR_PERSISTENT] = true;
}
try { try {
$pdo = new PDOConnection( $connection = new PDOConnection(
$this->_constructPdoDsn($params), $this->_constructPdoDsn($params),
$username, $username,
$password, $password,
...@@ -32,7 +36,7 @@ class Driver extends AbstractPostgreSQLDriver ...@@ -32,7 +36,7 @@ class Driver extends AbstractPostgreSQLDriver
|| $driverOptions[PDO::PGSQL_ATTR_DISABLE_PREPARES] === true || $driverOptions[PDO::PGSQL_ATTR_DISABLE_PREPARES] === true
) )
) { ) {
$pdo->setAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES, true); $connection->getWrappedConnection()->setAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES, true);
} }
/* defining client_encoding via SET NAMES to avoid inconsistent DSN support /* defining client_encoding via SET NAMES to avoid inconsistent DSN support
...@@ -40,10 +44,10 @@ class Driver extends AbstractPostgreSQLDriver ...@@ -40,10 +44,10 @@ class Driver extends AbstractPostgreSQLDriver
* - passing client_encoding via the 'options' param breaks pgbouncer support * - passing client_encoding via the 'options' param breaks pgbouncer support
*/ */
if (isset($params['charset'])) { if (isset($params['charset'])) {
$pdo->exec('SET NAMES \'' . $params['charset'] . '\''); $connection->exec('SET NAMES \'' . $params['charset'] . '\'');
} }
return $pdo; return $connection;
} catch (PDOException $e) { } catch (PDOException $e) {
throw DBALException::driverException($this, $e); throw DBALException::driverException($this, $e);
} }
......
...@@ -35,7 +35,7 @@ class Driver extends AbstractSQLiteDriver ...@@ -35,7 +35,7 @@ class Driver extends AbstractSQLiteDriver
} }
try { try {
$pdo = new PDOConnection( $connection = new PDOConnection(
$this->_constructPdoDsn($params), $this->_constructPdoDsn($params),
$username, $username,
$password, $password,
...@@ -45,11 +45,13 @@ class Driver extends AbstractSQLiteDriver ...@@ -45,11 +45,13 @@ class Driver extends AbstractSQLiteDriver
throw DBALException::driverException($this, $ex); throw DBALException::driverException($this, $ex);
} }
$pdo = $connection->getWrappedConnection();
foreach ($this->_userDefinedFunctions as $fn => $data) { foreach ($this->_userDefinedFunctions as $fn => $data) {
$pdo->sqliteCreateFunction($fn, $data['callback'], $data['numArgs']); $pdo->sqliteCreateFunction($fn, $data['callback'], $data['numArgs']);
} }
return $pdo; return $connection;
} }
/** /**
......
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
namespace Doctrine\DBAL\Driver\PDOSqlsrv; namespace Doctrine\DBAL\Driver\PDOSqlsrv;
use Doctrine\DBAL\Driver\PDOConnection; use Doctrine\DBAL\Driver\PDOConnection;
use Doctrine\DBAL\Driver\PDOStatement;
use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\ParameterType;
use PDO;
use function strpos; use function strpos;
use function substr; use function substr;
...@@ -13,15 +13,6 @@ use function substr; ...@@ -13,15 +13,6 @@ use function substr;
*/ */
class Connection extends PDOConnection class Connection extends PDOConnection
{ {
/**
* {@inheritdoc}
*/
public function __construct($dsn, $user = null, $password = null, ?array $options = null)
{
parent::__construct($dsn, $user, $password, $options);
$this->setAttribute(PDO::ATTR_STATEMENT_CLASS, [Statement::class, []]);
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
...@@ -51,4 +42,12 @@ class Connection extends PDOConnection ...@@ -51,4 +42,12 @@ class Connection extends PDOConnection
return $val; return $val;
} }
/**
* {@inheritDoc}
*/
protected function createStatement(\PDOStatement $stmt) : PDOStatement
{
return new Statement($stmt);
}
} }
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
namespace Doctrine\DBAL\Driver\PDOSqlsrv; namespace Doctrine\DBAL\Driver\PDOSqlsrv;
use Doctrine\DBAL\Driver\AbstractSQLServerDriver; use Doctrine\DBAL\Driver\AbstractSQLServerDriver;
use PDO;
use function is_int; use function is_int;
use function sprintf; use function sprintf;
...@@ -26,6 +27,10 @@ class Driver extends AbstractSQLServerDriver ...@@ -26,6 +27,10 @@ class Driver extends AbstractSQLServerDriver
} }
} }
if (! empty($params['persistent'])) {
$pdoOptions[PDO::ATTR_PERSISTENT] = true;
}
return new Connection( return new Connection(
$this->_constructPdoDsn($params, $dsnOptions), $this->_constructPdoDsn($params, $dsnOptions),
$username, $username,
......
...@@ -4,20 +4,19 @@ namespace Doctrine\DBAL\Driver; ...@@ -4,20 +4,19 @@ namespace Doctrine\DBAL\Driver;
use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\FetchMode;
use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\ParameterType;
use InvalidArgumentException;
use IteratorAggregate;
use PDO; use PDO;
use const E_USER_DEPRECATED;
use function array_slice; use function array_slice;
use function assert; use function assert;
use function func_get_args; use function func_get_args;
use function is_array; use function is_array;
use function sprintf;
use function trigger_error;
/** /**
* The PDO implementation of the Statement interface. * The PDO implementation of the Statement interface.
* Used by all PDO-based drivers. * Used by all PDO-based drivers.
*/ */
class PDOStatement extends \PDOStatement implements Statement class PDOStatement implements IteratorAggregate, Statement
{ {
private const PARAM_TYPE_MAP = [ private const PARAM_TYPE_MAP = [
ParameterType::NULL => PDO::PARAM_NULL, ParameterType::NULL => PDO::PARAM_NULL,
...@@ -37,34 +36,23 @@ class PDOStatement extends \PDOStatement implements Statement ...@@ -37,34 +36,23 @@ class PDOStatement extends \PDOStatement implements Statement
FetchMode::CUSTOM_OBJECT => PDO::FETCH_CLASS, FetchMode::CUSTOM_OBJECT => PDO::FETCH_CLASS,
]; ];
/** /** @var \PDOStatement */
* Protected constructor. private $stmt;
*/
protected function __construct() public function __construct(\PDOStatement $stmt)
{ {
$this->stmt = $stmt;
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) public function setFetchMode($fetchMode, ...$args)
{ {
$fetchMode = $this->convertFetchMode($fetchMode); $fetchMode = $this->convertFetchMode($fetchMode);
// This thin wrapper is necessary to shield against the weird signature
// of PDOStatement::setFetchMode(): even if the second and third
// parameters are optional, PHP will not let us remove it from this
// declaration.
try { try {
if ($arg2 === null && $arg3 === null) { return $this->stmt->setFetchMode($fetchMode, ...$args);
return parent::setFetchMode($fetchMode);
}
if ($arg3 === null) {
return parent::setFetchMode($fetchMode, $arg2);
}
return parent::setFetchMode($fetchMode, $arg2, $arg3);
} catch (\PDOException $exception) { } catch (\PDOException $exception) {
throw new PDOException($exception); throw new PDOException($exception);
} }
...@@ -78,7 +66,7 @@ class PDOStatement extends \PDOStatement implements Statement ...@@ -78,7 +66,7 @@ class PDOStatement extends \PDOStatement implements Statement
$type = $this->convertParamType($type); $type = $this->convertParamType($type);
try { try {
return parent::bindValue($param, $value, $type); return $this->stmt->bindValue($param, $value, $type);
} catch (\PDOException $exception) { } catch (\PDOException $exception) {
throw new PDOException($exception); throw new PDOException($exception);
} }
...@@ -92,7 +80,7 @@ class PDOStatement extends \PDOStatement implements Statement ...@@ -92,7 +80,7 @@ class PDOStatement extends \PDOStatement implements Statement
$type = $this->convertParamType($type); $type = $this->convertParamType($type);
try { try {
return parent::bindParam($column, $variable, $type, ...array_slice(func_get_args(), 3)); return $this->stmt->bindParam($column, $variable, $type, ...array_slice(func_get_args(), 3));
} catch (\PDOException $exception) { } catch (\PDOException $exception) {
throw new PDOException($exception); throw new PDOException($exception);
} }
...@@ -104,7 +92,7 @@ class PDOStatement extends \PDOStatement implements Statement ...@@ -104,7 +92,7 @@ class PDOStatement extends \PDOStatement implements Statement
public function closeCursor() public function closeCursor()
{ {
try { try {
return parent::closeCursor(); return $this->stmt->closeCursor();
} catch (\PDOException $exception) { } catch (\PDOException $exception) {
// Exceptions not allowed by the interface. // Exceptions not allowed by the interface.
// In case driver implementations do not adhere to the interface, silence exceptions here. // In case driver implementations do not adhere to the interface, silence exceptions here.
...@@ -112,31 +100,52 @@ class PDOStatement extends \PDOStatement implements Statement ...@@ -112,31 +100,52 @@ class PDOStatement extends \PDOStatement implements Statement
} }
} }
public function columnCount()
{
return $this->stmt->columnCount();
}
public function errorCode()
{
return $this->stmt->errorCode();
}
public function errorInfo()
{
return $this->stmt->errorInfo();
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function execute($params = null) public function execute($params = null)
{ {
try { try {
return parent::execute($params); return $this->stmt->execute($params);
} catch (\PDOException $exception) { } catch (\PDOException $exception) {
throw new PDOException($exception); throw new PDOException($exception);
} }
} }
public function rowCount() : int
{
return $this->stmt->rowCount();
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) public function fetch($fetchMode = null, ...$args)
{ {
$args = func_get_args(); try {
if ($fetchMode === null) {
if (isset($args[0])) { return $this->stmt->fetch();
$args[0] = $this->convertFetchMode($args[0]);
} }
try { return $this->stmt->fetch(
return parent::fetch(...$args); $this->convertFetchMode($fetchMode),
...$args
);
} catch (\PDOException $exception) { } catch (\PDOException $exception) {
throw new PDOException($exception); throw new PDOException($exception);
} }
...@@ -145,32 +154,24 @@ class PDOStatement extends \PDOStatement implements Statement ...@@ -145,32 +154,24 @@ class PDOStatement extends \PDOStatement implements Statement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) public function fetchAll($fetchMode = null, ...$args)
{ {
$args = func_get_args(); try {
if ($fetchMode === null) {
if (isset($args[0])) { $data = $this->stmt->fetchAll();
$args[0] = $this->convertFetchMode($args[0]);
}
if ($fetchMode === null && $fetchArgument === null && $ctorArgs === null) {
$args = [];
} elseif ($fetchArgument === null && $ctorArgs === null) {
$args = [$fetchMode];
} elseif ($ctorArgs === null) {
$args = [$fetchMode, $fetchArgument];
} else { } else {
$args = [$fetchMode, $fetchArgument, $ctorArgs]; $data = $this->stmt->fetchAll(
$this->convertFetchMode($fetchMode),
...$args
);
}
} catch (\PDOException $exception) {
throw new PDOException($exception);
} }
try {
$data = parent::fetchAll(...$args);
assert(is_array($data)); assert(is_array($data));
return $data; return $data;
} catch (\PDOException $exception) {
throw new PDOException($exception);
}
} }
/** /**
...@@ -179,7 +180,7 @@ class PDOStatement extends \PDOStatement implements Statement ...@@ -179,7 +180,7 @@ class PDOStatement extends \PDOStatement implements Statement
public function fetchColumn($columnIndex = 0) public function fetchColumn($columnIndex = 0)
{ {
try { try {
return parent::fetchColumn($columnIndex); return $this->stmt->fetchColumn($columnIndex);
} catch (\PDOException $exception) { } catch (\PDOException $exception) {
throw new PDOException($exception); throw new PDOException($exception);
} }
...@@ -193,13 +194,7 @@ class PDOStatement extends \PDOStatement implements Statement ...@@ -193,13 +194,7 @@ class PDOStatement extends \PDOStatement implements Statement
private function convertParamType(int $type) : int private function convertParamType(int $type) : int
{ {
if (! isset(self::PARAM_TYPE_MAP[$type])) { if (! isset(self::PARAM_TYPE_MAP[$type])) {
// TODO: next major: throw an exception throw new InvalidArgumentException('Invalid parameter type: ' . $type);
@trigger_error(sprintf(
'Using a PDO parameter type (%d given) is deprecated and will cause an error in Doctrine DBAL 3.0',
$type
), E_USER_DEPRECATED);
return $type;
} }
return self::PARAM_TYPE_MAP[$type]; return self::PARAM_TYPE_MAP[$type];
...@@ -213,16 +208,17 @@ class PDOStatement extends \PDOStatement implements Statement ...@@ -213,16 +208,17 @@ class PDOStatement extends \PDOStatement implements Statement
private function convertFetchMode(int $fetchMode) : int private function convertFetchMode(int $fetchMode) : int
{ {
if (! isset(self::FETCH_MODE_MAP[$fetchMode])) { if (! isset(self::FETCH_MODE_MAP[$fetchMode])) {
// TODO: next major: throw an exception throw new InvalidArgumentException('Invalid fetch mode: ' . $fetchMode);
@trigger_error(sprintf(
'Using a PDO fetch mode or their combination (%d given)' .
' is deprecated and will cause an error in Doctrine DBAL 3.0',
$fetchMode
), E_USER_DEPRECATED);
return $fetchMode;
} }
return self::FETCH_MODE_MAP[$fetchMode]; return self::FETCH_MODE_MAP[$fetchMode];
} }
/**
* {@inheritdoc}
*/
public function getIterator()
{
yield from $this->stmt;
}
} }
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
namespace Doctrine\DBAL\Driver; namespace Doctrine\DBAL\Driver;
use PDO;
use Traversable; use Traversable;
/** /**
...@@ -29,13 +28,13 @@ interface ResultStatement extends Traversable ...@@ -29,13 +28,13 @@ interface ResultStatement extends Traversable
/** /**
* Sets the fetch mode to use while iterating this statement. * Sets the fetch mode to use while iterating this statement.
* *
* @param int $fetchMode The fetch mode must be one of the {@link \Doctrine\DBAL\FetchMode} constants. * @param int $fetchMode Controls how the next row will be returned to the caller.
* @param mixed $arg2 * The value must be one of the {@link \Doctrine\DBAL\FetchMode} constants.
* @param mixed $arg3 * @param mixed ...$args Optional mode-specific arguments (see {@link self::fetchAll()}).
* *
* @return bool * @return bool
*/ */
public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null); public function setFetchMode($fetchMode, ...$args);
/** /**
* Returns the next row of a result set. * Returns the next row of a result set.
...@@ -43,26 +42,12 @@ interface ResultStatement extends Traversable ...@@ -43,26 +42,12 @@ interface ResultStatement extends Traversable
* @param int|null $fetchMode Controls how the next row will be returned to the caller. * @param int|null $fetchMode Controls how the next row will be returned to the caller.
* The value must be one of the {@link \Doctrine\DBAL\FetchMode} constants, * The value must be one of the {@link \Doctrine\DBAL\FetchMode} constants,
* defaulting to {@link \Doctrine\DBAL\FetchMode::MIXED}. * defaulting to {@link \Doctrine\DBAL\FetchMode::MIXED}.
* @param int $cursorOrientation For a ResultStatement object representing a scrollable cursor, * @param mixed ...$args Optional mode-specific arguments (see {@link self::fetchAll()}).
* this value determines which row will be returned to the caller.
* This value must be one of the \PDO::FETCH_ORI_* constants,
* defaulting to \PDO::FETCH_ORI_NEXT. To request a scrollable
* cursor for your ResultStatement object, you must set the \PDO::ATTR_CURSOR
* attribute to \PDO::CURSOR_SCROLL when you prepare the SQL statement with
* \PDO::prepare().
* @param int $cursorOffset For a ResultStatement object representing a scrollable cursor for which the
* cursorOrientation parameter is set to \PDO::FETCH_ORI_ABS, this value
* specifies the absolute number of the row in the result set that shall be
* fetched.
* For a ResultStatement object representing a scrollable cursor for which the
* cursorOrientation parameter is set to \PDO::FETCH_ORI_REL, this value
* specifies the row to fetch relative to the cursor position before
* ResultStatement::fetch() was called.
* *
* @return mixed The return value of this method on success depends on the fetch mode. In all cases, FALSE is * @return mixed The return value of this method on success depends on the fetch mode. In all cases, FALSE is
* returned on failure. * returned on failure.
*/ */
public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0); public function fetch($fetchMode = null, ...$args);
/** /**
* Returns an array containing all of the result set rows. * Returns an array containing all of the result set rows.
...@@ -70,21 +55,16 @@ interface ResultStatement extends Traversable ...@@ -70,21 +55,16 @@ interface ResultStatement extends Traversable
* @param int|null $fetchMode Controls how the next row will be returned to the caller. * @param int|null $fetchMode Controls how the next row will be returned to the caller.
* The value must be one of the {@link \Doctrine\DBAL\FetchMode} constants, * The value must be one of the {@link \Doctrine\DBAL\FetchMode} constants,
* defaulting to {@link \Doctrine\DBAL\FetchMode::MIXED}. * defaulting to {@link \Doctrine\DBAL\FetchMode::MIXED}.
* @param int|null $fetchArgument This argument has a different meaning depending on the value of the $fetchMode parameter: * @param mixed ...$args Optional mode-specific arguments. Supported modes:
* * {@link \Doctrine\DBAL\FetchMode::COLUMN}: * * {@link \Doctrine\DBAL\FetchMode::COLUMN}
* Returns the indicated 0-indexed column. * 1. The 0-indexed column to be returned.
* * {@link \Doctrine\DBAL\FetchMode::CUSTOM_OBJECT}: * * {@link \Doctrine\DBAL\FetchMode::CUSTOM_OBJECT}
* Returns instances of the specified class, mapping the columns of each row * 1. The class name of the object to be created,
* to named properties in the class. * 2. Array of constructor arguments
* * \PDO::FETCH_FUNC: Returns the results of calling the specified function, using each row's
* columns as parameters in the call.
* @param mixed[]|null $ctorArgs Controls how the next row will be returned to the caller.
* The value must be one of the {@link \Doctrine\DBAL\FetchMode} constants,
* defaulting to {@link \Doctrine\DBAL\FetchMode::MIXED}.
* *
* @return mixed[] * @return mixed[]
*/ */
public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null); public function fetchAll($fetchMode = null, ...$args);
/** /**
* Returns a single column from the next row of a result set or FALSE if there are no more rows. * Returns a single column from the next row of a result set or FALSE if there are no more rows.
......
...@@ -3,10 +3,11 @@ ...@@ -3,10 +3,11 @@
namespace Doctrine\DBAL\Driver\SQLAnywhere; namespace Doctrine\DBAL\Driver\SQLAnywhere;
use Doctrine\DBAL\Driver\Connection; use Doctrine\DBAL\Driver\Connection;
use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\DBAL\Driver\ServerInfoAwareConnection; use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
use Doctrine\DBAL\Driver\Statement as DriverStatement;
use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\ParameterType;
use function assert; use function assert;
use function func_get_args;
use function is_float; use function is_float;
use function is_int; use function is_int;
use function is_resource; use function is_resource;
...@@ -107,7 +108,7 @@ class SQLAnywhereConnection implements Connection, ServerInfoAwareConnection ...@@ -107,7 +108,7 @@ class SQLAnywhereConnection implements Connection, ServerInfoAwareConnection
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function exec($statement) public function exec(string $statement) : int
{ {
if (sasql_real_query($this->connection, $statement) === false) { if (sasql_real_query($this->connection, $statement) === false) {
throw SQLAnywhereException::fromSQLAnywhereError($this->connection); throw SQLAnywhereException::fromSQLAnywhereError($this->connection);
...@@ -143,19 +144,17 @@ class SQLAnywhereConnection implements Connection, ServerInfoAwareConnection ...@@ -143,19 +144,17 @@ class SQLAnywhereConnection implements Connection, ServerInfoAwareConnection
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function prepare($prepareString) public function prepare(string $sql) : DriverStatement
{ {
return new SQLAnywhereStatement($this->connection, $prepareString); return new SQLAnywhereStatement($this->connection, $sql);
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function query() public function query(string $sql) : ResultStatement
{ {
$args = func_get_args(); $stmt = $this->prepare($sql);
$stmt = $this->prepare($args[0]);
$stmt->execute(); $stmt->execute();
return $stmt; return $stmt;
......
...@@ -7,14 +7,12 @@ use Doctrine\DBAL\Driver\StatementIterator; ...@@ -7,14 +7,12 @@ use Doctrine\DBAL\Driver\StatementIterator;
use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\FetchMode;
use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\ParameterType;
use IteratorAggregate; use IteratorAggregate;
use PDO;
use ReflectionClass; use ReflectionClass;
use ReflectionObject; use ReflectionObject;
use stdClass; use stdClass;
use const SASQL_BOTH; use const SASQL_BOTH;
use function array_key_exists; use function array_key_exists;
use function func_get_args; use function count;
use function func_num_args;
use function gettype; use function gettype;
use function is_array; use function is_array;
use function is_int; use function is_int;
...@@ -199,7 +197,7 @@ class SQLAnywhereStatement implements IteratorAggregate, Statement ...@@ -199,7 +197,7 @@ class SQLAnywhereStatement implements IteratorAggregate, Statement
* *
* @throws SQLAnywhereException * @throws SQLAnywhereException
*/ */
public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) public function fetch($fetchMode = null, ...$args)
{ {
if (! is_resource($this->result)) { if (! is_resource($this->result)) {
return false; return false;
...@@ -221,10 +219,9 @@ class SQLAnywhereStatement implements IteratorAggregate, Statement ...@@ -221,10 +219,9 @@ class SQLAnywhereStatement implements IteratorAggregate, Statement
$className = $this->defaultFetchClass; $className = $this->defaultFetchClass;
$ctorArgs = $this->defaultFetchClassCtorArgs; $ctorArgs = $this->defaultFetchClassCtorArgs;
if (func_num_args() >= 2) { if (count($args) > 0) {
$args = func_get_args(); $className = $args[0];
$className = $args[1]; $ctorArgs = $args[1] ?? [];
$ctorArgs = $args[2] ?? [];
} }
$result = sasql_fetch_object($this->result); $result = sasql_fetch_object($this->result);
...@@ -249,13 +246,13 @@ class SQLAnywhereStatement implements IteratorAggregate, Statement ...@@ -249,13 +246,13 @@ class SQLAnywhereStatement implements IteratorAggregate, Statement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) public function fetchAll($fetchMode = null, ...$args)
{ {
$rows = []; $rows = [];
switch ($fetchMode) { switch ($fetchMode) {
case FetchMode::CUSTOM_OBJECT: case FetchMode::CUSTOM_OBJECT:
while (($row = $this->fetch(...func_get_args())) !== false) { while (($row = $this->fetch($fetchMode, ...$args)) !== false) {
$rows[] = $row; $rows[] = $row;
} }
break; break;
...@@ -300,7 +297,7 @@ class SQLAnywhereStatement implements IteratorAggregate, Statement ...@@ -300,7 +297,7 @@ class SQLAnywhereStatement implements IteratorAggregate, Statement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function rowCount() public function rowCount() : int
{ {
return sasql_stmt_affected_rows($this->stmt); return sasql_stmt_affected_rows($this->stmt);
} }
...@@ -308,11 +305,19 @@ class SQLAnywhereStatement implements IteratorAggregate, Statement ...@@ -308,11 +305,19 @@ class SQLAnywhereStatement implements IteratorAggregate, Statement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) public function setFetchMode($fetchMode, ...$args)
{ {
$this->defaultFetchMode = $fetchMode; $this->defaultFetchMode = $fetchMode;
$this->defaultFetchClass = $arg2 ?: $this->defaultFetchClass;
$this->defaultFetchClassCtorArgs = $arg3 ? (array) $arg3 : $this->defaultFetchClassCtorArgs; if (isset($args[0])) {
$this->defaultFetchClass = $args[0];
}
if (isset($args[1])) {
$this->defaultFetchClassCtorArgs = (array) $args[1];
}
return true;
} }
/** /**
......
...@@ -3,10 +3,11 @@ ...@@ -3,10 +3,11 @@
namespace Doctrine\DBAL\Driver\SQLSrv; namespace Doctrine\DBAL\Driver\SQLSrv;
use Doctrine\DBAL\Driver\Connection; use Doctrine\DBAL\Driver\Connection;
use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\DBAL\Driver\ServerInfoAwareConnection; use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
use Doctrine\DBAL\Driver\Statement as DriverStatement;
use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\ParameterType;
use const SQLSRV_ERR_ERRORS; use const SQLSRV_ERR_ERRORS;
use function func_get_args;
use function is_float; use function is_float;
use function is_int; use function is_int;
use function sprintf; use function sprintf;
...@@ -75,7 +76,7 @@ class SQLSrvConnection implements Connection, ServerInfoAwareConnection ...@@ -75,7 +76,7 @@ class SQLSrvConnection implements Connection, ServerInfoAwareConnection
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public function prepare($sql) public function prepare(string $sql) : DriverStatement
{ {
return new SQLSrvStatement($this->conn, $sql, $this->lastInsertId); return new SQLSrvStatement($this->conn, $sql, $this->lastInsertId);
} }
...@@ -83,10 +84,8 @@ class SQLSrvConnection implements Connection, ServerInfoAwareConnection ...@@ -83,10 +84,8 @@ class SQLSrvConnection implements Connection, ServerInfoAwareConnection
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public function query() public function query(string $sql) : ResultStatement
{ {
$args = func_get_args();
$sql = $args[0];
$stmt = $this->prepare($sql); $stmt = $this->prepare($sql);
$stmt->execute(); $stmt->execute();
...@@ -112,7 +111,7 @@ class SQLSrvConnection implements Connection, ServerInfoAwareConnection ...@@ -112,7 +111,7 @@ class SQLSrvConnection implements Connection, ServerInfoAwareConnection
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public function exec($statement) public function exec(string $statement) : int
{ {
$stmt = sqlsrv_query($this->conn, $statement); $stmt = sqlsrv_query($this->conn, $statement);
......
...@@ -7,7 +7,6 @@ use Doctrine\DBAL\Driver\StatementIterator; ...@@ -7,7 +7,6 @@ use Doctrine\DBAL\Driver\StatementIterator;
use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\FetchMode;
use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\ParameterType;
use IteratorAggregate; use IteratorAggregate;
use PDO;
use const SQLSRV_ENC_BINARY; use const SQLSRV_ENC_BINARY;
use const SQLSRV_ERR_ERRORS; use const SQLSRV_ERR_ERRORS;
use const SQLSRV_FETCH_ASSOC; use const SQLSRV_FETCH_ASSOC;
...@@ -16,7 +15,6 @@ use const SQLSRV_FETCH_NUMERIC; ...@@ -16,7 +15,6 @@ use const SQLSRV_FETCH_NUMERIC;
use const SQLSRV_PARAM_IN; use const SQLSRV_PARAM_IN;
use function array_key_exists; use function array_key_exists;
use function count; use function count;
use function func_get_args;
use function in_array; use function in_array;
use function is_int; use function is_int;
use function is_numeric; use function is_numeric;
...@@ -313,11 +311,17 @@ class SQLSrvStatement implements IteratorAggregate, Statement ...@@ -313,11 +311,17 @@ class SQLSrvStatement implements IteratorAggregate, Statement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) public function setFetchMode($fetchMode, ...$args)
{ {
$this->defaultFetchMode = $fetchMode; $this->defaultFetchMode = $fetchMode;
$this->defaultFetchClass = $arg2 ?: $this->defaultFetchClass;
$this->defaultFetchClassCtorArgs = $arg3 ? (array) $arg3 : $this->defaultFetchClassCtorArgs; if (isset($args[0])) {
$this->defaultFetchClass = $args[0];
}
if (isset($args[1])) {
$this->defaultFetchClassCtorArgs = (array) $args[1];
}
return true; return true;
} }
...@@ -335,7 +339,7 @@ class SQLSrvStatement implements IteratorAggregate, Statement ...@@ -335,7 +339,7 @@ class SQLSrvStatement implements IteratorAggregate, Statement
* *
* @throws SQLSrvException * @throws SQLSrvException
*/ */
public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) public function fetch($fetchMode = null, ...$args)
{ {
// do not try fetching from the statement if it's not expected to contain result // do not try fetching from the statement if it's not expected to contain result
// in order to prevent exceptional situation // in order to prevent exceptional situation
...@@ -343,7 +347,6 @@ class SQLSrvStatement implements IteratorAggregate, Statement ...@@ -343,7 +347,6 @@ class SQLSrvStatement implements IteratorAggregate, Statement
return false; return false;
} }
$args = func_get_args();
$fetchMode = $fetchMode ?: $this->defaultFetchMode; $fetchMode = $fetchMode ?: $this->defaultFetchMode;
if ($fetchMode === FetchMode::COLUMN) { if ($fetchMode === FetchMode::COLUMN) {
...@@ -358,9 +361,9 @@ class SQLSrvStatement implements IteratorAggregate, Statement ...@@ -358,9 +361,9 @@ class SQLSrvStatement implements IteratorAggregate, Statement
$className = $this->defaultFetchClass; $className = $this->defaultFetchClass;
$ctorArgs = $this->defaultFetchClassCtorArgs; $ctorArgs = $this->defaultFetchClassCtorArgs;
if (count($args) >= 2) { if (count($args) > 0) {
$className = $args[1]; $className = $args[0];
$ctorArgs = $args[2] ?? []; $ctorArgs = $args[1] ?? [];
} }
return sqlsrv_fetch_object($this->stmt, $className, $ctorArgs) ?: false; return sqlsrv_fetch_object($this->stmt, $className, $ctorArgs) ?: false;
...@@ -372,13 +375,13 @@ class SQLSrvStatement implements IteratorAggregate, Statement ...@@ -372,13 +375,13 @@ class SQLSrvStatement implements IteratorAggregate, Statement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) public function fetchAll($fetchMode = null, ...$args)
{ {
$rows = []; $rows = [];
switch ($fetchMode) { switch ($fetchMode) {
case FetchMode::CUSTOM_OBJECT: case FetchMode::CUSTOM_OBJECT:
while (($row = $this->fetch(...func_get_args())) !== false) { while (($row = $this->fetch($fetchMode, ...$args)) !== false) {
$rows[] = $row; $rows[] = $row;
} }
break; break;
...@@ -415,7 +418,7 @@ class SQLSrvStatement implements IteratorAggregate, Statement ...@@ -415,7 +418,7 @@ class SQLSrvStatement implements IteratorAggregate, Statement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function rowCount() public function rowCount() : int
{ {
if ($this->stmt === null) { if ($this->stmt === null) {
return 0; return 0;
......
...@@ -49,8 +49,7 @@ interface Statement extends ResultStatement ...@@ -49,8 +49,7 @@ interface Statement extends ResultStatement
* question mark placeholders, this will be the 1-indexed position of the parameter. * question mark placeholders, this will be the 1-indexed position of the parameter.
* @param mixed $variable Name of the PHP variable to bind to the SQL statement parameter. * @param mixed $variable Name of the PHP variable to bind to the SQL statement parameter.
* @param int $type Explicit data type for the parameter using the {@link \Doctrine\DBAL\ParameterType} * @param int $type Explicit data type for the parameter using the {@link \Doctrine\DBAL\ParameterType}
* constants. To return an INOUT parameter from a stored procedure, use the bitwise * constants.
* OR operator to set the PDO::PARAM_INPUT_OUTPUT bits for the data_type parameter.
* @param int|null $length You must specify maxlength when using an OUT bind * @param int|null $length You must specify maxlength when using an OUT bind
* so that PHP allocates enough memory to hold the returned value. * so that PHP allocates enough memory to hold the returned value.
* *
...@@ -101,5 +100,5 @@ interface Statement extends ResultStatement ...@@ -101,5 +100,5 @@ interface Statement extends ResultStatement
* *
* @return int The number of rows. * @return int The number of rows.
*/ */
public function rowCount(); public function rowCount() : int;
} }
...@@ -14,7 +14,6 @@ use Doctrine\DBAL\Driver\PDOSqlite\Driver as PDOSQLiteDriver; ...@@ -14,7 +14,6 @@ use Doctrine\DBAL\Driver\PDOSqlite\Driver as PDOSQLiteDriver;
use Doctrine\DBAL\Driver\PDOSqlsrv\Driver as PDOSQLSrvDriver; use Doctrine\DBAL\Driver\PDOSqlsrv\Driver as PDOSQLSrvDriver;
use Doctrine\DBAL\Driver\SQLAnywhere\Driver as SQLAnywhereDriver; use Doctrine\DBAL\Driver\SQLAnywhere\Driver as SQLAnywhereDriver;
use Doctrine\DBAL\Driver\SQLSrv\Driver as SQLSrvDriver; use Doctrine\DBAL\Driver\SQLSrv\Driver as SQLSrvDriver;
use PDO;
use function array_keys; use function array_keys;
use function array_map; use function array_map;
use function array_merge; use function array_merge;
...@@ -171,17 +170,7 @@ final class DriverManager ...@@ -171,17 +170,7 @@ final class DriverManager
} }
} }
// check for existing pdo object
if (isset($params['pdo']) && ! $params['pdo'] instanceof PDO) {
throw DBALException::invalidPdoInstance();
}
if (isset($params['pdo'])) {
$params['pdo']->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$params['driver'] = 'pdo_' . $params['pdo']->getAttribute(PDO::ATTR_DRIVER_NAME);
} else {
self::_checkParams($params); self::_checkParams($params);
}
$className = $params['driverClass'] ?? self::$_driverMap[$params['driver']]; $className = $params['driverClass'] ?? self::$_driverMap[$params['driver']];
...@@ -277,10 +266,6 @@ final class DriverManager ...@@ -277,10 +266,6 @@ final class DriverManager
$url = array_map('rawurldecode', $url); $url = array_map('rawurldecode', $url);
// If we have a connection URL, we have to unset the default PDO instance connection parameter (if any)
// as we cannot merge connection details from the URL into the PDO instance (URL takes precedence).
unset($params['pdo']);
$params = self::parseDatabaseUrlScheme($url, $params); $params = self::parseDatabaseUrlScheme($url, $params);
if (isset($url['host'])) { if (isset($url['host'])) {
......
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
namespace Doctrine\DBAL; namespace Doctrine\DBAL;
use PDO;
/** /**
* Contains statement fetch modes. * Contains statement fetch modes.
*/ */
...@@ -17,7 +15,7 @@ final class FetchMode ...@@ -17,7 +15,7 @@ final class FetchMode
* *
* @see \PDO::FETCH_ASSOC * @see \PDO::FETCH_ASSOC
*/ */
public const ASSOCIATIVE = PDO::FETCH_ASSOC; public const ASSOCIATIVE = 2;
/** /**
* Specifies that the fetch method shall return each row as an array indexed * Specifies that the fetch method shall return each row as an array indexed
...@@ -26,7 +24,7 @@ final class FetchMode ...@@ -26,7 +24,7 @@ final class FetchMode
* *
* @see \PDO::FETCH_NUM * @see \PDO::FETCH_NUM
*/ */
public const NUMERIC = PDO::FETCH_NUM; public const NUMERIC = 3;
/** /**
* Specifies that the fetch method shall return each row as an array indexed * Specifies that the fetch method shall return each row as an array indexed
...@@ -35,7 +33,7 @@ final class FetchMode ...@@ -35,7 +33,7 @@ final class FetchMode
* *
* @see \PDO::FETCH_BOTH * @see \PDO::FETCH_BOTH
*/ */
public const MIXED = PDO::FETCH_BOTH; public const MIXED = 4;
/** /**
* Specifies that the fetch method shall return each row as an object with * Specifies that the fetch method shall return each row as an object with
...@@ -44,7 +42,7 @@ final class FetchMode ...@@ -44,7 +42,7 @@ final class FetchMode
* *
* @see \PDO::FETCH_OBJ * @see \PDO::FETCH_OBJ
*/ */
public const STANDARD_OBJECT = PDO::FETCH_OBJ; public const STANDARD_OBJECT = 5;
/** /**
* Specifies that the fetch method shall return only a single requested * Specifies that the fetch method shall return only a single requested
...@@ -52,7 +50,7 @@ final class FetchMode ...@@ -52,7 +50,7 @@ final class FetchMode
* *
* @see \PDO::FETCH_COLUMN * @see \PDO::FETCH_COLUMN
*/ */
public const COLUMN = PDO::FETCH_COLUMN; public const COLUMN = 7;
/** /**
* Specifies that the fetch method shall return a new instance of the * Specifies that the fetch method shall return a new instance of the
...@@ -60,7 +58,7 @@ final class FetchMode ...@@ -60,7 +58,7 @@ final class FetchMode
* *
* @see \PDO::FETCH_CLASS * @see \PDO::FETCH_CLASS
*/ */
public const CUSTOM_OBJECT = PDO::FETCH_CLASS; public const CUSTOM_OBJECT = 8;
/** /**
* This class cannot be instantiated. * This class cannot be instantiated.
......
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
namespace Doctrine\DBAL; namespace Doctrine\DBAL;
use PDO;
/** /**
* Contains statement parameter types. * Contains statement parameter types.
*/ */
...@@ -14,35 +12,35 @@ final class ParameterType ...@@ -14,35 +12,35 @@ final class ParameterType
* *
* @see \PDO::PARAM_NULL * @see \PDO::PARAM_NULL
*/ */
public const NULL = PDO::PARAM_NULL; public const NULL = 0;
/** /**
* Represents the SQL INTEGER data type. * Represents the SQL INTEGER data type.
* *
* @see \PDO::PARAM_INT * @see \PDO::PARAM_INT
*/ */
public const INTEGER = PDO::PARAM_INT; public const INTEGER = 1;
/** /**
* Represents the SQL CHAR, VARCHAR, or other string data type. * Represents the SQL CHAR, VARCHAR, or other string data type.
* *
* @see \PDO::PARAM_STR * @see \PDO::PARAM_STR
*/ */
public const STRING = PDO::PARAM_STR; public const STRING = 2;
/** /**
* Represents the SQL large object data type. * Represents the SQL large object data type.
* *
* @see \PDO::PARAM_LOB * @see \PDO::PARAM_LOB
*/ */
public const LARGE_OBJECT = PDO::PARAM_LOB; public const LARGE_OBJECT = 3;
/** /**
* Represents a boolean data type. * Represents a boolean data type.
* *
* @see \PDO::PARAM_BOOL * @see \PDO::PARAM_BOOL
*/ */
public const BOOLEAN = PDO::PARAM_BOOL; public const BOOLEAN = 5;
/** /**
* Represents a binary string data type. * Represents a binary string data type.
......
...@@ -5,10 +5,11 @@ namespace Doctrine\DBAL\Portability; ...@@ -5,10 +5,11 @@ namespace Doctrine\DBAL\Portability;
use Doctrine\DBAL\Cache\QueryCacheProfile; use Doctrine\DBAL\Cache\QueryCacheProfile;
use Doctrine\DBAL\ColumnCase; use Doctrine\DBAL\ColumnCase;
use Doctrine\DBAL\Driver\PDOConnection; use Doctrine\DBAL\Driver\PDOConnection;
use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\DBAL\Driver\Statement as DriverStatement;
use PDO; use PDO;
use const CASE_LOWER; use const CASE_LOWER;
use const CASE_UPPER; use const CASE_UPPER;
use function func_get_args;
/** /**
* Portability wrapper for a Connection. * Portability wrapper for a Connection.
...@@ -68,7 +69,7 @@ class Connection extends \Doctrine\DBAL\Connection ...@@ -68,7 +69,7 @@ class Connection extends \Doctrine\DBAL\Connection
if (isset($params['fetch_case']) && $this->portability & self::PORTABILITY_FIX_CASE) { if (isset($params['fetch_case']) && $this->portability & self::PORTABILITY_FIX_CASE) {
if ($this->_conn instanceof PDOConnection) { if ($this->_conn instanceof PDOConnection) {
// make use of c-level support for case handling // make use of c-level support for case handling
$this->_conn->setAttribute(PDO::ATTR_CASE, $params['fetch_case']); $this->_conn->getWrappedConnection()->setAttribute(PDO::ATTR_CASE, $params['fetch_case']);
} else { } else {
$this->case = $params['fetch_case'] === ColumnCase::LOWER ? CASE_LOWER : CASE_UPPER; $this->case = $params['fetch_case'] === ColumnCase::LOWER ? CASE_LOWER : CASE_UPPER;
} }
...@@ -97,7 +98,7 @@ class Connection extends \Doctrine\DBAL\Connection ...@@ -97,7 +98,7 @@ class Connection extends \Doctrine\DBAL\Connection
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function executeQuery($query, array $params = [], $types = [], ?QueryCacheProfile $qcp = null) public function executeQuery(string $query, array $params = [], $types = [], ?QueryCacheProfile $qcp = null) : ResultStatement
{ {
$stmt = new Statement(parent::executeQuery($query, $params, $types, $qcp), $this); $stmt = new Statement(parent::executeQuery($query, $params, $types, $qcp), $this);
$stmt->setFetchMode($this->defaultFetchMode); $stmt->setFetchMode($this->defaultFetchMode);
...@@ -108,9 +109,9 @@ class Connection extends \Doctrine\DBAL\Connection ...@@ -108,9 +109,9 @@ class Connection extends \Doctrine\DBAL\Connection
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function prepare($statement) public function prepare(string $sql) : DriverStatement
{ {
$stmt = new Statement(parent::prepare($statement), $this); $stmt = new Statement(parent::prepare($sql), $this);
$stmt->setFetchMode($this->defaultFetchMode); $stmt->setFetchMode($this->defaultFetchMode);
return $stmt; return $stmt;
...@@ -119,11 +120,11 @@ class Connection extends \Doctrine\DBAL\Connection ...@@ -119,11 +120,11 @@ class Connection extends \Doctrine\DBAL\Connection
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function query() public function query(string $sql) : ResultStatement
{ {
$connection = $this->getWrappedConnection(); $connection = $this->getWrappedConnection();
$stmt = $connection->query(...func_get_args()); $stmt = $connection->query($sql);
$stmt = new Statement($stmt, $this); $stmt = new Statement($stmt, $this);
$stmt->setFetchMode($this->defaultFetchMode); $stmt->setFetchMode($this->defaultFetchMode);
......
...@@ -8,7 +8,6 @@ use Doctrine\DBAL\Driver\StatementIterator; ...@@ -8,7 +8,6 @@ use Doctrine\DBAL\Driver\StatementIterator;
use Doctrine\DBAL\FetchMode; use Doctrine\DBAL\FetchMode;
use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\ParameterType;
use IteratorAggregate; use IteratorAggregate;
use PDO;
use function array_change_key_case; use function array_change_key_case;
use function assert; use function assert;
use function is_string; use function is_string;
...@@ -112,11 +111,11 @@ class Statement implements IteratorAggregate, DriverStatement ...@@ -112,11 +111,11 @@ class Statement implements IteratorAggregate, DriverStatement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function setFetchMode($fetchMode, $arg1 = null, $arg2 = null) public function setFetchMode($fetchMode, ...$args)
{ {
$this->defaultFetchMode = $fetchMode; $this->defaultFetchMode = $fetchMode;
return $this->stmt->setFetchMode($fetchMode, $arg1, $arg2); return $this->stmt->setFetchMode($fetchMode, ...$args);
} }
/** /**
...@@ -130,11 +129,11 @@ class Statement implements IteratorAggregate, DriverStatement ...@@ -130,11 +129,11 @@ class Statement implements IteratorAggregate, DriverStatement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) public function fetch($fetchMode = null, ...$args)
{ {
$fetchMode = $fetchMode ?: $this->defaultFetchMode; $fetchMode = $fetchMode ?: $this->defaultFetchMode;
$row = $this->stmt->fetch($fetchMode); $row = $this->stmt->fetch($fetchMode, ...$args);
$iterateRow = $this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL|Connection::PORTABILITY_RTRIM); $iterateRow = $this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL|Connection::PORTABILITY_RTRIM);
$fixCase = $this->case !== null $fixCase = $this->case !== null
...@@ -149,15 +148,11 @@ class Statement implements IteratorAggregate, DriverStatement ...@@ -149,15 +148,11 @@ class Statement implements IteratorAggregate, DriverStatement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) public function fetchAll($fetchMode = null, ...$args)
{ {
$fetchMode = $fetchMode ?: $this->defaultFetchMode; $fetchMode = $fetchMode ?: $this->defaultFetchMode;
if ($fetchArgument) { $rows = $this->stmt->fetchAll($fetchMode, ...$args);
$rows = $this->stmt->fetchAll($fetchMode, $fetchArgument);
} else {
$rows = $this->stmt->fetchAll($fetchMode);
}
$iterateRow = $this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL|Connection::PORTABILITY_RTRIM); $iterateRow = $this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL|Connection::PORTABILITY_RTRIM);
$fixCase = $this->case !== null $fixCase = $this->case !== null
...@@ -238,7 +233,7 @@ class Statement implements IteratorAggregate, DriverStatement ...@@ -238,7 +233,7 @@ class Statement implements IteratorAggregate, DriverStatement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function rowCount() public function rowCount() : int
{ {
assert($this->stmt instanceof DriverStatement); assert($this->stmt instanceof DriverStatement);
......
...@@ -6,7 +6,6 @@ use Doctrine\DBAL\Driver\Statement as DriverStatement; ...@@ -6,7 +6,6 @@ use Doctrine\DBAL\Driver\Statement as DriverStatement;
use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Type;
use IteratorAggregate; use IteratorAggregate;
use PDO;
use Throwable; use Throwable;
use function is_array; use function is_array;
use function is_string; use function is_string;
...@@ -213,17 +212,9 @@ class Statement implements IteratorAggregate, DriverStatement ...@@ -213,17 +212,9 @@ class Statement implements IteratorAggregate, DriverStatement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null) public function setFetchMode($fetchMode, ...$args)
{ {
if ($arg2 === null) { return $this->stmt->setFetchMode($fetchMode, ...$args);
return $this->stmt->setFetchMode($fetchMode);
}
if ($arg3 === null) {
return $this->stmt->setFetchMode($fetchMode, $arg2);
}
return $this->stmt->setFetchMode($fetchMode, $arg2, $arg3);
} }
/** /**
...@@ -239,21 +230,17 @@ class Statement implements IteratorAggregate, DriverStatement ...@@ -239,21 +230,17 @@ class Statement implements IteratorAggregate, DriverStatement
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0) public function fetch($fetchMode = null, ...$args)
{ {
return $this->stmt->fetch($fetchMode); return $this->stmt->fetch($fetchMode, ...$args);
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null) public function fetchAll($fetchMode = null, ...$args)
{ {
if ($fetchArgument) { return $this->stmt->fetchAll($fetchMode, ...$args);
return $this->stmt->fetchAll($fetchMode, $fetchArgument);
}
return $this->stmt->fetchAll($fetchMode);
} }
/** /**
...@@ -269,7 +256,7 @@ class Statement implements IteratorAggregate, DriverStatement ...@@ -269,7 +256,7 @@ class Statement implements IteratorAggregate, DriverStatement
* *
* @return int The number of affected rows. * @return int The number of affected rows.
*/ */
public function rowCount() public function rowCount() : int
{ {
return $this->stmt->rowCount(); return $this->stmt->rowCount();
} }
......
<?php
namespace Doctrine\DBAL\Tools\Console\Command;
use Doctrine\DBAL\Driver\PDOConnection;
use Doctrine\DBAL\Driver\PDOStatement;
use InvalidArgumentException;
use PDOException;
use RuntimeException;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use const PHP_EOL;
use function assert;
use function error_get_last;
use function file_exists;
use function file_get_contents;
use function is_readable;
use function realpath;
use function sprintf;
/**
* Task for executing arbitrary SQL that can come from a file or directly from
* the command line.
*
* @deprecated Use a database client application instead
*/
class ImportCommand extends Command
{
/**
* {@inheritdoc}
*/
protected function configure()
{
$this
->setName('dbal:import')
->setDescription('Import SQL file(s) directly to Database.')
->setDefinition([new InputArgument(
'file',
InputArgument::REQUIRED | InputArgument::IS_ARRAY,
'File path(s) of SQL to be executed.'
),
])
->setHelp(<<<EOT
Import SQL file(s) directly to Database.
EOT
);
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$conn = $this->getHelper('db')->getConnection();
$fileNames = $input->getArgument('file');
if ($fileNames === null) {
return 0;
}
foreach ((array) $fileNames as $fileName) {
$filePath = realpath($fileName);
// Phar compatibility.
if ($filePath === false) {
$filePath = $fileName;
}
if (! file_exists($filePath)) {
throw new InvalidArgumentException(
sprintf("SQL file '<info>%s</info>' does not exist.", $filePath)
);
}
if (! is_readable($filePath)) {
throw new InvalidArgumentException(
sprintf("SQL file '<info>%s</info>' does not have read permissions.", $filePath)
);
}
$output->write(sprintf("Processing file '<info>%s</info>'... ", $filePath));
$sql = @file_get_contents($filePath);
if ($sql === false) {
throw new RuntimeException(
sprintf("Unable to read SQL file '<info>%s</info>': %s", $filePath, error_get_last()['message'])
);
}
if ($conn instanceof PDOConnection) {
// PDO Drivers
try {
$lines = 0;
$stmt = $conn->prepare($sql);
assert($stmt instanceof PDOStatement);
$stmt->execute();
do {
// Required due to "MySQL has gone away!" issue
$stmt->fetch();
$stmt->closeCursor();
$lines++;
} while ($stmt->nextRowset());
$output->write(sprintf('%d statements executed!', $lines) . PHP_EOL);
} catch (PDOException $e) {
$output->write('error!' . PHP_EOL);
throw new RuntimeException($e->getMessage(), $e->getCode(), $e);
}
} else {
// Non-PDO Drivers (ie. OCI8 driver)
$stmt = $conn->prepare($sql);
$rs = $stmt->execute();
if (! $rs) {
$error = $stmt->errorInfo();
$output->write('error!' . PHP_EOL);
throw new RuntimeException($error[2], $error[0]);
}
$output->writeln('OK!' . PHP_EOL);
$stmt->closeCursor();
}
}
return 0;
}
}
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
namespace Doctrine\DBAL\Tools\Console; namespace Doctrine\DBAL\Tools\Console;
use Doctrine\DBAL\Connection; use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Tools\Console\Command\ImportCommand;
use Doctrine\DBAL\Tools\Console\Command\ReservedWordsCommand; use Doctrine\DBAL\Tools\Console\Command\ReservedWordsCommand;
use Doctrine\DBAL\Tools\Console\Command\RunSqlCommand; use Doctrine\DBAL\Tools\Console\Command\RunSqlCommand;
use Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper; use Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper;
...@@ -56,7 +55,6 @@ class ConsoleRunner ...@@ -56,7 +55,6 @@ class ConsoleRunner
{ {
$cli->addCommands([ $cli->addCommands([
new RunSqlCommand(), new RunSqlCommand(),
new ImportCommand(),
new ReservedWordsCommand(), new ReservedWordsCommand(),
]); ]);
} }
......
...@@ -29,7 +29,7 @@ parameters: ...@@ -29,7 +29,7 @@ parameters:
- '~^Method Doctrine\\DBAL\\Driver\\SQLSrv\\SQLSrvConnection::errorCode\(\) should return string\|null but returns false\.\z~' - '~^Method Doctrine\\DBAL\\Driver\\SQLSrv\\SQLSrvConnection::errorCode\(\) should return string\|null but returns false\.\z~'
# https://bugs.php.net/bug.php?id=78126 # https://bugs.php.net/bug.php?id=78126
- '~^Call to an undefined method Doctrine\\DBAL\\Driver\\PDOConnection::sqliteCreateFunction\(\)\.\z~' - '~^Call to an undefined method PDO::sqliteCreateFunction\(\)\.\z~'
# https://github.com/phpstan/phpstan/issues/1847 # https://github.com/phpstan/phpstan/issues/1847
- '~^Parameter #2 \$registeredAliases of static method Doctrine\\DBAL\\Query\\QueryException::unknownAlias\(\) expects array<string>, array<int, int|string> given\.\z~' - '~^Parameter #2 \$registeredAliases of static method Doctrine\\DBAL\\Query\\QueryException::unknownAlias\(\) expects array<string>, array<int, int|string> given\.\z~'
......
...@@ -27,7 +27,6 @@ use Doctrine\Tests\DbalTestCase; ...@@ -27,7 +27,6 @@ use Doctrine\Tests\DbalTestCase;
use Exception; use Exception;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use stdClass; use stdClass;
use function call_user_func_array;
/** /**
* @requires extension pdo_mysql * @requires extension pdo_mysql
...@@ -686,82 +685,28 @@ class ConnectionTest extends DbalTestCase ...@@ -686,82 +685,28 @@ class ConnectionTest extends DbalTestCase
self::assertSame($result, $conn->fetchAll($statement, $params, $types)); self::assertSame($result, $conn->fetchAll($statement, $params, $types));
} }
public function testConnectionDoesNotMaintainTwoReferencesToExternalPDO() : void
{
$params['pdo'] = new stdClass();
$driverMock = $this->createMock(Driver::class);
$conn = new Connection($params, $driverMock);
self::assertArrayNotHasKey('pdo', $conn->getParams(), 'Connection is maintaining additional reference to the PDO connection');
}
public function testPassingExternalPDOMeansConnectionIsConnected() : void
{
$params['pdo'] = new stdClass();
$driverMock = $this->createMock(Driver::class);
$conn = new Connection($params, $driverMock);
self::assertTrue($conn->isConnected(), 'Connection is not connected after passing external PDO');
}
public function testCallingDeleteWithNoDeletionCriteriaResultsInInvalidArgumentException() : void public function testCallingDeleteWithNoDeletionCriteriaResultsInInvalidArgumentException() : void
{ {
/** @var Driver $driver */ /** @var Driver $driver */
$driver = $this->createMock(Driver::class); $driver = $this->createMock(Driver::class);
$pdoMock = $this->createMock(\Doctrine\DBAL\Driver\Connection::class); $conn = new Connection([], $driver);
// should never execute queries with invalid arguments
$pdoMock->expects($this->never())->method('exec');
$pdoMock->expects($this->never())->method('prepare');
$conn = new Connection(['pdo' => $pdoMock], $driver);
$this->expectException(InvalidArgumentException::class); $this->expectException(InvalidArgumentException::class);
$conn->delete('kittens', []); $conn->delete('kittens', []);
} }
/** public function testCallConnectOnce() : void
* @return array<int, array<int, mixed>>
*/
public static function dataCallConnectOnce() : iterable
{
return [
['delete', ['tbl', ['id' => 12345]]],
['insert', ['tbl', ['data' => 'foo']]],
['update', ['tbl', ['data' => 'bar'], ['id' => 12345]]],
['prepare', ['select * from dual']],
['executeUpdate', ['insert into tbl (id) values (?)'], [123]],
];
}
/**
* @param array<int, mixed> $params
*
* @dataProvider dataCallConnectOnce
*/
public function testCallConnectOnce(string $method, array $params) : void
{ {
$driverMock = $this->createMock(Driver::class); /** @var Driver|MockObject $driver */
$pdoMock = $this->createMock(Connection::class); $driver = $this->createMock(Driver::class);
$platformMock = $this->createMock(AbstractPlatform::class); $driver->expects($this->once())
$stmtMock = $this->createMock(Statement::class); ->method('connect');
$pdoMock->expects($this->any())
->method('prepare')
->will($this->returnValue($stmtMock));
$conn = $this->getMockBuilder(Connection::class)
->setConstructorArgs([['pdo' => $pdoMock, 'platform' => $platformMock], $driverMock])
->onlyMethods(['connect'])
->getMock();
$conn->expects($this->once())->method('connect'); $platform = $this->createMock(AbstractPlatform::class);
call_user_func_array([$conn, $method], $params); $conn = new Connection(['platform' => $platform], $driver);
$conn->connect();
$conn->connect();
} }
/** /**
......
...@@ -5,8 +5,10 @@ namespace Doctrine\Tests\DBAL\Driver; ...@@ -5,8 +5,10 @@ namespace Doctrine\Tests\DBAL\Driver;
use Doctrine\DBAL\Driver\PDOException; use Doctrine\DBAL\Driver\PDOException;
use Doctrine\Tests\DbalTestCase; use Doctrine\Tests\DbalTestCase;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use function extension_loaded;
/**
* @requires extension pdo
*/
class PDOExceptionTest extends DbalTestCase class PDOExceptionTest extends DbalTestCase
{ {
public const ERROR_CODE = 666; public const ERROR_CODE = 666;
...@@ -31,10 +33,6 @@ class PDOExceptionTest extends DbalTestCase ...@@ -31,10 +33,6 @@ class PDOExceptionTest extends DbalTestCase
protected function setUp() : void protected function setUp() : void
{ {
if (! extension_loaded('PDO')) {
$this->markTestSkipped('PDO is not installed.');
}
parent::setUp(); parent::setUp();
$this->wrappedException = new \PDOException(self::MESSAGE, self::SQLSTATE); $this->wrappedException = new \PDOException(self::MESSAGE, self::SQLSTATE);
......
...@@ -36,7 +36,7 @@ class DriverTest extends AbstractPostgreSQLDriverTest ...@@ -36,7 +36,7 @@ class DriverTest extends AbstractPostgreSQLDriverTest
self::assertInstanceOf(PDOConnection::class, $connection); self::assertInstanceOf(PDOConnection::class, $connection);
try { try {
self::assertTrue($connection->getAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES)); self::assertTrue($connection->getWrappedConnection()->getAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES));
} catch (PDOException $ignored) { } catch (PDOException $ignored) {
/** @link https://bugs.php.net/bug.php?id=68371 */ /** @link https://bugs.php.net/bug.php?id=68371 */
$this->markTestIncomplete('See https://bugs.php.net/bug.php?id=68371'); $this->markTestIncomplete('See https://bugs.php.net/bug.php?id=68371');
...@@ -63,7 +63,10 @@ class DriverTest extends AbstractPostgreSQLDriverTest ...@@ -63,7 +63,10 @@ class DriverTest extends AbstractPostgreSQLDriverTest
self::assertInstanceOf(PDOConnection::class, $connection); self::assertInstanceOf(PDOConnection::class, $connection);
try { try {
self::assertNotSame(true, $connection->getAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES)); self::assertNotSame(
true,
$connection->getWrappedConnection()->getAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES)
);
} catch (PDOException $ignored) { } catch (PDOException $ignored) {
/** @link https://bugs.php.net/bug.php?id=68371 */ /** @link https://bugs.php.net/bug.php?id=68371 */
$this->markTestIncomplete('See https://bugs.php.net/bug.php?id=68371'); $this->markTestIncomplete('See https://bugs.php.net/bug.php?id=68371');
...@@ -90,7 +93,7 @@ class DriverTest extends AbstractPostgreSQLDriverTest ...@@ -90,7 +93,7 @@ class DriverTest extends AbstractPostgreSQLDriverTest
self::assertInstanceOf(PDOConnection::class, $connection); self::assertInstanceOf(PDOConnection::class, $connection);
try { try {
self::assertTrue($connection->getAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES)); self::assertTrue($connection->getWrappedConnection()->getAttribute(PDO::PGSQL_ATTR_DISABLE_PREPARES));
} catch (PDOException $ignored) { } catch (PDOException $ignored) {
/** @link https://bugs.php.net/bug.php?id=68371 */ /** @link https://bugs.php.net/bug.php?id=68371 */
$this->markTestIncomplete('See https://bugs.php.net/bug.php?id=68371'); $this->markTestIncomplete('See https://bugs.php.net/bug.php?id=68371');
......
...@@ -15,50 +15,13 @@ use Doctrine\DBAL\Platforms\AbstractPlatform; ...@@ -15,50 +15,13 @@ use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Sharding\PoolingShardConnection; use Doctrine\DBAL\Sharding\PoolingShardConnection;
use Doctrine\DBAL\Sharding\ShardChoser\MultiTenantShardChoser; use Doctrine\DBAL\Sharding\ShardChoser\MultiTenantShardChoser;
use Doctrine\Tests\DbalTestCase; use Doctrine\Tests\DbalTestCase;
use PDO;
use stdClass; use stdClass;
use function extension_loaded;
use function get_class; use function get_class;
use function in_array; use function in_array;
use function is_array; use function is_array;
class DriverManagerTest extends DbalTestCase class DriverManagerTest extends DbalTestCase
{ {
/**
* @requires extension pdo_sqlite
*/
public function testInvalidPdoInstance() : void
{
$this->expectException(DBALException::class);
DriverManager::getConnection(['pdo' => 'test']);
}
/**
* @requires extension pdo_sqlite
*/
public function testValidPdoInstance() : void
{
$conn = DriverManager::getConnection([
'pdo' => new PDO('sqlite::memory:'),
]);
self::assertEquals('sqlite', $conn->getDatabasePlatform()->getName());
}
/**
* @group DBAL-32
* @requires extension pdo_sqlite
*/
public function testPdoInstanceSetErrorMode() : void
{
$pdo = new PDO('sqlite::memory:');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
$options = ['pdo' => $pdo];
DriverManager::getConnection($options);
self::assertEquals(PDO::ERRMODE_EXCEPTION, $pdo->getAttribute(PDO::ATTR_ERRMODE));
}
public function testCheckParams() : void public function testCheckParams() : void
{ {
$this->expectException(DBALException::class); $this->expectException(DBALException::class);
...@@ -80,7 +43,7 @@ class DriverManagerTest extends DbalTestCase ...@@ -80,7 +43,7 @@ class DriverManagerTest extends DbalTestCase
{ {
$platform = $this->createMock(AbstractPlatform::class); $platform = $this->createMock(AbstractPlatform::class);
$options = [ $options = [
'pdo' => new PDO('sqlite::memory:'), 'url' => 'sqlite::memory:',
'platform' => $platform, 'platform' => $platform,
]; ];
...@@ -97,7 +60,7 @@ class DriverManagerTest extends DbalTestCase ...@@ -97,7 +60,7 @@ class DriverManagerTest extends DbalTestCase
$wrapperClass = get_class($wrapper); $wrapperClass = get_class($wrapper);
$options = [ $options = [
'pdo' => new PDO('sqlite::memory:'), 'url' => 'sqlite::memory:',
'wrapperClass' => $wrapperClass, 'wrapperClass' => $wrapperClass,
]; ];
...@@ -113,7 +76,7 @@ class DriverManagerTest extends DbalTestCase ...@@ -113,7 +76,7 @@ class DriverManagerTest extends DbalTestCase
$this->expectException(DBALException::class); $this->expectException(DBALException::class);
$options = [ $options = [
'pdo' => new PDO('sqlite::memory:'), 'url' => 'sqlite::memory:',
'wrapperClass' => stdClass::class, 'wrapperClass' => stdClass::class,
]; ];
...@@ -215,16 +178,6 @@ class DriverManagerTest extends DbalTestCase ...@@ -215,16 +178,6 @@ class DriverManagerTest extends DbalTestCase
{ {
$options = is_array($url) ? $url : ['url' => $url]; $options = is_array($url) ? $url : ['url' => $url];
if (isset($options['pdo'])) {
if (! extension_loaded('pdo')) {
$this->markTestSkipped('PDO is not installed');
}
$options['pdo'] = $this->createMock(PDO::class);
}
$options = is_array($url) ? $url : ['url' => $url];
if ($expected === false) { if ($expected === false) {
$this->expectException(DBALException::class); $this->expectException(DBALException::class);
} }
...@@ -233,7 +186,7 @@ class DriverManagerTest extends DbalTestCase ...@@ -233,7 +186,7 @@ class DriverManagerTest extends DbalTestCase
$params = $conn->getParams(); $params = $conn->getParams();
foreach ($expected as $key => $value) { foreach ($expected as $key => $value) {
if (in_array($key, ['pdo', 'driver', 'driverClass'], true)) { if (in_array($key, ['driver', 'driverClass'], true)) {
self::assertInstanceOf($value, $conn->getDriver()); self::assertInstanceOf($value, $conn->getDriver());
} else { } else {
self::assertEquals($value, $params[$key]); self::assertEquals($value, $params[$key]);
...@@ -394,13 +347,6 @@ class DriverManagerTest extends DbalTestCase ...@@ -394,13 +347,6 @@ class DriverManagerTest extends DbalTestCase
['url' => '//foo:bar@localhost/baz'], ['url' => '//foo:bar@localhost/baz'],
false, false,
], ],
'URL without scheme but default PDO driver' => [
[
'url' => '//foo:bar@localhost/baz',
'pdo' => true,
],
false,
],
'URL without scheme but default driver' => [ 'URL without scheme but default driver' => [
[ [
'url' => '//foo:bar@localhost/baz', 'url' => '//foo:bar@localhost/baz',
...@@ -427,20 +373,6 @@ class DriverManagerTest extends DbalTestCase ...@@ -427,20 +373,6 @@ class DriverManagerTest extends DbalTestCase
'driverClass' => $driverClass, 'driverClass' => $driverClass,
], ],
], ],
'URL without scheme but default PDO driver and default driver' => [
[
'url' => '//foo:bar@localhost/baz',
'pdo' => true,
'driver' => 'pdo_mysql',
],
[
'user' => 'foo',
'password' => 'bar',
'host' => 'localhost',
'dbname' => 'baz',
'driver' => PDOMySQLDriver::class,
],
],
'URL without scheme but driver and custom driver' => [ 'URL without scheme but driver and custom driver' => [
[ [
'url' => '//foo:bar@localhost/baz', 'url' => '//foo:bar@localhost/baz',
...@@ -455,19 +387,6 @@ class DriverManagerTest extends DbalTestCase ...@@ -455,19 +387,6 @@ class DriverManagerTest extends DbalTestCase
'driverClass' => $driverClass, 'driverClass' => $driverClass,
], ],
], ],
'URL with default PDO driver' => [
[
'url' => 'mysql://foo:bar@localhost/baz',
'pdo' => true,
],
[
'user' => 'foo',
'password' => 'bar',
'host' => 'localhost',
'dbname' => 'baz',
'driver' => PDOMySQLDriver::class,
],
],
'URL with default driver' => [ 'URL with default driver' => [
[ [
'url' => 'mysql://foo:bar@localhost/baz', 'url' => 'mysql://foo:bar@localhost/baz',
...@@ -494,20 +413,6 @@ class DriverManagerTest extends DbalTestCase ...@@ -494,20 +413,6 @@ class DriverManagerTest extends DbalTestCase
'driver' => PDOMySQLDriver::class, 'driver' => PDOMySQLDriver::class,
], ],
], ],
'URL with default PDO driver and default driver' => [
[
'url' => 'mysql://foo:bar@localhost/baz',
'pdo' => true,
'driver' => 'sqlite',
],
[
'user' => 'foo',
'password' => 'bar',
'host' => 'localhost',
'dbname' => 'baz',
'driver' => PDOMySQLDriver::class,
],
],
'URL with default driver and default custom driver' => [ 'URL with default driver and default custom driver' => [
[ [
'url' => 'mysql://foo:bar@localhost/baz', 'url' => 'mysql://foo:bar@localhost/baz',
...@@ -522,21 +427,6 @@ class DriverManagerTest extends DbalTestCase ...@@ -522,21 +427,6 @@ class DriverManagerTest extends DbalTestCase
'driver' => PDOMySQLDriver::class, 'driver' => PDOMySQLDriver::class,
], ],
], ],
'URL with default PDO driver and default driver and default custom driver' => [
[
'url' => 'mysql://foo:bar@localhost/baz',
'pdo' => true,
'driver' => 'sqlite',
'driverClass' => $driverClass,
],
[
'user' => 'foo',
'password' => 'bar',
'host' => 'localhost',
'dbname' => 'baz',
'driver' => PDOMySQLDriver::class,
],
],
]; ];
} }
} }
...@@ -5,11 +5,15 @@ namespace Doctrine\Tests\DBAL\Functional; ...@@ -5,11 +5,15 @@ namespace Doctrine\Tests\DBAL\Functional;
use Doctrine\DBAL\Connection; use Doctrine\DBAL\Connection;
use Doctrine\DBAL\ConnectionException; use Doctrine\DBAL\ConnectionException;
use Doctrine\DBAL\Driver\Connection as DriverConnection; use Doctrine\DBAL\Driver\Connection as DriverConnection;
use Doctrine\DBAL\Driver\PDOConnection;
use Doctrine\DBAL\DriverManager; use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\SqlitePlatform;
use Doctrine\DBAL\Platforms\SQLServerPlatform;
use Doctrine\DBAL\Types\Types; use Doctrine\DBAL\Types\Types;
use Doctrine\Tests\DbalFunctionalTestCase; use Doctrine\Tests\DbalFunctionalTestCase;
use Doctrine\Tests\TestUtil;
use Error; use Error;
use Exception; use Exception;
use PDO; use PDO;
...@@ -353,15 +357,27 @@ class ConnectionTest extends DbalFunctionalTestCase ...@@ -353,15 +357,27 @@ class ConnectionTest extends DbalFunctionalTestCase
$connection->close(); $connection->close();
} }
/** public function testPersistentConnection() : void
* @requires extension pdo_sqlite
*/
public function testUserProvidedPDOConnection() : void
{ {
self::assertTrue( $platform = $this->connection->getDatabasePlatform();
DriverManager::getConnection([
'pdo' => new PDO('sqlite::memory:'), if ($platform instanceof SqlitePlatform
])->ping() || $platform instanceof SQLServerPlatform) {
); self::markTestSkipped('The platform does not support persistent connections');
}
$params = TestUtil::getConnectionParams();
$params['persistent'] = true;
$connection = DriverManager::getConnection($params);
$driverConnection = $connection->getWrappedConnection();
if (! $driverConnection instanceof PDOConnection) {
self::markTestSkipped('Unable to test if the connection is persistent');
}
$pdo = $driverConnection->getWrappedConnection();
self::assertTrue($pdo->getAttribute(PDO::ATTR_PERSISTENT));
} }
} }
...@@ -954,8 +954,9 @@ class DataAccessTest extends DbalFunctionalTestCase ...@@ -954,8 +954,9 @@ class DataAccessTest extends DbalFunctionalTestCase
} }
/** @var PDOConnection $connection */ /** @var PDOConnection $connection */
$connection = $this->connection->getWrappedConnection(); $connection = $this->connection
$connection->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER); ->getWrappedConnection();
$connection->getWrappedConnection()->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
} }
} }
......
...@@ -9,10 +9,12 @@ use Doctrine\DBAL\Driver\PDOPgSql\Driver as PDOPgSQLDriver; ...@@ -9,10 +9,12 @@ use Doctrine\DBAL\Driver\PDOPgSql\Driver as PDOPgSQLDriver;
use Doctrine\DBAL\Driver\PDOSqlsrv\Driver as PDOSQLSRVDriver; use Doctrine\DBAL\Driver\PDOSqlsrv\Driver as PDOSQLSRVDriver;
use Doctrine\Tests\DbalFunctionalTestCase; use Doctrine\Tests\DbalFunctionalTestCase;
use PDO; use PDO;
use function extension_loaded;
use function get_class; use function get_class;
use function sprintf; use function sprintf;
/**
* @requires extension pdo
*/
class PDOConnectionTest extends DbalFunctionalTestCase class PDOConnectionTest extends DbalFunctionalTestCase
{ {
/** /**
...@@ -24,10 +26,6 @@ class PDOConnectionTest extends DbalFunctionalTestCase ...@@ -24,10 +26,6 @@ class PDOConnectionTest extends DbalFunctionalTestCase
protected function setUp() : void protected function setUp() : void
{ {
if (! extension_loaded('PDO')) {
$this->markTestSkipped('PDO is not installed.');
}
parent::setUp(); parent::setUp();
$this->driverConnection = $this->connection->getWrappedConnection(); $this->driverConnection = $this->connection->getWrappedConnection();
...@@ -90,7 +88,9 @@ class PDOConnectionTest extends DbalFunctionalTestCase ...@@ -90,7 +88,9 @@ class PDOConnectionTest extends DbalFunctionalTestCase
// Emulated prepared statements have to be disabled for this test // Emulated prepared statements have to be disabled for this test
// so that PDO actually communicates with the database server to check the query. // so that PDO actually communicates with the database server to check the query.
$this->driverConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $this->driverConnection
->getWrappedConnection()
->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$this->expectException(PDOException::class); $this->expectException(PDOException::class);
......
...@@ -4,9 +4,11 @@ namespace Doctrine\Tests\DBAL\Functional\Driver\PDOSqlsrv; ...@@ -4,9 +4,11 @@ namespace Doctrine\Tests\DBAL\Functional\Driver\PDOSqlsrv;
use Doctrine\DBAL\Driver as DriverInterface; use Doctrine\DBAL\Driver as DriverInterface;
use Doctrine\DBAL\Driver\Connection; use Doctrine\DBAL\Driver\Connection;
use Doctrine\DBAL\Driver\PDOConnection;
use Doctrine\DBAL\Driver\PDOSqlsrv\Driver; use Doctrine\DBAL\Driver\PDOSqlsrv\Driver;
use Doctrine\Tests\DBAL\Functional\Driver\AbstractDriverTest; use Doctrine\Tests\DBAL\Functional\Driver\AbstractDriverTest;
use PDO; use PDO;
use function assert;
use function extension_loaded; use function extension_loaded;
class DriverTest extends AbstractDriverTest class DriverTest extends AbstractDriverTest
...@@ -70,6 +72,13 @@ class DriverTest extends AbstractDriverTest ...@@ -70,6 +72,13 @@ class DriverTest extends AbstractDriverTest
{ {
$connection = $this->getConnection([PDO::ATTR_CASE => PDO::CASE_UPPER]); $connection = $this->getConnection([PDO::ATTR_CASE => PDO::CASE_UPPER]);
self::assertSame(PDO::CASE_UPPER, $connection->getAttribute(PDO::ATTR_CASE)); assert($connection instanceof PDOConnection);
self::assertSame(
PDO::CASE_UPPER,
$connection
->getWrappedConnection()
->getAttribute(PDO::ATTR_CASE)
);
} }
} }
...@@ -27,7 +27,7 @@ class StatementTest extends DbalFunctionalTestCase ...@@ -27,7 +27,7 @@ class StatementTest extends DbalFunctionalTestCase
public function testFailureToPrepareResultsInException() : void public function testFailureToPrepareResultsInException() : void
{ {
// use the driver connection directly to avoid having exception wrapped // use the driver connection directly to avoid having exception wrapped
$stmt = $this->connection->getWrappedConnection()->prepare(null); $stmt = $this->connection->getWrappedConnection()->prepare('');
// it's impossible to prepare the statement without bound variables for SQL Server, // it's impossible to prepare the statement without bound variables for SQL Server,
// so the preparation happens before the first execution when variables are already in place // so the preparation happens before the first execution when variables are already in place
......
<?php
namespace Doctrine\Tests\DBAL\Functional;
use Doctrine\DBAL\Driver\PDOConnection;
use Doctrine\DBAL\Schema\Table;
use Doctrine\Tests\DbalFunctionalTestCase;
use PDO;
use function extension_loaded;
class PDOStatementTest extends DbalFunctionalTestCase
{
protected function setUp() : void
{
if (! extension_loaded('pdo')) {
$this->markTestSkipped('PDO is not installed');
}
parent::setUp();
if (! $this->connection->getWrappedConnection() instanceof PDOConnection) {
$this->markTestSkipped('PDO-only test');
}
$table = new Table('stmt_test');
$table->addColumn('id', 'integer');
$table->addColumn('name', 'string');
$this->connection->getSchemaManager()->dropAndCreateTable($table);
}
/**
* @group legacy
* @expectedDeprecation Using a PDO fetch mode or their combination (%d given) is deprecated and will cause an error in Doctrine DBAL 3.0
*/
public function testPDOSpecificModeIsAccepted() : void
{
$this->connection->insert('stmt_test', [
'id' => 1,
'name' => 'Alice',
]);
$this->connection->insert('stmt_test', [
'id' => 2,
'name' => 'Bob',
]);
$data = $this->connection->query('SELECT id, name FROM stmt_test ORDER BY id')
->fetchAll(PDO::FETCH_KEY_PAIR);
self::assertSame([
1 => 'Alice',
2 => 'Bob',
], $data);
}
}
...@@ -37,7 +37,9 @@ class DBAL630Test extends DbalFunctionalTestCase ...@@ -37,7 +37,9 @@ class DBAL630Test extends DbalFunctionalTestCase
protected function tearDown() : void protected function tearDown() : void
{ {
if ($this->running) { if ($this->running) {
$this->connection->getWrappedConnection()->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $this->connection->getWrappedConnection()
->getWrappedConnection()
->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
} }
parent::tearDown(); parent::tearDown();
...@@ -71,7 +73,9 @@ class DBAL630Test extends DbalFunctionalTestCase ...@@ -71,7 +73,9 @@ class DBAL630Test extends DbalFunctionalTestCase
public function testBooleanConversionBoolParamEmulatedPrepares() : void public function testBooleanConversionBoolParamEmulatedPrepares() : void
{ {
$this->connection->getWrappedConnection()->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); $this->connection->getWrappedConnection()
->getWrappedConnection()
->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
$platform = $this->connection->getDatabasePlatform(); $platform = $this->connection->getDatabasePlatform();
...@@ -95,7 +99,9 @@ class DBAL630Test extends DbalFunctionalTestCase ...@@ -95,7 +99,9 @@ class DBAL630Test extends DbalFunctionalTestCase
?bool $statementValue, ?bool $statementValue,
?bool $databaseConvertedValue ?bool $databaseConvertedValue
) : void { ) : void {
$this->connection->getWrappedConnection()->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); $this->connection->getWrappedConnection()
->getWrappedConnection()
->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
$platform = $this->connection->getDatabasePlatform(); $platform = $this->connection->getDatabasePlatform();
...@@ -119,7 +125,9 @@ class DBAL630Test extends DbalFunctionalTestCase ...@@ -119,7 +125,9 @@ class DBAL630Test extends DbalFunctionalTestCase
?bool $statementValue, ?bool $statementValue,
bool $databaseConvertedValue bool $databaseConvertedValue
) : void { ) : void {
$this->connection->getWrappedConnection()->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); $this->connection->getWrappedConnection()
->getWrappedConnection()
->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
$platform = $this->connection->getDatabasePlatform(); $platform = $this->connection->getDatabasePlatform();
......
...@@ -7,6 +7,7 @@ use Doctrine\DBAL\Connection; ...@@ -7,6 +7,7 @@ use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DBALException; use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver; use Doctrine\DBAL\Driver;
use Doctrine\DBAL\Driver\Connection as DriverConnection; use Doctrine\DBAL\Driver\Connection as DriverConnection;
use Doctrine\DBAL\Driver\Statement as DriverStatement;
use Doctrine\DBAL\Logging\SQLLogger; use Doctrine\DBAL\Logging\SQLLogger;
use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Statement; use Doctrine\DBAL\Statement;
...@@ -23,18 +24,15 @@ class StatementTest extends DbalTestCase ...@@ -23,18 +24,15 @@ class StatementTest extends DbalTestCase
private $configuration; private $configuration;
/** @var PDOStatement */ /** @var PDOStatement */
private $pdoStatement; private $driverStatement;
protected function setUp() : void protected function setUp() : void
{ {
$this->pdoStatement = $this->getMockBuilder(PDOStatement::class) $this->driverStatement = $this->createMock(DriverStatement::class);
->onlyMethods(['execute', 'bindParam', 'bindValue'])
->getMock();
$driverConnection = $this->createMock(DriverConnection::class); $driverConnection = $this->createConfiguredMock(DriverConnection::class, [
$driverConnection->expects($this->any()) 'prepare' => $this->driverStatement,
->method('prepare') ]);
->will($this->returnValue($this->pdoStatement));
$driver = $this->createMock(Driver::class); $driver = $this->createMock(Driver::class);
...@@ -140,7 +138,7 @@ class StatementTest extends DbalTestCase ...@@ -140,7 +138,7 @@ class StatementTest extends DbalTestCase
$logger->expects($this->once()) $logger->expects($this->once())
->method('stopQuery'); ->method('stopQuery');
$this->pdoStatement->expects($this->once()) $this->driverStatement->expects($this->once())
->method('execute') ->method('execute')
->will($this->throwException(new Exception('Mock test exception'))); ->will($this->throwException(new Exception('Mock test exception')));
......
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