diff --git a/UPGRADE.md b/UPGRADE.md index 5082c7a67b2..b36f9270c69 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -378,6 +378,24 @@ Please use other database client applications for import, e.g.: * For PostgreSQL: `psql [dbname] < data.sql`. * For SQLite: `sqlite3 /path/to/file.db < data.sql`. +## BC BREAK: Changed signature of `ExceptionConverter::convert()` + +Before: + +```php +public function convert(string $message, Doctrine\DBAL\Driver\Exception $exception): DriverException +``` + +After: + +```php +public function convert(Doctrine\DBAL\Driver\Exception $exception, ?Doctrine\DBAL\Query $query): DriverException +``` + +## BC Break: The `DriverException` constructor is now internal + +The constructor of `Doctrine\DBAL\Exception\DriverException` is now `@internal`. + # Upgrade to 2.12 ## PDO signature changes with php 8 diff --git a/src/Connection.php b/src/Connection.php index 91a5ec65520..4d4e68a08d7 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -10,10 +10,10 @@ use Doctrine\DBAL\Cache\QueryCacheProfile; use Doctrine\DBAL\Driver\API\ExceptionConverter; use Doctrine\DBAL\Driver\Connection as DriverConnection; -use Doctrine\DBAL\Driver\Exception as DriverException; use Doctrine\DBAL\Driver\ServerInfoAwareConnection; use Doctrine\DBAL\Driver\Statement as DriverStatement; use Doctrine\DBAL\Exception\ConnectionLost; +use Doctrine\DBAL\Exception\DriverException; use Doctrine\DBAL\Exception\InvalidArgumentException; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Query\Expression\ExpressionBuilder; @@ -24,18 +24,12 @@ use Traversable; use function array_key_exists; -use function array_map; use function assert; -use function bin2hex; use function count; use function implode; use function is_int; -use function is_resource; use function is_string; -use function json_encode; use function key; -use function preg_replace; -use function sprintf; /** * A database abstraction-level connection that implements features like events, transaction isolation levels, @@ -291,7 +285,7 @@ public function connect() try { $this->_conn = $this->_driver->connect($this->params); - } catch (DriverException $e) { + } catch (Driver\Exception $e) { throw $this->convertException($e); } @@ -409,7 +403,7 @@ private function getServerVersion() if ($connection instanceof ServerInfoAwareConnection) { try { return $connection->getServerVersion(); - } catch (DriverException $e) { + } catch (Driver\Exception $e) { throw $this->convertException($e); } } @@ -481,7 +475,7 @@ public function fetchAssociative(string $query, array $params = [], array $types { try { return $this->executeQuery($query, $params, $types)->fetchAssociative(); - } catch (DriverException $e) { + } catch (Driver\Exception $e) { throw $this->convertExceptionDuringQuery($e, $query, $params, $types); } } @@ -502,7 +496,7 @@ public function fetchNumeric(string $query, array $params = [], array $types = [ { try { return $this->executeQuery($query, $params, $types)->fetchNumeric(); - } catch (DriverException $e) { + } catch (Driver\Exception $e) { throw $this->convertExceptionDuringQuery($e, $query, $params, $types); } } @@ -523,7 +517,7 @@ public function fetchOne(string $query, array $params = [], array $types = []) { try { return $this->executeQuery($query, $params, $types)->fetchOne(); - } catch (DriverException $e) { + } catch (Driver\Exception $e) { throw $this->convertExceptionDuringQuery($e, $query, $params, $types); } } @@ -791,7 +785,7 @@ public function fetchAllNumeric(string $query, array $params = [], array $types { try { return $this->executeQuery($query, $params, $types)->fetchAllNumeric(); - } catch (DriverException $e) { + } catch (Driver\Exception $e) { throw $this->convertExceptionDuringQuery($e, $query, $params, $types); } } @@ -811,7 +805,7 @@ public function fetchAllAssociative(string $query, array $params = [], array $ty { try { return $this->executeQuery($query, $params, $types)->fetchAllAssociative(); - } catch (DriverException $e) { + } catch (Driver\Exception $e) { throw $this->convertExceptionDuringQuery($e, $query, $params, $types); } } @@ -866,7 +860,7 @@ public function fetchFirstColumn(string $query, array $params = [], array $types { try { return $this->executeQuery($query, $params, $types)->fetchFirstColumn(); - } catch (DriverException $e) { + } catch (Driver\Exception $e) { throw $this->convertExceptionDuringQuery($e, $query, $params, $types); } } @@ -890,7 +884,7 @@ public function iterateNumeric(string $query, array $params = [], array $types = while (($row = $result->fetchNumeric()) !== false) { yield $row; } - } catch (DriverException $e) { + } catch (Driver\Exception $e) { throw $this->convertExceptionDuringQuery($e, $query, $params, $types); } } @@ -915,7 +909,7 @@ public function iterateAssociative(string $query, array $params = [], array $typ while (($row = $result->fetchAssociative()) !== false) { yield $row; } - } catch (DriverException $e) { + } catch (Driver\Exception $e) { throw $this->convertExceptionDuringQuery($e, $query, $params, $types); } } @@ -974,7 +968,7 @@ public function iterateColumn(string $query, array $params = [], array $types = while (($value = $result->fetchOne()) !== false) { yield $value; } - } catch (DriverException $e) { + } catch (Driver\Exception $e) { throw $this->convertExceptionDuringQuery($e, $query, $params, $types); } } @@ -1036,7 +1030,7 @@ public function executeQuery( } return new Result($result, $this); - } catch (DriverException $e) { + } catch (Driver\Exception $e) { throw $this->convertExceptionDuringQuery($e, $sql, $params, $types); } finally { if ($logger !== null) { @@ -1140,7 +1134,7 @@ public function executeStatement($sql, array $params = [], array $types = []) } return $connection->exec($sql); - } catch (DriverException $e) { + } catch (Driver\Exception $e) { throw $this->convertExceptionDuringQuery($e, $sql, $params, $types); } finally { if ($logger !== null) { @@ -1177,7 +1171,7 @@ public function lastInsertId($name = null) { try { return $this->getWrappedConnection()->lastInsertId($name); - } catch (DriverException $e) { + } catch (Driver\Exception $e) { throw $this->convertException($e); } } @@ -1642,51 +1636,6 @@ private function getBindingInfo($value, $type) return [$value, $bindingType]; } - /** - * Resolves the parameters to a format which can be displayed. - * - * @param array|array $params Query parameters - * @param array|array $types Parameter types - * - * @return array|array - */ - private function resolveParams(array $params, array $types): array - { - $resolvedParams = []; - - // Check whether parameters are positional or named. Mixing is not allowed. - if (is_int(key($params))) { - // Positional parameters - $typeOffset = array_key_exists(0, $types) ? -1 : 0; - $bindIndex = 1; - foreach ($params as $value) { - $typeIndex = $bindIndex + $typeOffset; - if (isset($types[$typeIndex])) { - $type = $types[$typeIndex]; - [$value] = $this->getBindingInfo($value, $type); - $resolvedParams[$bindIndex] = $value; - } else { - $resolvedParams[$bindIndex] = $value; - } - - ++$bindIndex; - } - } else { - // Named parameters - foreach ($params as $name => $value) { - if (isset($types[$name])) { - $type = $types[$name]; - [$value] = $this->getBindingInfo($value, $type); - $resolvedParams[$name] = $value; - } else { - $resolvedParams[$name] = $value; - } - } - } - - return $resolvedParams; - } - /** * Creates a new instance of a SQL query builder. * @@ -1704,66 +1653,31 @@ public function createQueryBuilder() * @param array|array $types */ final public function convertExceptionDuringQuery( - DriverException $e, + Driver\Exception $e, string $sql, array $params = [], array $types = [] - ): Exception { - $message = "An exception occurred while executing '" . $sql . "'"; - - if (count($params) > 0) { - $message .= ' with params ' . $this->formatParameters( - $this->resolveParams($params, $types) - ); - } - - $message .= ":\n\n" . $e->getMessage(); - - return $this->handleDriverException($e, $message); + ): DriverException { + return $this->handleDriverException($e, new Query($sql, $params, $types)); } /** * @internal */ - final public function convertException(DriverException $e): Exception + final public function convertException(Driver\Exception $e): DriverException { - return $this->handleDriverException( - $e, - 'An exception occurred in driver: ' . $e->getMessage() - ); + return $this->handleDriverException($e, null); } - /** - * Returns a human-readable representation of an array of parameters. - * This properly handles binary data by returning a hex representation. - * - * @param mixed[] $params - */ - private function formatParameters(array $params): string - { - return '[' . implode(', ', array_map(static function ($param): string { - if (is_resource($param)) { - return (string) $param; - } - - $json = @json_encode($param); - - if (! is_string($json) || $json === 'null' && is_string($param)) { - // JSON encoding failed, this is not a UTF-8 string. - return sprintf('"%s"', preg_replace('/.{2}/', '\\x$0', bin2hex($param))); - } - - return $json; - }, $params)) . ']'; - } - - private function handleDriverException(DriverException $driverException, string $message): Exception - { + private function handleDriverException( + Driver\Exception $driverException, + ?Query $query + ): DriverException { if ($this->exceptionConverter === null) { $this->exceptionConverter = $this->_driver->getExceptionConverter(); } - $exception = $this->exceptionConverter->convert($message, $driverException); + $exception = $this->exceptionConverter->convert($driverException, $query); if ($exception instanceof ConnectionLost) { $this->close(); diff --git a/src/Driver/API/ExceptionConverter.php b/src/Driver/API/ExceptionConverter.php index 8078abbd692..b848b0e282c 100644 --- a/src/Driver/API/ExceptionConverter.php +++ b/src/Driver/API/ExceptionConverter.php @@ -6,6 +6,7 @@ use Doctrine\DBAL\Driver\Exception; use Doctrine\DBAL\Exception\DriverException; +use Doctrine\DBAL\Query; interface ExceptionConverter { @@ -15,10 +16,10 @@ interface ExceptionConverter * Implementors should use the vendor-specific error code and SQLSTATE of the exception * and instantiate the most appropriate specialized {@link DriverException} subclass. * - * @param string $message The exception message to use. - * @param Exception $exception The driver exception to convert. + * @param Exception $exception The driver exception to convert. + * @param Query|null $query The SQL query that triggered the exception, if any. * * @return DriverException An instance of {@link DriverException} or one of its subclasses. */ - public function convert(string $message, Exception $exception): DriverException; + public function convert(Exception $exception, ?Query $query): DriverException; } diff --git a/src/Driver/API/IBMDB2/ExceptionConverter.php b/src/Driver/API/IBMDB2/ExceptionConverter.php index 2f7035326e4..20831e0fd7a 100644 --- a/src/Driver/API/IBMDB2/ExceptionConverter.php +++ b/src/Driver/API/IBMDB2/ExceptionConverter.php @@ -7,11 +7,15 @@ use Doctrine\DBAL\Driver\API\ExceptionConverter as ExceptionConverterInterface; use Doctrine\DBAL\Driver\Exception; use Doctrine\DBAL\Exception\DriverException; +use Doctrine\DBAL\Query; +/** + * @internal + */ final class ExceptionConverter implements ExceptionConverterInterface { - public function convert(string $message, Exception $exception): DriverException + public function convert(Exception $exception, ?Query $query): DriverException { - return new DriverException($message, $exception); + return new DriverException($exception, $query); } } diff --git a/src/Driver/API/MySQL/ExceptionConverter.php b/src/Driver/API/MySQL/ExceptionConverter.php index 149f8697a22..04f58516e24 100644 --- a/src/Driver/API/MySQL/ExceptionConverter.php +++ b/src/Driver/API/MySQL/ExceptionConverter.php @@ -19,51 +19,55 @@ use Doctrine\DBAL\Exception\TableExistsException; use Doctrine\DBAL\Exception\TableNotFoundException; use Doctrine\DBAL\Exception\UniqueConstraintViolationException; +use Doctrine\DBAL\Query; +/** + * @internal + */ final class ExceptionConverter implements ExceptionConverterInterface { /** * @link https://dev.mysql.com/doc/refman/8.0/en/client-error-reference.html * @link https://dev.mysql.com/doc/refman/8.0/en/server-error-reference.html */ - public function convert(string $message, Exception $exception): DriverException + public function convert(Exception $exception, ?Query $query): DriverException { switch ($exception->getCode()) { case 1213: - return new DeadlockException($message, $exception); + return new DeadlockException($exception, $query); case 1205: - return new LockWaitTimeoutException($message, $exception); + return new LockWaitTimeoutException($exception, $query); case 1050: - return new TableExistsException($message, $exception); + return new TableExistsException($exception, $query); case 1051: case 1146: - return new TableNotFoundException($message, $exception); + return new TableNotFoundException($exception, $query); case 1216: case 1217: case 1451: case 1452: case 1701: - return new ForeignKeyConstraintViolationException($message, $exception); + return new ForeignKeyConstraintViolationException($exception, $query); case 1062: case 1557: case 1569: case 1586: - return new UniqueConstraintViolationException($message, $exception); + return new UniqueConstraintViolationException($exception, $query); case 1054: case 1166: case 1611: - return new InvalidFieldNameException($message, $exception); + return new InvalidFieldNameException($exception, $query); case 1052: case 1060: case 1110: - return new NonUniqueFieldNameException($message, $exception); + return new NonUniqueFieldNameException($exception, $query); case 1064: case 1149: @@ -77,7 +81,7 @@ public function convert(string $message, Exception $exception): DriverException case 1541: case 1554: case 1626: - return new SyntaxErrorException($message, $exception); + return new SyntaxErrorException($exception, $query); case 1044: case 1045: @@ -91,10 +95,10 @@ public function convert(string $message, Exception $exception): DriverException case 1429: case 2002: case 2005: - return new ConnectionException($message, $exception); + return new ConnectionException($exception, $query); case 2006: - return new ConnectionLost($message, $exception); + return new ConnectionLost($exception, $query); case 1048: case 1121: @@ -104,9 +108,9 @@ public function convert(string $message, Exception $exception): DriverException case 1263: case 1364: case 1566: - return new NotNullConstraintViolationException($message, $exception); + return new NotNullConstraintViolationException($exception, $query); } - return new DriverException($message, $exception); + return new DriverException($exception, $query); } } diff --git a/src/Driver/API/OCI/ExceptionConverter.php b/src/Driver/API/OCI/ExceptionConverter.php index e98be404d35..f25e58d6c7c 100644 --- a/src/Driver/API/OCI/ExceptionConverter.php +++ b/src/Driver/API/OCI/ExceptionConverter.php @@ -16,49 +16,53 @@ use Doctrine\DBAL\Exception\TableExistsException; use Doctrine\DBAL\Exception\TableNotFoundException; use Doctrine\DBAL\Exception\UniqueConstraintViolationException; +use Doctrine\DBAL\Query; +/** + * @internal + */ final class ExceptionConverter implements ExceptionConverterInterface { /** * @link http://www.dba-oracle.com/t_error_code_list.htm */ - public function convert(string $message, Exception $exception): DriverException + public function convert(Exception $exception, ?Query $query): DriverException { switch ($exception->getCode()) { case 1: case 2299: case 38911: - return new UniqueConstraintViolationException($message, $exception); + return new UniqueConstraintViolationException($exception, $query); case 904: - return new InvalidFieldNameException($message, $exception); + return new InvalidFieldNameException($exception, $query); case 918: case 960: - return new NonUniqueFieldNameException($message, $exception); + return new NonUniqueFieldNameException($exception, $query); case 923: - return new SyntaxErrorException($message, $exception); + return new SyntaxErrorException($exception, $query); case 942: - return new TableNotFoundException($message, $exception); + return new TableNotFoundException($exception, $query); case 955: - return new TableExistsException($message, $exception); + return new TableExistsException($exception, $query); case 1017: case 12545: - return new ConnectionException($message, $exception); + return new ConnectionException($exception, $query); case 1400: - return new NotNullConstraintViolationException($message, $exception); + return new NotNullConstraintViolationException($exception, $query); case 2266: case 2291: case 2292: - return new ForeignKeyConstraintViolationException($message, $exception); + return new ForeignKeyConstraintViolationException($exception, $query); } - return new DriverException($message, $exception); + return new DriverException($exception, $query); } } diff --git a/src/Driver/API/PostgreSQL/ExceptionConverter.php b/src/Driver/API/PostgreSQL/ExceptionConverter.php index 532cc51d99e..b9530d0b299 100644 --- a/src/Driver/API/PostgreSQL/ExceptionConverter.php +++ b/src/Driver/API/PostgreSQL/ExceptionConverter.php @@ -17,65 +17,69 @@ use Doctrine\DBAL\Exception\TableExistsException; use Doctrine\DBAL\Exception\TableNotFoundException; use Doctrine\DBAL\Exception\UniqueConstraintViolationException; +use Doctrine\DBAL\Query; use function strpos; +/** + * @internal + */ final class ExceptionConverter implements ExceptionConverterInterface { /** * @link http://www.postgresql.org/docs/9.4/static/errcodes-appendix.html */ - public function convert(string $message, Exception $exception): DriverException + public function convert(Exception $exception, ?Query $query): DriverException { switch ($exception->getSQLState()) { case '40001': case '40P01': - return new DeadlockException($message, $exception); + return new DeadlockException($exception, $query); case '0A000': // Foreign key constraint violations during a TRUNCATE operation // are considered "feature not supported" in PostgreSQL. if (strpos($exception->getMessage(), 'truncate') !== false) { - return new ForeignKeyConstraintViolationException($message, $exception); + return new ForeignKeyConstraintViolationException($exception, $query); } break; case '23502': - return new NotNullConstraintViolationException($message, $exception); + return new NotNullConstraintViolationException($exception, $query); case '23503': - return new ForeignKeyConstraintViolationException($message, $exception); + return new ForeignKeyConstraintViolationException($exception, $query); case '23505': - return new UniqueConstraintViolationException($message, $exception); + return new UniqueConstraintViolationException($exception, $query); case '42601': - return new SyntaxErrorException($message, $exception); + return new SyntaxErrorException($exception, $query); case '42702': - return new NonUniqueFieldNameException($message, $exception); + return new NonUniqueFieldNameException($exception, $query); case '42703': - return new InvalidFieldNameException($message, $exception); + return new InvalidFieldNameException($exception, $query); case '42P01': - return new TableNotFoundException($message, $exception); + return new TableNotFoundException($exception, $query); case '42P07': - return new TableExistsException($message, $exception); + return new TableExistsException($exception, $query); case '08006': - return new ConnectionException($message, $exception); + return new ConnectionException($exception, $query); } // Prior to fixing https://bugs.php.net/bug.php?id=64705 (PHP 7.3.22 and PHP 7.4.10), // in some cases (mainly connection errors) the PDO exception wouldn't provide a SQLSTATE via its code. // We have to match against the SQLSTATE in the error message in these cases. if ($exception->getCode() === 7 && strpos($exception->getMessage(), 'SQLSTATE[08006]') !== false) { - return new ConnectionException($message, $exception); + return new ConnectionException($exception, $query); } - return new DriverException($message, $exception); + return new DriverException($exception, $query); } } diff --git a/src/Driver/API/SQLSrv/ExceptionConverter.php b/src/Driver/API/SQLSrv/ExceptionConverter.php index 37b1c7cbcec..3fc3ff081f7 100644 --- a/src/Driver/API/SQLSrv/ExceptionConverter.php +++ b/src/Driver/API/SQLSrv/ExceptionConverter.php @@ -7,11 +7,15 @@ use Doctrine\DBAL\Driver\API\ExceptionConverter as ExceptionConverterInterface; use Doctrine\DBAL\Driver\Exception; use Doctrine\DBAL\Exception\DriverException; +use Doctrine\DBAL\Query; +/** + * @internal + */ final class ExceptionConverter implements ExceptionConverterInterface { - public function convert(string $message, Exception $exception): DriverException + public function convert(Exception $exception, ?Query $query): DriverException { - return new DriverException($message, $exception); + return new DriverException($exception, $query); } } diff --git a/src/Driver/API/SQLite/ExceptionConverter.php b/src/Driver/API/SQLite/ExceptionConverter.php index 42bba99f4e1..d78b0832aef 100644 --- a/src/Driver/API/SQLite/ExceptionConverter.php +++ b/src/Driver/API/SQLite/ExceptionConverter.php @@ -17,18 +17,22 @@ use Doctrine\DBAL\Exception\TableExistsException; use Doctrine\DBAL\Exception\TableNotFoundException; use Doctrine\DBAL\Exception\UniqueConstraintViolationException; +use Doctrine\DBAL\Query; use function strpos; +/** + * @internal + */ final class ExceptionConverter implements ExceptionConverterInterface { /** * @link http://www.sqlite.org/c3ref/c_abort.html */ - public function convert(string $message, Exception $exception): DriverException + public function convert(Exception $exception, ?Query $query): DriverException { if (strpos($exception->getMessage(), 'database is locked') !== false) { - return new LockWaitTimeoutException($message, $exception); + return new LockWaitTimeoutException($exception, $query); } if ( @@ -37,44 +41,44 @@ public function convert(string $message, Exception $exception): DriverException strpos($exception->getMessage(), 'are not unique') !== false || strpos($exception->getMessage(), 'UNIQUE constraint failed') !== false ) { - return new UniqueConstraintViolationException($message, $exception); + return new UniqueConstraintViolationException($exception, $query); } if ( strpos($exception->getMessage(), 'may not be NULL') !== false || strpos($exception->getMessage(), 'NOT NULL constraint failed') !== false ) { - return new NotNullConstraintViolationException($message, $exception); + return new NotNullConstraintViolationException($exception, $query); } if (strpos($exception->getMessage(), 'no such table:') !== false) { - return new TableNotFoundException($message, $exception); + return new TableNotFoundException($exception, $query); } if (strpos($exception->getMessage(), 'already exists') !== false) { - return new TableExistsException($message, $exception); + return new TableExistsException($exception, $query); } if (strpos($exception->getMessage(), 'has no column named') !== false) { - return new InvalidFieldNameException($message, $exception); + return new InvalidFieldNameException($exception, $query); } if (strpos($exception->getMessage(), 'ambiguous column name') !== false) { - return new NonUniqueFieldNameException($message, $exception); + return new NonUniqueFieldNameException($exception, $query); } if (strpos($exception->getMessage(), 'syntax error') !== false) { - return new SyntaxErrorException($message, $exception); + return new SyntaxErrorException($exception, $query); } if (strpos($exception->getMessage(), 'attempt to write a readonly database') !== false) { - return new ReadOnlyException($message, $exception); + return new ReadOnlyException($exception, $query); } if (strpos($exception->getMessage(), 'unable to open database file') !== false) { - return new ConnectionException($message, $exception); + return new ConnectionException($exception, $query); } - return new DriverException($message, $exception); + return new DriverException($exception, $query); } } diff --git a/src/Exception/DriverException.php b/src/Exception/DriverException.php index 9aedbf436af..10d6019a57d 100644 --- a/src/Exception/DriverException.php +++ b/src/Exception/DriverException.php @@ -4,6 +4,7 @@ use Doctrine\DBAL\Driver\Exception as TheDriverException; use Doctrine\DBAL\Exception; +use Doctrine\DBAL\Query; use function assert; @@ -15,12 +16,29 @@ class DriverException extends Exception implements TheDriverException { /** - * @param string $message The exception message. + * The query that triggered the exception, if any. + * + * @var Query|null + */ + private $query; + + /** + * @internal + * * @param TheDriverException $driverException The DBAL driver exception to chain. + * @param Query|null $query The SQL query that triggered the exception, if any. */ - public function __construct($message, TheDriverException $driverException) + public function __construct(TheDriverException $driverException, ?Query $query) { + if ($query !== null) { + $message = 'An exception occurred while executing a query: ' . $driverException->getMessage(); + } else { + $message = 'An exception occurred in the driver: ' . $driverException->getMessage(); + } + parent::__construct($message, $driverException->getCode(), $driverException); + + $this->query = $query; } /** @@ -33,4 +51,9 @@ public function getSQLState() return $previous->getSQLState(); } + + public function getQuery(): ?Query + { + return $this->query; + } } diff --git a/src/Query.php b/src/Query.php new file mode 100644 index 00000000000..ea6024cd810 --- /dev/null +++ b/src/Query.php @@ -0,0 +1,70 @@ + + */ + private $params; + + /** + * The types of the parameters bound to the query. + * + * @var array + */ + private $types; + + /** + * @param array $params + * @param array $types + * + * @psalm-suppress ImpurePropertyAssignment + */ + public function __construct(string $sql, array $params, array $types) + { + $this->sql = $sql; + $this->params = $params; + $this->types = $types; + } + + public function getSQL(): string + { + return $this->sql; + } + + /** + * @return array + */ + public function getParams(): array + { + return $this->params; + } + + /** + * @return array + */ + public function getTypes(): array + { + return $this->types; + } +} diff --git a/tests/Connection/ExceptionHandlingTest.php b/tests/Connection/ExceptionHandlingTest.php deleted file mode 100644 index 9b164630838..00000000000 --- a/tests/Connection/ExceptionHandlingTest.php +++ /dev/null @@ -1,59 +0,0 @@ -exceptionConverter = $this->createMock(ExceptionConverter::class); - - $this->connection = new Connection([], $this->createConfiguredMock(Driver::class, [ - 'getExceptionConverter' => $this->exceptionConverter, - ])); - } - - public function testDriverExceptionDuringQueryAcceptsBinaryData(): void - { - $this->exceptionConverter->expects(self::once()) - ->method('convert') - ->with(self::stringContains('with params ["ABC", "\x80"]')); - - $this->connection->convertExceptionDuringQuery( - $this->createMock(DriverException::class), - '', - ['ABC', chr(128)] - ); - } - - public function testDriverExceptionDuringQueryAcceptsResource(): void - { - $this->exceptionConverter->expects(self::once()) - ->method('convert') - ->with(self::stringContains('Resource')); - - $this->connection->convertExceptionDuringQuery( - $this->createMock(DriverException::class), - 'INSERT INTO file (`content`) VALUES (?)', - [ - 1 => fopen(__FILE__, 'r'), - ] - ); - } -} diff --git a/tests/ConnectionTest.php b/tests/ConnectionTest.php index 905ad303bbe..8e05c8eecde 100644 --- a/tests/ConnectionTest.php +++ b/tests/ConnectionTest.php @@ -159,11 +159,8 @@ public function testEventManagerPassedToPlatform(): void public function testDriverExceptionIsWrapped(callable $callback): void { $this->expectException(Exception::class); - $this->expectExceptionMessage(<<expectExceptionMessage( + 'An exception occurred while executing a query: SQLSTATE[HY000]: General error: 1 near "MUUHAAAAHAAAA"' ); $connection = DriverManager::getConnection([ diff --git a/tests/Driver/API/ExceptionConverterTest.php b/tests/Driver/API/ExceptionConverterTest.php index 24e748bb385..14cbca728ea 100644 --- a/tests/Driver/API/ExceptionConverterTest.php +++ b/tests/Driver/API/ExceptionConverterTest.php @@ -7,6 +7,7 @@ use Doctrine\DBAL\Driver\AbstractException; use Doctrine\DBAL\Driver\API\ExceptionConverter; use Doctrine\DBAL\Exception\DriverException; +use Doctrine\DBAL\Query; use PHPUnit\Framework\TestCase; use function array_merge; @@ -34,20 +35,27 @@ public function testConvertsException( string $expectedClass, int $errorCode, ?string $sqlState = null, - string $message = '' + string $message = '', + ?Query $query = null ): void { $driverException = $this->getMockForAbstractClass( AbstractException::class, [$message, $sqlState, $errorCode] ); - $dbalMessage = 'DBAL exception message'; - $dbalException = $this->converter->convert($dbalMessage, $driverException); + if ($query !== null) { + $expectedMessage = 'An exception occurred while executing a query: ' . $message; + } else { + $expectedMessage = 'An exception occurred in the driver: ' . $message; + } + + $dbalException = $this->converter->convert($driverException, $query); self::assertSame($driverException->getCode(), $dbalException->getCode()); self::assertSame($driverException->getSQLState(), $dbalException->getSQLState()); self::assertSame($driverException, $dbalException->getPrevious()); - self::assertSame($dbalMessage, $dbalException->getMessage()); + self::assertSame($expectedMessage, $dbalException->getMessage()); + self::assertSame($query, $dbalException->getQuery()); } /** @@ -62,6 +70,7 @@ public static function exceptionConversionProvider(): iterable } yield [DriverException::class, 1, 'HY000', 'The message']; + yield [DriverException::class, 1, 'HY000', 'The message', new Query('SELECT x', [], [])]; } /** diff --git a/tests/Functional/ExceptionTest.php b/tests/Functional/ExceptionTest.php index 95cde9ca317..b6cefa25167 100644 --- a/tests/Functional/ExceptionTest.php +++ b/tests/Functional/ExceptionTest.php @@ -336,11 +336,8 @@ public function testConnectionExceptionSqLite(): void $this->expectException(Exception\ReadOnlyException::class); $this->expectExceptionMessage( - <<