Skip to content

Commit

Permalink
exceptions are converted in PdoDriver
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed Jan 20, 2022
1 parent 9bb6ec8 commit a25a912
Show file tree
Hide file tree
Showing 14 changed files with 72 additions and 76 deletions.
5 changes: 0 additions & 5 deletions src/Database/Driver.php
Expand Up @@ -29,11 +29,6 @@ interface Driver
*/
function connect(string $dsn, ?string $user = null, ?string $password = null, ?array $options = null): void;

/**
* Converts PDOException to DriverException or its descendant.
*/
function convertException(\PDOException $e): DriverException;

function query(string $queryString, array $params): ResultDriver;

function beginTransaction(): void;
Expand Down
35 changes: 18 additions & 17 deletions src/Database/DriverException.php
Expand Up @@ -13,41 +13,42 @@
/**
* Base class for all errors in the driver or SQL server.
*/
class DriverException extends \PDOException
class DriverException extends \Exception
{
public ?string $queryString = null;

public ?array $params = null;
private int|string|null $driverCode = null;
private string|null $sqlState = null;


public static function from(\PDOException $src): static
public function __construct(string $message = '', $code = 0, ?\Throwable $previous = null)
{
$e = new static($src->message, 0, $src);
$e->file = $src->file;
$e->line = $src->line;
if (!$src->errorInfo && preg_match('#SQLSTATE\[(.*?)\] \[(.*?)\] (.*)#A', $src->message, $m)) {
$m[2] = (int) $m[2];
$e->errorInfo = array_slice($m, 1);
$e->code = $m[1];
} else {
$e->errorInfo = $src->errorInfo;
$e->code = $src->code;
$e->code = $e->errorInfo[0] ?? $src->code;
parent::__construct($message, 0, $previous);
$this->code = $code;
if ($previous) {
$this->file = $previous->file;
$this->line = $previous->line;
}
}

return $e;

/** @internal */
public function setDriverCode(string $state, int|string $code): void
{
$this->sqlState = $state;
$this->driverCode = $code;
}


public function getDriverCode(): int|string|null
{
return $this->errorInfo[1] ?? null;
return $this->driverCode;
}


public function getSqlState(): ?string
{
return $this->errorInfo[0] ?? null;
return $this->sqlState;
}


Expand Down
9 changes: 0 additions & 9 deletions src/Database/Drivers/MsSqlDriver.php
Expand Up @@ -17,15 +17,6 @@
*/
class MsSqlDriver extends PdoDriver
{
public function convertException(\PDOException $e): Nette\Database\DriverException
{
return Nette\Database\DriverException::from($e);
}


/********************* SQL ****************d*g**/


public function delimite(string $name): string
{
// @see https://msdn.microsoft.com/en-us/library/ms176027.aspx
Expand Down
12 changes: 6 additions & 6 deletions src/Database/Drivers/MySqlDriver.php
Expand Up @@ -43,23 +43,23 @@ public function connect(string $dsn, ?string $user = null, ?string $password = n
}


public function convertException(\PDOException $e): Nette\Database\DriverException
public function detectExceptionClass(\PDOException $e): ?string
{
$code = $e->errorInfo[1] ?? null;
if (in_array($code, [1216, 1217, 1451, 1452, 1701], true)) {
return Nette\Database\ForeignKeyConstraintViolationException::from($e);
return Nette\Database\ForeignKeyConstraintViolationException::class;

} elseif (in_array($code, [1062, 1557, 1569, 1586], true)) {
return Nette\Database\UniqueConstraintViolationException::from($e);
return Nette\Database\UniqueConstraintViolationException::class;

} elseif ($code >= 2001 && $code <= 2028) {
return Nette\Database\ConnectionException::from($e);
return Nette\Database\ConnectionException::class;

} elseif (in_array($code, [1048, 1121, 1138, 1171, 1252, 1263, 1566], true)) {
return Nette\Database\NotNullConstraintViolationException::from($e);
return Nette\Database\NotNullConstraintViolationException::class;

} else {
return Nette\Database\DriverException::from($e);
return null;
}
}

Expand Down
10 changes: 5 additions & 5 deletions src/Database/Drivers/OciDriver.php
Expand Up @@ -28,20 +28,20 @@ public function connect(string $dsn, ?string $user = null, ?string $password = n
}


public function convertException(\PDOException $e): Nette\Database\DriverException
public function detectExceptionClass(\PDOException $e): ?string
{
$code = $e->errorInfo[1] ?? null;
if (in_array($code, [1, 2299, 38911], true)) {
return Nette\Database\UniqueConstraintViolationException::from($e);
return Nette\Database\UniqueConstraintViolationException::class;

} elseif (in_array($code, [1400], true)) {
return Nette\Database\NotNullConstraintViolationException::from($e);
return Nette\Database\NotNullConstraintViolationException::class;

} elseif (in_array($code, [2266, 2291, 2292], true)) {
return Nette\Database\ForeignKeyConstraintViolationException::from($e);
return Nette\Database\ForeignKeyConstraintViolationException::class;

} else {
return Nette\Database\DriverException::from($e);
return null;
}
}

Expand Down
9 changes: 0 additions & 9 deletions src/Database/Drivers/OdbcDriver.php
Expand Up @@ -17,15 +17,6 @@
*/
class OdbcDriver extends PdoDriver
{
public function convertException(\PDOException $e): Nette\Database\DriverException
{
return Nette\Database\DriverException::from($e);
}


/********************* SQL ****************d*g**/


public function delimite(string $name): string
{
return '[' . str_replace(['[', ']'], ['[[', ']]'], $name) . ']';
Expand Down
28 changes: 26 additions & 2 deletions src/Database/Drivers/PdoDriver.php
Expand Up @@ -31,7 +31,7 @@ public function connect(string $dsn, ?string $user = null, ?string $password = n
$this->pdo = new PDO($dsn, $user, $password, $options);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
throw Nette\Database\ConnectionException::from($e);
throw $this->convertException($e, Nette\Database\ConnectionException::class);
}
}

Expand Down Expand Up @@ -113,7 +113,31 @@ public function quote(string $string, int $type = PDO::PARAM_STR): string
try {
return $this->pdo->quote($string, $type);
} catch (PDOException $e) {
throw DriverException::from($e);
throw $this->convertException($e);
}
}


public function convertException(\PDOException $src, ?string $class = null): DriverException
{
if ($src->errorInfo) {
[$sqlState, $driverCode] = $src->errorInfo;
} elseif (preg_match('#SQLSTATE\[(.*?)\] \[(.*?)\] (.*)#A', $src->getMessage(), $m)) {
[, $sqlState, $driverCode] = $m;
}

$class = $this->detectExceptionClass($src) ?? $class ?? DriverException::class;
$e = new $class($src->getMessage(), $sqlState ?? $src->getCode(), $src);
if (isset($sqlState)) {
$e->setDriverCode($sqlState, (int) $driverCode);
}

return $e;
}


public function detectExceptionClass(\PDOException $e): ?string
{
return null;
}
}
14 changes: 7 additions & 7 deletions src/Database/Drivers/PgSqlDriver.php
Expand Up @@ -17,26 +17,26 @@
*/
class PgSqlDriver extends PdoDriver
{
public function convertException(\PDOException $e): Nette\Database\DriverException
public function detectExceptionClass(\PDOException $e): ?string
{
$code = $e->errorInfo[0] ?? null;
if ($code === '0A000' && str_contains($e->getMessage(), 'truncate')) {
return Nette\Database\ForeignKeyConstraintViolationException::from($e);
return Nette\Database\ForeignKeyConstraintViolationException::class;

} elseif ($code === '23502') {
return Nette\Database\NotNullConstraintViolationException::from($e);
return Nette\Database\NotNullConstraintViolationException::class;

} elseif ($code === '23503') {
return Nette\Database\ForeignKeyConstraintViolationException::from($e);
return Nette\Database\ForeignKeyConstraintViolationException::class;

} elseif ($code === '23505') {
return Nette\Database\UniqueConstraintViolationException::from($e);
return Nette\Database\UniqueConstraintViolationException::class;

} elseif ($code === '08006') {
return Nette\Database\ConnectionException::from($e);
return Nette\Database\ConnectionException::class;

} else {
return Nette\Database\DriverException::from($e);
return null;
}
}

Expand Down
12 changes: 6 additions & 6 deletions src/Database/Drivers/SqliteDriver.php
Expand Up @@ -28,34 +28,34 @@ public function connect(string $dsn, ?string $user = null, ?string $password = n
}


public function convertException(\PDOException $e): Nette\Database\DriverException
public function detectExceptionClass(\PDOException $e): ?string
{
$code = $e->errorInfo[1] ?? null;
$msg = $e->getMessage();
if ($code !== 19) {
return Nette\Database\DriverException::from($e);
return null;

} elseif (
str_contains($msg, 'must be unique')
|| str_contains($msg, 'is not unique')
|| str_contains($msg, 'UNIQUE constraint failed')
) {
return Nette\Database\UniqueConstraintViolationException::from($e);
return Nette\Database\UniqueConstraintViolationException::class;

} elseif (
str_contains($msg, 'may not be null')
|| str_contains($msg, 'NOT NULL constraint failed')
) {
return Nette\Database\NotNullConstraintViolationException::from($e);
return Nette\Database\NotNullConstraintViolationException::class;

} elseif (
str_contains($msg, 'foreign key constraint failed')
|| str_contains($msg, 'FOREIGN KEY constraint failed')
) {
return Nette\Database\ForeignKeyConstraintViolationException::from($e);
return Nette\Database\ForeignKeyConstraintViolationException::class;

} else {
return Nette\Database\ConstraintViolationException::from($e);
return Nette\Database\ConstraintViolationException::class;
}
}

Expand Down
6 changes: 0 additions & 6 deletions src/Database/Drivers/SqlsrvDriver.php
Expand Up @@ -27,12 +27,6 @@ public function connect(string $dsn, ?string $user = null, ?string $password = n
}


public function convertException(\PDOException $e): Nette\Database\DriverException
{
return Nette\Database\DriverException::from($e);
}


/********************* SQL ****************d*g**/


Expand Down
2 changes: 1 addition & 1 deletion tests/Database/Connection.lazy.phpt
Expand Up @@ -44,7 +44,7 @@ test('connect & disconnect', function () {

try {
$connection = new Nette\Database\Connection($options['dsn'], $options['user'], $options['password']);
} catch (PDOException $e) {
} catch (Nette\Database\ConnectionException $e) {
Tester\Environment::skip("Connection to '$options[dsn]' failed. Reason: " . $e->getMessage());
}

Expand Down
2 changes: 1 addition & 1 deletion tests/Database/Explorer/Selection.insert().phpt
Expand Up @@ -47,7 +47,7 @@ if ($driverName !== 'sqlsrv') {
'name' => 'Jon Snow',
'web' => 'http://example.com',
]);
}, PDOException::class);
}, Nette\Database\DriverException::class);
}


Expand Down
2 changes: 1 addition & 1 deletion tests/Database/Explorer/bugs/bug216.phpt
Expand Up @@ -16,7 +16,7 @@ $options = Tester\Environment::loadData() + ['user' => null, 'password' => null]

try {
$connection = new Nette\Database\Connection($options['dsn'], $options['user'], $options['password']);
} catch (PDOException $e) {
} catch (Nette\Database\ConnectionException $e) {
Tester\Environment::skip("Connection to '$options[dsn]' failed. Reason: " . $e->getMessage());
}

Expand Down
2 changes: 1 addition & 1 deletion tests/Database/connect.inc.php
Expand Up @@ -13,7 +13,7 @@

try {
$connection = new Nette\Database\Connection($options['dsn'], $options['user'], $options['password']);
} catch (PDOException $e) {
} catch (Nette\Database\ConnectionException $e) {
Tester\Environment::skip("Connection to '$options[dsn]' failed. Reason: " . $e->getMessage());
}

Expand Down

0 comments on commit a25a912

Please sign in to comment.