Skip to content

Commit

Permalink
try/catch checking and converting of PDOException moved to drivers
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed Aug 19, 2024
1 parent 2486656 commit f633cf9
Show file tree
Hide file tree
Showing 23 changed files with 165 additions and 166 deletions.
6 changes: 3 additions & 3 deletions src/Bridges/DatabaseTracy/ConnectionPanel.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ private function logQuery(Connection $connection, $result): void
$this->count++;

$source = null;
$trace = $result instanceof \PDOException
$trace = $result instanceof \Exception
? $result->getTrace()
: debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
foreach ($trace as $row) {
Expand All @@ -100,15 +100,15 @@ private function logQuery(Connection $connection, $result): void
if ($this->count < $this->maxQueries) {
$this->queries[] = [$connection, $result->getQueryString(), $result->getParameters(), $source, $result->getTime(), $result->getRowCount(), null];
}
} elseif ($result instanceof \PDOException && $this->count < $this->maxQueries) {
} elseif ($result instanceof \Exception && $this->count < $this->maxQueries) {
$this->queries[] = [$connection, $result->queryString, null, $source, null, null, $result->getMessage()];

Check failure on line 104 in src/Bridges/DatabaseTracy/ConnectionPanel.php

View workflow job for this annotation

GitHub Actions / PHPStan

Access to an undefined property Exception::$queryString.
}
}


