Skip to content

Commit

Permalink
Transform Oracle's "transaction rolled back" exception and use the un…
Browse files Browse the repository at this point in the history
…derlying one that DBAL supports
  • Loading branch information
simPod committed Oct 14, 2024
1 parent 36e23d1 commit b1b6ab2
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 4 deletions.
18 changes: 17 additions & 1 deletion src/Driver/OCI8/Exception/Error.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
use Doctrine\DBAL\Driver\AbstractException;

use function assert;
use function explode;
use function oci_error;
use function str_replace;

/**
* @internal
Expand All @@ -16,12 +18,26 @@
*/
final class Error extends AbstractException
{
private const CODE_TRANSACTION_ROLLED_BACK = 2091;

/** @param resource $resource */
public static function new($resource): self
{
$error = oci_error($resource);
assert($error !== false);

return new self($error['message'], null, $error['code']);
$code = $error['code'];
$message = $error['message'];
if ($code === self::CODE_TRANSACTION_ROLLED_BACK) {

Check warning on line 31 in src/Driver/OCI8/Exception/Error.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/OCI8/Exception/Error.php#L29-L31

Added lines #L29 - L31 were not covered by tests
// There's no way this can be unit-tested as it's impossible to mock $resource
//ORA-02091: transaction rolled back
//ORA-00001: unique constraint (DOCTRINE.GH3423_UNIQUE) violated
[$firstMessage, $secondMessage] = explode("\n", $message, 2);

Check warning on line 35 in src/Driver/OCI8/Exception/Error.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/OCI8/Exception/Error.php#L35

Added line #L35 was not covered by tests

[$code, $message] = explode(': ', $secondMessage, 2);
$code = (int) str_replace('ORA-', '', $code);

Check warning on line 38 in src/Driver/OCI8/Exception/Error.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/OCI8/Exception/Error.php#L37-L38

Added lines #L37 - L38 were not covered by tests
}

return new self($message, null, $code);

Check warning on line 41 in src/Driver/OCI8/Exception/Error.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/OCI8/Exception/Error.php#L41

Added line #L41 was not covered by tests
}
}
18 changes: 17 additions & 1 deletion src/Driver/PDO/Exception.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,22 @@
use Doctrine\DBAL\Driver\AbstractException;
use PDOException;

use function explode;
use function str_replace;

/**
* @internal
*
* @psalm-immutable
*/
final class Exception extends AbstractException
{
private const CODE_TRANSACTION_ROLLED_BACK = 2091;

public static function new(PDOException $exception): self
{
$message = $exception->getMessage();

if ($exception->errorInfo !== null) {
[$sqlState, $code] = $exception->errorInfo;

Expand All @@ -25,6 +32,15 @@ public static function new(PDOException $exception): self
$sqlState = null;
}

return new self($exception->getMessage(), $sqlState, $code, $exception);
if ($code === self::CODE_TRANSACTION_ROLLED_BACK) {
//ORA-02091: transaction rolled back
//ORA-00001: unique constraint (DOCTRINE.GH3423_UNIQUE) violated
[$firstMessage, $secondMessage] = explode("\n", $message, 2);

Check warning on line 38 in src/Driver/PDO/Exception.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/PDO/Exception.php#L38

Added line #L38 was not covered by tests

[$code, $message] = explode(': ', $secondMessage, 2);
$code = (int) str_replace('ORA-', '', $code);

Check warning on line 41 in src/Driver/PDO/Exception.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/PDO/Exception.php#L40-L41

Added lines #L40 - L41 were not covered by tests
}

return new self($message, $sqlState, $code, $exception);
}
}
25 changes: 23 additions & 2 deletions src/Driver/PDO/PDOException.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@

use Doctrine\DBAL\Driver\Exception as DriverException;

use function explode;
use function is_numeric;
use function str_replace;
use function strpos;

/**
* @internal
*
Expand All @@ -17,10 +22,26 @@ final class PDOException extends \PDOException implements DriverException

public static function new(\PDOException $previous): self
{
$exception = new self($previous->message, 0, $previous);
if (isset($previous->errorInfo[2]) && strpos($previous->errorInfo[2], 'OCITransCommit: ORA-02091') === 0) {

Check warning on line 25 in src/Driver/PDO/PDOException.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/PDO/PDOException.php#L25

Added line #L25 was not covered by tests
// With pdo_oci driver, the root-cause error is in the second line
//ORA-02091: transaction rolled back
//ORA-00001: unique constraint (DOCTRINE.GH3423_UNIQUE) violated
[$firstMessage, $secondMessage] = explode("\n", $previous->message, 2);

Check warning on line 29 in src/Driver/PDO/PDOException.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/PDO/PDOException.php#L29

Added line #L29 was not covered by tests

[$code, $message] = explode(': ', $secondMessage, 2);
$code = (int) str_replace('ORA-', '', $code);

Check warning on line 32 in src/Driver/PDO/PDOException.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/PDO/PDOException.php#L31-L32

Added lines #L31 - L32 were not covered by tests
} else {
$message = $previous->message;
if (is_numeric($previous->code)) {
$code = (int) $previous->code;

Check warning on line 36 in src/Driver/PDO/PDOException.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/PDO/PDOException.php#L34-L36

Added lines #L34 - L36 were not covered by tests
} else {
$code = $previous->errorInfo[1] ?? 0;

Check warning on line 38 in src/Driver/PDO/PDOException.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/PDO/PDOException.php#L38

Added line #L38 was not covered by tests
}
}

$exception = new self($message, $code, $previous);

Check warning on line 42 in src/Driver/PDO/PDOException.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/PDO/PDOException.php#L42

Added line #L42 was not covered by tests

$exception->errorInfo = $previous->errorInfo;
$exception->code = $previous->code;
$exception->sqlState = $previous->errorInfo[0] ?? null;

return $exception;
Expand Down

0 comments on commit b1b6ab2

Please sign in to comment.