Skip to content

Commit b1b6ab2

Browse files
committed
Transform Oracle's "transaction rolled back" exception and use the underlying one that DBAL supports
1 parent 36e23d1 commit b1b6ab2

File tree

3 files changed

+57
-4
lines changed

3 files changed

+57
-4
lines changed

src/Driver/OCI8/Exception/Error.php

+17-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
use Doctrine\DBAL\Driver\AbstractException;
88

99
use function assert;
10+
use function explode;
1011
use function oci_error;
12+
use function str_replace;
1113

1214
/**
1315
* @internal
@@ -16,12 +18,26 @@
1618
*/
1719
final class Error extends AbstractException
1820
{
21+
private const CODE_TRANSACTION_ROLLED_BACK = 2091;
22+
1923
/** @param resource $resource */
2024
public static function new($resource): self
2125
{
2226
$error = oci_error($resource);
2327
assert($error !== false);
2428

25-
return new self($error['message'], null, $error['code']);
29+
$code = $error['code'];
30+
$message = $error['message'];
31+
if ($code === self::CODE_TRANSACTION_ROLLED_BACK) {
32+
// There's no way this can be unit-tested as it's impossible to mock $resource
33+
//ORA-02091: transaction rolled back
34+
//ORA-00001: unique constraint (DOCTRINE.GH3423_UNIQUE) violated
35+
[$firstMessage, $secondMessage] = explode("\n", $message, 2);
36+
37+
[$code, $message] = explode(': ', $secondMessage, 2);
38+
$code = (int) str_replace('ORA-', '', $code);
39+
}
40+
41+
return new self($message, null, $code);
2642
}
2743
}

src/Driver/PDO/Exception.php

+17-1
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,22 @@
77
use Doctrine\DBAL\Driver\AbstractException;
88
use PDOException;
99

10+
use function explode;
11+
use function str_replace;
12+
1013
/**
1114
* @internal
1215
*
1316
* @psalm-immutable
1417
*/
1518
final class Exception extends AbstractException
1619
{
20+
private const CODE_TRANSACTION_ROLLED_BACK = 2091;
21+
1722
public static function new(PDOException $exception): self
1823
{
24+
$message = $exception->getMessage();
25+
1926
if ($exception->errorInfo !== null) {
2027
[$sqlState, $code] = $exception->errorInfo;
2128

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

28-
return new self($exception->getMessage(), $sqlState, $code, $exception);
35+
if ($code === self::CODE_TRANSACTION_ROLLED_BACK) {
36+
//ORA-02091: transaction rolled back
37+
//ORA-00001: unique constraint (DOCTRINE.GH3423_UNIQUE) violated
38+
[$firstMessage, $secondMessage] = explode("\n", $message, 2);
39+
40+
[$code, $message] = explode(': ', $secondMessage, 2);
41+
$code = (int) str_replace('ORA-', '', $code);
42+
}
43+
44+
return new self($message, $sqlState, $code, $exception);
2945
}
3046
}

src/Driver/PDO/PDOException.php

+23-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66

77
use Doctrine\DBAL\Driver\Exception as DriverException;
88

9+
use function explode;
10+
use function is_numeric;
11+
use function str_replace;
12+
use function strpos;
13+
914
/**
1015
* @internal
1116
*
@@ -17,10 +22,26 @@ final class PDOException extends \PDOException implements DriverException
1722

1823
public static function new(\PDOException $previous): self
1924
{
20-
$exception = new self($previous->message, 0, $previous);
25+
if (isset($previous->errorInfo[2]) && strpos($previous->errorInfo[2], 'OCITransCommit: ORA-02091') === 0) {
26+
// With pdo_oci driver, the root-cause error is in the second line
27+
//ORA-02091: transaction rolled back
28+
//ORA-00001: unique constraint (DOCTRINE.GH3423_UNIQUE) violated
29+
[$firstMessage, $secondMessage] = explode("\n", $previous->message, 2);
30+
31+
[$code, $message] = explode(': ', $secondMessage, 2);
32+
$code = (int) str_replace('ORA-', '', $code);
33+
} else {
34+
$message = $previous->message;
35+
if (is_numeric($previous->code)) {
36+
$code = (int) $previous->code;
37+
} else {
38+
$code = $previous->errorInfo[1] ?? 0;
39+
}
40+
}
41+
42+
$exception = new self($message, $code, $previous);
2143

2244
$exception->errorInfo = $previous->errorInfo;
23-
$exception->code = $previous->code;
2445
$exception->sqlState = $previous->errorInfo[0] ?? null;
2546

2647
return $exception;

0 commit comments

Comments
 (0)