Unverified Commit f0e37197 authored by Sergei Morozov's avatar Sergei Morozov

Merge pull request #3548 from morozov/issues/3545

Remove user provided PDO functionality
parents 5193c972 735b5a07
# Upgrade to 3.0 # 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 PostgreSqlPlatform ForeignKeyConstraint support for `feferred` misspelling removed ## BC BREAK PostgreSqlPlatform ForeignKeyConstraint support for `feferred` misspelling removed
`PostgreSqlPlatform::getAdvancedForeignKeyOptionsSQL()` had a typo in it in 2.x. Both the option name `PostgreSqlPlatform::getAdvancedForeignKeyOptionsSQL()` had a typo in it in 2.x. Both the option name
......
...@@ -197,12 +197,6 @@ class Connection implements DriverConnection ...@@ -197,12 +197,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 InvalidPlatformType::new($params['platform']); throw InvalidPlatformType::new($params['platform']);
......
...@@ -17,10 +17,8 @@ use Doctrine\DBAL\Driver\SQLAnywhere\Driver as SQLAnywhereDriver; ...@@ -17,10 +17,8 @@ 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 Doctrine\DBAL\Exception\DriverRequired; use Doctrine\DBAL\Exception\DriverRequired;
use Doctrine\DBAL\Exception\InvalidDriverClass; use Doctrine\DBAL\Exception\InvalidDriverClass;
use Doctrine\DBAL\Exception\InvalidPdoInstance;
use Doctrine\DBAL\Exception\InvalidWrapperClass; use Doctrine\DBAL\Exception\InvalidWrapperClass;
use Doctrine\DBAL\Exception\UnknownDriver; use Doctrine\DBAL\Exception\UnknownDriver;
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;
...@@ -175,17 +173,7 @@ final class DriverManager ...@@ -175,17 +173,7 @@ final class DriverManager
} }
} }
// check for existing pdo object self::_checkParams($params);
if (isset($params['pdo']) && ! $params['pdo'] instanceof PDO) {
throw InvalidPdoInstance::new();
}
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);
}
$className = $params['driverClass'] ?? self::$_driverMap[$params['driver']]; $className = $params['driverClass'] ?? self::$_driverMap[$params['driver']];
...@@ -281,10 +269,6 @@ final class DriverManager ...@@ -281,10 +269,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'])) {
......
<?php
declare(strict_types=1);
namespace Doctrine\DBAL\Exception;
use Doctrine\DBAL\DBALException;
final class InvalidPdoInstance extends DBALException
{
public static function new() : self
{
return new self('The "pdo" option was used in DriverManager::getConnection() but no instance of PDO was given.');
}
}
...@@ -29,7 +29,6 @@ use Doctrine\Tests\DbalTestCase; ...@@ -29,7 +29,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
...@@ -664,82 +663,28 @@ class ConnectionTest extends DbalTestCase ...@@ -664,82 +663,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();
} }
/** /**
......
...@@ -7,8 +7,10 @@ namespace Doctrine\Tests\DBAL\Driver; ...@@ -7,8 +7,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;
...@@ -33,10 +35,6 @@ class PDOExceptionTest extends DbalTestCase ...@@ -33,10 +35,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); $this->wrappedException = new \PDOException(self::MESSAGE);
......
...@@ -16,50 +16,13 @@ use Doctrine\DBAL\Platforms\AbstractPlatform; ...@@ -16,50 +16,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);
...@@ -81,7 +44,7 @@ class DriverManagerTest extends DbalTestCase ...@@ -81,7 +44,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,
]; ];
...@@ -98,7 +61,7 @@ class DriverManagerTest extends DbalTestCase ...@@ -98,7 +61,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,
]; ];
...@@ -114,7 +77,7 @@ class DriverManagerTest extends DbalTestCase ...@@ -114,7 +77,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,
]; ];
...@@ -216,16 +179,6 @@ class DriverManagerTest extends DbalTestCase ...@@ -216,16 +179,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);
} }
...@@ -234,7 +187,7 @@ class DriverManagerTest extends DbalTestCase ...@@ -234,7 +187,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]);
...@@ -395,13 +348,6 @@ class DriverManagerTest extends DbalTestCase ...@@ -395,13 +348,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',
...@@ -428,20 +374,6 @@ class DriverManagerTest extends DbalTestCase ...@@ -428,20 +374,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',
...@@ -456,19 +388,6 @@ class DriverManagerTest extends DbalTestCase ...@@ -456,19 +388,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',
...@@ -495,20 +414,6 @@ class DriverManagerTest extends DbalTestCase ...@@ -495,20 +414,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',
...@@ -523,21 +428,6 @@ class DriverManagerTest extends DbalTestCase ...@@ -523,21 +428,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,
],
],
]; ];
} }
} }
...@@ -353,18 +353,6 @@ class ConnectionTest extends DbalFunctionalTestCase ...@@ -353,18 +353,6 @@ class ConnectionTest extends DbalFunctionalTestCase
$connection->close(); $connection->close();
} }
/**
* @requires extension pdo_sqlite
*/
public function testUserProvidedPDOConnection() : void
{
self::assertTrue(
DriverManager::getConnection([
'pdo' => new PDO('sqlite::memory:'),
])->ping()
);
}
public function testPersistentConnection() : void public function testPersistentConnection() : void
{ {
$platform = $this->connection->getDatabasePlatform(); $platform = $this->connection->getDatabasePlatform();
......
...@@ -11,10 +11,12 @@ use Doctrine\DBAL\Driver\PDOPgSql\Driver as PDOPgSQLDriver; ...@@ -11,10 +11,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
{ {
/** /**
...@@ -26,10 +28,6 @@ class PDOConnectionTest extends DbalFunctionalTestCase ...@@ -26,10 +28,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();
......
...@@ -8,16 +8,14 @@ use Doctrine\DBAL\Driver\PDOConnection; ...@@ -8,16 +8,14 @@ use Doctrine\DBAL\Driver\PDOConnection;
use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Schema\Table;
use Doctrine\Tests\DbalFunctionalTestCase; use Doctrine\Tests\DbalFunctionalTestCase;
use PDO; use PDO;
use function extension_loaded;
/**
* @requires extension pdo
*/
class PDOStatementTest extends DbalFunctionalTestCase class PDOStatementTest extends DbalFunctionalTestCase
{ {
protected function setUp() : void protected function setUp() : void
{ {
if (! extension_loaded('pdo')) {
$this->markTestSkipped('PDO is not installed');
}
parent::setUp(); parent::setUp();
if (! $this->connection->getWrappedConnection() instanceof PDOConnection) { if (! $this->connection->getWrappedConnection() instanceof PDOConnection) {
......
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