-
Notifications
You must be signed in to change notification settings - Fork 11.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[8.x] Throwable error code can only be an integer #39280
Conversation
Eh, maybe we should check both to be safe? I think this would be reported much more often? |
There's an explicit comment about the test double override that forces a string framework/tests/Database/DatabaseConnectionTest.php Lines 460 to 463 in 994cf4c
Maybe @jansennerd10 can remember exactly why that was done in #29067 two years ago? https://www.php.net/manual/en/class.pdoexception.php documents: class PDOException extends RuntimeException {
/* Inherited methods */
final public Exception::getCode(): int But Only methods The PDO extension source contains many alphanumeric So AFAIK the extension raises |
I remember this being (bafflingly) the case... love PHP for its (lack of) consistency. Glad someone looked into the C code to figure out how it's happening.
Well... I thought the same about the original issue fixed in #29067. My guess is very few people actually use transaction modes that can auto-rollback on commit, so it's an edge case that doesn't get a lot of attention.
@lucacri can you provide more details about your setup? If you're trying to test the behavior with your own synthetic If on the other hand you're observing this problem with a "live" |
This is not necessary. It will always be a string. |
The information in the docs is wrong unfortunately. If you look at the C code, you will see PDO exception codes are strings (I see you did, and it is a string... i don't understand the PR then?). |
You are right, I'm trying to synthetically test that the transaction would retry if an exception with the code 40001 is thrown. Using PHP 8.0.5. My setup is a bit different than usual since I'm using CockroachDB in production, and there are a few error messages that all have the code 40001, but the message itself is different than the ones we already have in the DetectsConcurrencyErrors.php. The final goal would be to have that every single query passing through \DB or Eloquent would retry if it's receiving a 40001. For the time being I created a simple static function: public static function run(Closure $query, $attempt = 0) {
try {
return $query();
} catch (Throwable $e) {
$attempt++;
if ($attempt >= self::MAX_ATTEMPTS) {
throw $e;
}
if ($e instanceof PDOException && $e->getCode() === 40001) {
// RETRY it
return self::run($query, $attempt);
}
throw $e;
}
} I had to manually check the PDOException instead of using I was testing it with (snippet): RetryableQuery::run(function () {
$this->testAttempt++;
if ($this->testAttempt === 1) {
throw new PDOException('Deadlock found', 40001);
} else {
return Team::first();
}
}); In the test, if I try to pass I understand this might be one of PHP's funkiness, and I think that @taylorotwell edit might just be the safest approach |
You can't pass it in the exception constructor, but you can set it directly on the exception after it's constructed. |
While testing the automatic retrying of a transaction for concurrency issues, I noticed that it only worked if the message contained any of the strings. The error code could never match the
'40001'
since the$e->getCode()
always returns an INT.