Unverified Commit 7addd996 authored by Sergei Morozov's avatar Sergei Morozov Committed by GitHub

Merge pull request #4119 from morozov/deprecate-pingable

Deprecate PingableConnection in favor of handling lost connection
parents 4cb9e36d 0a5bac1c
# Upgrade to 2.11 # Upgrade to 2.11
## Statement constructors are marked internal
The driver and wrapper statement objects can be only created by the corresponding connection objects.
## The `PingableConnection` interface is deprecated
The wrapper connection will automatically handle the lost connection if the driver supports reporting it.
## The `ExceptionConverterDriver` interface is deprecated ## The `ExceptionConverterDriver` interface is deprecated
All drivers will have to implement the exception conversion API. All drivers will have to implement the exception conversion API.
......
...@@ -13,6 +13,7 @@ use Doctrine\DBAL\Driver\Connection as DriverConnection; ...@@ -13,6 +13,7 @@ use Doctrine\DBAL\Driver\Connection as DriverConnection;
use Doctrine\DBAL\Driver\PingableConnection; use Doctrine\DBAL\Driver\PingableConnection;
use Doctrine\DBAL\Driver\ResultStatement; use Doctrine\DBAL\Driver\ResultStatement;
use Doctrine\DBAL\Driver\ServerInfoAwareConnection; use Doctrine\DBAL\Driver\ServerInfoAwareConnection;
use Doctrine\DBAL\Exception\ConnectionLost;
use Doctrine\DBAL\Exception\InvalidArgumentException; use Doctrine\DBAL\Exception\InvalidArgumentException;
use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Query\Expression\ExpressionBuilder; use Doctrine\DBAL\Query\Expression\ExpressionBuilder;
...@@ -614,7 +615,7 @@ class Connection implements DriverConnection ...@@ -614,7 +615,7 @@ class Connection implements DriverConnection
return $stmt->fetch(FetchMode::ASSOCIATIVE); return $stmt->fetch(FetchMode::ASSOCIATIVE);
} catch (Throwable $e) { } catch (Throwable $e) {
throw DBALException::driverExceptionDuringQuery($this->_driver, $e, $query); $this->handleExceptionDuringQuery($e, $query, $params, $types);
} }
} }
...@@ -641,7 +642,7 @@ class Connection implements DriverConnection ...@@ -641,7 +642,7 @@ class Connection implements DriverConnection
return $stmt->fetch(FetchMode::NUMERIC); return $stmt->fetch(FetchMode::NUMERIC);
} catch (Throwable $e) { } catch (Throwable $e) {
throw DBALException::driverExceptionDuringQuery($this->_driver, $e, $query); $this->handleExceptionDuringQuery($e, $query, $params, $types);
} }
} }
...@@ -668,7 +669,7 @@ class Connection implements DriverConnection ...@@ -668,7 +669,7 @@ class Connection implements DriverConnection
return $stmt->fetch(FetchMode::COLUMN); return $stmt->fetch(FetchMode::COLUMN);
} catch (Throwable $e) { } catch (Throwable $e) {
throw DBALException::driverExceptionDuringQuery($this->_driver, $e, $query); $this->handleExceptionDuringQuery($e, $query, $params, $types);
} }
} }
...@@ -952,7 +953,7 @@ class Connection implements DriverConnection ...@@ -952,7 +953,7 @@ class Connection implements DriverConnection
return $stmt->fetchAll(FetchMode::NUMERIC); return $stmt->fetchAll(FetchMode::NUMERIC);
} catch (Throwable $e) { } catch (Throwable $e) {
throw DBALException::driverExceptionDuringQuery($this->_driver, $e, $query); $this->handleExceptionDuringQuery($e, $query, $params, $types);
} }
} }
...@@ -978,7 +979,7 @@ class Connection implements DriverConnection ...@@ -978,7 +979,7 @@ class Connection implements DriverConnection
return $stmt->fetchAll(FetchMode::ASSOCIATIVE); return $stmt->fetchAll(FetchMode::ASSOCIATIVE);
} catch (Throwable $e) { } catch (Throwable $e) {
throw DBALException::driverExceptionDuringQuery($this->_driver, $e, $query); $this->handleExceptionDuringQuery($e, $query, $params, $types);
} }
} }
...@@ -1004,7 +1005,7 @@ class Connection implements DriverConnection ...@@ -1004,7 +1005,7 @@ class Connection implements DriverConnection
return $stmt->fetchAll(FetchMode::COLUMN); return $stmt->fetchAll(FetchMode::COLUMN);
} catch (Throwable $e) { } catch (Throwable $e) {
throw DBALException::driverExceptionDuringQuery($this->_driver, $e, $query); $this->handleExceptionDuringQuery($e, $query, $params, $types);
} }
} }
...@@ -1032,7 +1033,7 @@ class Connection implements DriverConnection ...@@ -1032,7 +1033,7 @@ class Connection implements DriverConnection
} }
} }
} catch (Throwable $e) { } catch (Throwable $e) {
throw DBALException::driverExceptionDuringQuery($this->_driver, $e, $query); $this->handleExceptionDuringQuery($e, $query, $params, $types);
} }
} }
...@@ -1060,7 +1061,7 @@ class Connection implements DriverConnection ...@@ -1060,7 +1061,7 @@ class Connection implements DriverConnection
} }
} }
} catch (Throwable $e) { } catch (Throwable $e) {
throw DBALException::driverExceptionDuringQuery($this->_driver, $e, $query); $this->handleExceptionDuringQuery($e, $query, $params, $types);
} }
} }
...@@ -1088,7 +1089,7 @@ class Connection implements DriverConnection ...@@ -1088,7 +1089,7 @@ class Connection implements DriverConnection
} }
} }
} catch (Throwable $e) { } catch (Throwable $e) {
throw DBALException::driverExceptionDuringQuery($this->_driver, $e, $query); $this->handleExceptionDuringQuery($e, $query, $params, $types);
} }
} }
...@@ -1105,8 +1106,8 @@ class Connection implements DriverConnection ...@@ -1105,8 +1106,8 @@ class Connection implements DriverConnection
{ {
try { try {
$stmt = new Statement($statement, $this); $stmt = new Statement($statement, $this);
} catch (Throwable $ex) { } catch (Throwable $e) {
throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $statement); $this->handleExceptionDuringQuery($e, $statement);
} }
$stmt->setFetchMode($this->defaultFetchMode); $stmt->setFetchMode($this->defaultFetchMode);
...@@ -1156,8 +1157,8 @@ class Connection implements DriverConnection ...@@ -1156,8 +1157,8 @@ class Connection implements DriverConnection
} else { } else {
$stmt = $connection->query($query); $stmt = $connection->query($query);
} }
} catch (Throwable $ex) { } catch (Throwable $e) {
throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $query, $this->resolveParams($params, $types)); $this->handleExceptionDuringQuery($e, $query, $params, $types);
} }
$stmt->setFetchMode($this->defaultFetchMode); $stmt->setFetchMode($this->defaultFetchMode);
...@@ -1263,8 +1264,8 @@ class Connection implements DriverConnection ...@@ -1263,8 +1264,8 @@ class Connection implements DriverConnection
try { try {
$statement = $connection->query(...$args); $statement = $connection->query(...$args);
} catch (Throwable $ex) { } catch (Throwable $e) {
throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $args[0]); $this->handleExceptionDuringQuery($e, $args[0]);
} }
$statement->setFetchMode($this->defaultFetchMode); $statement->setFetchMode($this->defaultFetchMode);
...@@ -1316,8 +1317,8 @@ class Connection implements DriverConnection ...@@ -1316,8 +1317,8 @@ class Connection implements DriverConnection
} else { } else {
$result = $connection->exec($query); $result = $connection->exec($query);
} }
} catch (Throwable $ex) { } catch (Throwable $e) {
throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $query, $this->resolveParams($params, $types)); $this->handleExceptionDuringQuery($e, $query, $params, $types);
} }
if ($logger) { if ($logger) {
...@@ -1347,8 +1348,8 @@ class Connection implements DriverConnection ...@@ -1347,8 +1348,8 @@ class Connection implements DriverConnection
try { try {
$result = $connection->exec($statement); $result = $connection->exec($statement);
} catch (Throwable $ex) { } catch (Throwable $e) {
throw DBALException::driverExceptionDuringQuery($this->_driver, $ex, $statement); $this->handleExceptionDuringQuery($e, $statement);
} }
if ($logger) { if ($logger) {
...@@ -1924,6 +1925,8 @@ class Connection implements DriverConnection ...@@ -1924,6 +1925,8 @@ class Connection implements DriverConnection
* It is responsibility of the developer to handle this case * It is responsibility of the developer to handle this case
* and abort the request or reconnect manually: * and abort the request or reconnect manually:
* *
* @deprecated
*
* @return bool * @return bool
* *
* @example * @example
...@@ -1954,4 +1957,59 @@ class Connection implements DriverConnection ...@@ -1954,4 +1957,59 @@ class Connection implements DriverConnection
return false; return false;
} }
} }
/**
* @internal
*
* @param array<int, mixed>|array<string, mixed> $params
* @param array<int, int|string>|array<string, int|string> $types
*
* @throws DBALException
*
* @psalm-return never-return
*/
public function handleExceptionDuringQuery(Throwable $e, string $sql, array $params = [], array $types = []): void
{
$this->throw(
DBALException::driverExceptionDuringQuery(
$this->_driver,
$e,
$sql,
$this->resolveParams($params, $types)
)
);
}
/**
* @internal
*
* @throws DBALException
*
* @psalm-return never-return
*/
public function handleDriverException(Throwable $e): void
{
$this->throw(
DBALException::driverException(
$this->_driver,
$e
)
);
}
/**
* @internal
*
* @throws DBALException
*
* @psalm-return never-return
*/
private function throw(DBALException $e): void
{
if ($e instanceof ConnectionLost) {
$this->close();
}
throw $e;
}
} }
...@@ -7,6 +7,7 @@ use Doctrine\DBAL\DBALException; ...@@ -7,6 +7,7 @@ use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver; use Doctrine\DBAL\Driver;
use Doctrine\DBAL\Driver\DriverException as DeprecatedDriverException; use Doctrine\DBAL\Driver\DriverException as DeprecatedDriverException;
use Doctrine\DBAL\Exception\ConnectionException; use Doctrine\DBAL\Exception\ConnectionException;
use Doctrine\DBAL\Exception\ConnectionLost;
use Doctrine\DBAL\Exception\DeadlockException; use Doctrine\DBAL\Exception\DeadlockException;
use Doctrine\DBAL\Exception\DriverException; use Doctrine\DBAL\Exception\DriverException;
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException; use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
...@@ -108,6 +109,9 @@ abstract class AbstractMySQLDriver implements Driver, ExceptionConverterDriver, ...@@ -108,6 +109,9 @@ abstract class AbstractMySQLDriver implements Driver, ExceptionConverterDriver,
case '2005': case '2005':
return new ConnectionException($message, $exception); return new ConnectionException($message, $exception);
case '2006':
return new ConnectionLost($message, $exception);
case '1048': case '1048':
case '1121': case '1121':
case '1138': case '1138':
......
...@@ -92,6 +92,8 @@ class DB2Statement implements IteratorAggregate, StatementInterface, Result ...@@ -92,6 +92,8 @@ class DB2Statement implements IteratorAggregate, StatementInterface, Result
private $result = false; private $result = false;
/** /**
* @internal The statement can be only instantiated by its driver connection.
*
* @param resource $stmt * @param resource $stmt
*/ */
public function __construct($stmt) public function __construct($stmt)
......
...@@ -281,6 +281,8 @@ class MysqliConnection implements ConnectionInterface, PingableConnection, Serve ...@@ -281,6 +281,8 @@ class MysqliConnection implements ConnectionInterface, PingableConnection, Serve
/** /**
* Pings the server and re-connects when `mysqli.reconnect = 1` * Pings the server and re-connects when `mysqli.reconnect = 1`
* *
* @deprecated
*
* @return bool * @return bool
*/ */
public function ping() public function ping()
......
...@@ -82,6 +82,8 @@ class MysqliStatement implements IteratorAggregate, StatementInterface, Result ...@@ -82,6 +82,8 @@ class MysqliStatement implements IteratorAggregate, StatementInterface, Result
private $result = false; private $result = false;
/** /**
* @internal The statement can be only instantiated by its driver connection.
*
* @param string $prepareString * @param string $prepareString
* *
* @throws MysqliException * @throws MysqliException
......
...@@ -105,6 +105,8 @@ class OCI8Statement implements IteratorAggregate, StatementInterface, Result ...@@ -105,6 +105,8 @@ class OCI8Statement implements IteratorAggregate, StatementInterface, Result
/** /**
* Creates a new OCI8Statement that uses the given connection handle and SQL statement. * Creates a new OCI8Statement that uses the given connection handle and SQL statement.
* *
* @internal The statement can be only instantiated by its driver connection.
*
* @param resource $dbh The connection handle. * @param resource $dbh The connection handle.
* @param string $query The SQL query. * @param string $query The SQL query.
*/ */
......
...@@ -46,6 +46,8 @@ class PDOStatement extends \PDOStatement implements StatementInterface, Result ...@@ -46,6 +46,8 @@ class PDOStatement extends \PDOStatement implements StatementInterface, Result
/** /**
* Protected constructor. * Protected constructor.
*
* @internal The statement can be only instantiated by its driver connection.
*/ */
protected function __construct() protected function __construct()
{ {
......
...@@ -4,6 +4,8 @@ namespace Doctrine\DBAL\Driver; ...@@ -4,6 +4,8 @@ namespace Doctrine\DBAL\Driver;
/** /**
* An interface for connections which support a "native" ping method. * An interface for connections which support a "native" ping method.
*
* @deprecated
*/ */
interface PingableConnection interface PingableConnection
{ {
......
...@@ -71,6 +71,8 @@ class SQLAnywhereStatement implements IteratorAggregate, Statement, Result ...@@ -71,6 +71,8 @@ class SQLAnywhereStatement implements IteratorAggregate, Statement, Result
/** /**
* Prepares given statement for given connection. * Prepares given statement for given connection.
* *
* @internal The statement can be only instantiated by its driver connection.
*
* @param resource $conn The connection resource to use. * @param resource $conn The connection resource to use.
* @param string $sql The SQL statement to prepare. * @param string $sql The SQL statement to prepare.
* *
......
...@@ -136,6 +136,8 @@ class SQLSrvStatement implements IteratorAggregate, StatementInterface, Result ...@@ -136,6 +136,8 @@ class SQLSrvStatement implements IteratorAggregate, StatementInterface, Result
public const LAST_INSERT_ID_SQL = ';SELECT SCOPE_IDENTITY() AS LastInsertId;'; public const LAST_INSERT_ID_SQL = ';SELECT SCOPE_IDENTITY() AS LastInsertId;';
/** /**
* @internal The statement can be only instantiated by its driver connection.
*
* @param resource $conn * @param resource $conn
* @param string $sql * @param string $sql
*/ */
......
<?php
namespace Doctrine\DBAL\Exception;
/**
* @psalm-immutable
*/
final class ConnectionLost extends ConnectionException
{
}
...@@ -66,6 +66,8 @@ class Statement implements IteratorAggregate, DriverStatement, Result ...@@ -66,6 +66,8 @@ class Statement implements IteratorAggregate, DriverStatement, Result
/** /**
* Creates a new <tt>Statement</tt> for the given SQL and <tt>Connection</tt>. * Creates a new <tt>Statement</tt> for the given SQL and <tt>Connection</tt>.
* *
* @internal The statement can be only instantiated by {@link Connection}.
*
* @param string $sql The SQL of the statement. * @param string $sql The SQL of the statement.
* @param Connection $conn The connection on which the statement should be executed. * @param Connection $conn The connection on which the statement should be executed.
*/ */
...@@ -161,12 +163,7 @@ class Statement implements IteratorAggregate, DriverStatement, Result ...@@ -161,12 +163,7 @@ class Statement implements IteratorAggregate, DriverStatement, Result
$logger->stopQuery(); $logger->stopQuery();
} }
throw DBALException::driverExceptionDuringQuery( $this->conn->handleExceptionDuringQuery($ex, $this->sql, $this->params, $this->types);
$this->conn->getDriver(),
$ex,
$this->sql,
$this->conn->resolveParams($this->params, $this->types)
);
} }
if ($logger) { if ($logger) {
...@@ -297,7 +294,7 @@ class Statement implements IteratorAggregate, DriverStatement, Result ...@@ -297,7 +294,7 @@ class Statement implements IteratorAggregate, DriverStatement, Result
return $this->stmt->fetch(FetchMode::NUMERIC); return $this->stmt->fetch(FetchMode::NUMERIC);
} catch (Exception $e) { } catch (Exception $e) {
throw DBALException::driverException($this->conn->getDriver(), $e); $this->conn->handleDriverException($e);
} }
} }
...@@ -315,7 +312,7 @@ class Statement implements IteratorAggregate, DriverStatement, Result ...@@ -315,7 +312,7 @@ class Statement implements IteratorAggregate, DriverStatement, Result
return $this->stmt->fetch(FetchMode::ASSOCIATIVE); return $this->stmt->fetch(FetchMode::ASSOCIATIVE);
} catch (Exception $e) { } catch (Exception $e) {
throw DBALException::driverException($this->conn->getDriver(), $e); $this->conn->handleDriverException($e);
} }
} }
...@@ -333,7 +330,7 @@ class Statement implements IteratorAggregate, DriverStatement, Result ...@@ -333,7 +330,7 @@ class Statement implements IteratorAggregate, DriverStatement, Result
return $this->stmt->fetch(FetchMode::COLUMN); return $this->stmt->fetch(FetchMode::COLUMN);
} catch (Exception $e) { } catch (Exception $e) {
throw DBALException::driverException($this->conn->getDriver(), $e); $this->conn->handleDriverException($e);
} }
} }
...@@ -351,7 +348,7 @@ class Statement implements IteratorAggregate, DriverStatement, Result ...@@ -351,7 +348,7 @@ class Statement implements IteratorAggregate, DriverStatement, Result
return $this->stmt->fetchAll(FetchMode::NUMERIC); return $this->stmt->fetchAll(FetchMode::NUMERIC);
} catch (Exception $e) { } catch (Exception $e) {
throw DBALException::driverException($this->conn->getDriver(), $e); $this->conn->handleDriverException($e);
} }
} }
...@@ -369,7 +366,7 @@ class Statement implements IteratorAggregate, DriverStatement, Result ...@@ -369,7 +366,7 @@ class Statement implements IteratorAggregate, DriverStatement, Result
return $this->stmt->fetchAll(FetchMode::ASSOCIATIVE); return $this->stmt->fetchAll(FetchMode::ASSOCIATIVE);
} catch (Exception $e) { } catch (Exception $e) {
throw DBALException::driverException($this->conn->getDriver(), $e); $this->conn->handleDriverException($e);
} }
} }
...@@ -387,7 +384,7 @@ class Statement implements IteratorAggregate, DriverStatement, Result ...@@ -387,7 +384,7 @@ class Statement implements IteratorAggregate, DriverStatement, Result
return $this->stmt->fetchAll(FetchMode::COLUMN); return $this->stmt->fetchAll(FetchMode::COLUMN);
} catch (Exception $e) { } catch (Exception $e) {
throw DBALException::driverException($this->conn->getDriver(), $e); $this->conn->handleDriverException($e);
} }
} }
...@@ -411,7 +408,7 @@ class Statement implements IteratorAggregate, DriverStatement, Result ...@@ -411,7 +408,7 @@ class Statement implements IteratorAggregate, DriverStatement, Result
} }
} }
} catch (Exception $e) { } catch (Exception $e) {
throw DBALException::driverException($this->conn->getDriver(), $e); $this->conn->handleDriverException($e);
} }
} }
...@@ -435,7 +432,7 @@ class Statement implements IteratorAggregate, DriverStatement, Result ...@@ -435,7 +432,7 @@ class Statement implements IteratorAggregate, DriverStatement, Result
} }
} }
} catch (Exception $e) { } catch (Exception $e) {
throw DBALException::driverException($this->conn->getDriver(), $e); $this->conn->handleDriverException($e);
} }
} }
...@@ -459,7 +456,7 @@ class Statement implements IteratorAggregate, DriverStatement, Result ...@@ -459,7 +456,7 @@ class Statement implements IteratorAggregate, DriverStatement, Result
} }
} }
} catch (Exception $e) { } catch (Exception $e) {
throw DBALException::driverException($this->conn->getDriver(), $e); $this->conn->handleDriverException($e);
} }
} }
......
...@@ -7,6 +7,10 @@ parameters: ...@@ -7,6 +7,10 @@ parameters:
reportUnmatchedIgnoredErrors: false reportUnmatchedIgnoredErrors: false
checkMissingIterableValueType: false checkMissingIterableValueType: false
checkGenericClassInNonGenericObjectType: false checkGenericClassInNonGenericObjectType: false
earlyTerminatingMethodCalls:
Doctrine\DBAL\Connection:
- handleDriverException
- handleExceptionDuringQuery
ignoreErrors: ignoreErrors:
# extension not available # extension not available
- '~^(Used )?(Function|Constant) sasql_\S+ not found\.\z~i' - '~^(Used )?(Function|Constant) sasql_\S+ not found\.\z~i'
......
<?php
namespace Doctrine\Tests\DBAL\Functional;
use Doctrine\DBAL\Exception\ConnectionLost;
use Doctrine\DBAL\Platforms\MySqlPlatform;
use Doctrine\Tests\DbalFunctionalTestCase;
use function sleep;
class ConnectionLostTest extends DbalFunctionalTestCase
{
protected function setUp(): void
{
parent::setUp();
if ($this->connection->getDatabasePlatform() instanceof MySqlPlatform) {
return;
}
$this->markTestSkipped('Currently only supported with MySQL');
}
protected function tearDown(): void
{
$this->resetSharedConn();
parent::tearDown();
}
public function testConnectionLost(): void
{
$this->connection->query('SET SESSION wait_timeout=1');
sleep(2);
$query = $this->connection->getDatabasePlatform()
->getDummySelectSQL();
try {
// in addition to the error, PHP 7.3 will generate a warning that needs to be
// suppressed in order to not let PHPUnit handle it before the actual error
@$this->connection->executeQuery($query);
} catch (ConnectionLost $e) {
self::assertEquals(1, $this->connection->fetchOne($query));
return;
}
self::fail('The connection should have lost');
}
}
...@@ -131,10 +131,9 @@ class StatementTest extends DbalTestCase ...@@ -131,10 +131,9 @@ class StatementTest extends DbalTestCase
->method('getSQLLogger') ->method('getSQLLogger')
->will($this->returnValue($logger)); ->will($this->returnValue($logger));
// Needed to satisfy construction of DBALException
$this->conn->expects($this->any()) $this->conn->expects($this->any())
->method('resolveParams') ->method('handleExceptionDuringQuery')
->will($this->returnValue([])); ->will($this->throwException(new DBALException()));
$logger->expects($this->once()) $logger->expects($this->once())
->method('startQuery'); ->method('startQuery');
......
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