public static function renderException(?\Throwable $e): ?array
{
if (!$e instanceof \PDOException) {
if (!$e instanceof \Exception) {
return null;
}

Expand Down
20 changes: 4 additions & 16 deletions src/Database/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
use JetBrains\PhpStorm\Language;
use Nette\Utils\Arrays;
use Nette\Utils\DateTime;
use PDOException;


/**
Expand Down Expand Up @@ -61,18 +60,11 @@ public function __construct(

public function connect(): void
{
if ($this->connection) {
return;
}

try {
if (!$this->connection) {
$this->connection = $this->driver->connect();
$this->engine = $this->driver->createDatabaseEngine($this->connection);
} catch (PDOException $e) {
throw ConnectionException::from($e);
Arrays::invoke($this->onConnect, $this);
}

Arrays::invoke($this->onConnect, $this);
}


Expand Down Expand Up @@ -152,11 +144,7 @@ public function setRowNormalizer(?callable $normalizer): static

public function getInsertId(?string $sequence = null): string
{
try {
return $this->getConnectionDriver()->getInsertId($sequence);
} catch (PDOException $e) {
throw $this->engine->convertException($e);
}
return $this->getConnectionDriver()->getInsertId($sequence);
}


Expand Down Expand Up @@ -232,7 +220,7 @@ public function query(#[Language('SQL')] string $sql, #[Language('GenericSQL')]
[$this->sql, $params] = $this->preprocess($sql, ...$params);
try {
$result = new ResultSet($this, $this->sql, $params, $this->rowNormalizer);
} catch (PDOException $e) {
} catch (DriverException $e) {
Arrays::invoke($this->onQuery, $this, $e);
throw $e;
}
Expand Down
39 changes: 14 additions & 25 deletions src/Database/DriverException.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,51 +13,40 @@
/**
* 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;


public static function from(\PDOException $src): static
{
$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;
}

return $e;
public function __construct(
string $message,
private readonly ?string $sqlState = null,
private int $driverCode = 0,
private readonly ?SqlLiteral $query = null,
?\Throwable $previous = null,
) {
parent::__construct($message, 0, $previous);
$this->code = $sqlState ?: null;
}


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


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


public function getQueryString(): ?string
{
return $this->queryString;
return $this->query?->getSql();
}


public function getParameters(): ?array
{
return $this->params;
return $this->query?->getParameters();
}
}
5 changes: 2 additions & 3 deletions src/Database/Drivers/Engine.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

namespace Nette\Database\Drivers;

use Nette\Database;
use Nette\Database\TypeConverter;


Expand All @@ -27,9 +26,9 @@ interface Engine
SupportSchema = 'schema';

/**
* Converts PDOException to DriverException or its descendant.
* Suggests an appropriate class for the exception.
*/
function convertException(\PDOException $e): Database\DriverException;
static function determineExceptionClass(int $code, ?string $sqlState, string $message): ?string;

/**
* Delimites identifier for use in a SQL statement.
Expand Down
4 changes: 2 additions & 2 deletions src/Database/Drivers/Engines/MSSQLEngine.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ public function __construct(
}


public function convertException(\PDOException $e): Nette\Database\DriverException
public static function determineExceptionClass(int $code, ?string $sqlState, string $message): ?string
{
return Nette\Database\DriverException::from($e);
return null;
}


Expand Down
25 changes: 8 additions & 17 deletions src/Database/Drivers/Engines/MySQLEngine.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,15 @@ public function __construct(
}


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

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

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

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

} else {
return Nette\Database\DriverException::from($e);
}
return match (true) {
in_array($code, [1216, 1217, 1451, 1452, 1701], strict: true) => Nette\Database\ForeignKeyConstraintViolationException::class,
in_array($code, [1062, 1557, 1569, 1586], strict: true) => Nette\Database\UniqueConstraintViolationException::class,
$code >= 2001 && $code <= 2028 => Nette\Database\ConnectionException::class,
in_array($code, [1048, 1121, 1138, 1171, 1252, 1263, 1566], strict: true) => Nette\Database\NotNullConstraintViolationException::class,
default => null,
};
}


Expand Down
4 changes: 2 additions & 2 deletions src/Database/Drivers/Engines/ODBCEngine.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
*/
class ODBCEngine implements Engine
{
public function convertException(\PDOException $e): Nette\Database\DriverException
public static function determineExceptionClass(int $code, ?string $sqlState, string $message): ?string
{
return Nette\Database\DriverException::from($e);
return null;
}


Expand Down
21 changes: 7 additions & 14 deletions src/Database/Drivers/Engines/OracleEngine.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,14 @@ public function __construct(
}


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

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

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

} else {
return Nette\Database\DriverException::from($e);
}
return match (true) {
in_array($code, [1, 2299, 38911], strict: true) => Nette\Database\UniqueConstraintViolationException::class,
in_array($code, [1400], strict: true) => Nette\Database\NotNullConstraintViolationException::class,
in_array($code, [2266, 2291, 2292], strict: true) => Nette\Database\ForeignKeyConstraintViolationException::class,
default => null,
};
}


Expand Down
29 changes: 9 additions & 20 deletions src/Database/Drivers/Engines/PostgreSQLEngine.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,27 +26,16 @@ public function __construct(
}


public function convertException(\PDOException $e): Nette\Database\DriverException
public static function determineExceptionClass(int $code, ?string $sqlState, string $message): ?string
{
$code = $e->errorInfo[0] ?? null;
if ($code === '0A000' && str_contains($e->getMessage(), 'truncate')) {
return Nette\Database\ForeignKeyConstraintViolationException::from($e);

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

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

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

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

} else {
return Nette\Database\DriverException::from($e);
}
return match ($sqlState) {
'0A000' => str_contains($message, 'truncate') ? Nette\Database\ForeignKeyConstraintViolationException::class : null,
'23502' => Nette\Database\NotNullConstraintViolationException::class,
'23503' => Nette\Database\ForeignKeyConstraintViolationException::class,
'23505' => Nette\Database\UniqueConstraintViolationException::class,
'08006' => Nette\Database\ConnectionException::class,
default => null,
};
}


Expand Down
4 changes: 2 additions & 2 deletions src/Database/Drivers/Engines/SQLServerEngine.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ public function __construct(
}


public function convertException(\PDOException $e): Nette\Database\DriverException
public static function determineExceptionClass(int $code, ?string $sqlState, string $message): ?string
{
return Nette\Database\DriverException::from($e);
return null;
}


Expand Down
28 changes: 13 additions & 15 deletions src/Database/Drivers/Engines/SQLiteEngine.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,34 +30,32 @@ public function __construct(
}


public function convertException(\PDOException $e): Nette\Database\DriverException
public static function determineExceptionClass(int $code, ?string $sqlState, string $message): ?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')
str_contains($message, 'must be unique')
|| str_contains($message, 'is not unique')
|| str_contains($message, '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')
str_contains($message, 'may not be null')
|| str_contains($message, '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')
str_contains($message, 'foreign key constraint failed')
|| str_contains($message, '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
Loading

0 comments on commit f633cf9

Please sign in to comment.