Skip to content

Commit 5800d08

Browse files
authored
Merge pull request #6596 from segrax/6595-oci8-replace-asserts-with-exceptions
Use exception in OCI8 driver, instead of relying on assert
2 parents 83469cb + 2905453 commit 5800d08

File tree

2 files changed

+77
-3
lines changed

2 files changed

+77
-3
lines changed

src/Driver/OCI8/Connection.php

+9-3
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,21 @@ public function getServerVersion(): string
4747
return $matches[1];
4848
}
4949

50-
/** @throws Parser\Exception */
50+
/**
51+
* @throws Parser\Exception
52+
* @throws Error
53+
*/
5154
public function prepare(string $sql): Statement
5255
{
5356
$visitor = new ConvertPositionalToNamedPlaceholders();
5457

5558
$this->parser->parse($sql, $visitor);
5659

57-
$statement = oci_parse($this->connection, $visitor->getSQL());
58-
assert(is_resource($statement));
60+
$statement = @oci_parse($this->connection, $visitor->getSQL());
61+
62+
if (! is_resource($statement)) {
63+
throw Error::new($this->connection);
64+
}
5965

6066
return new Statement($this->connection, $statement, $visitor->getParameterMap(), $this->executionMode);
6167
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Doctrine\DBAL\Tests\Functional\Driver\OCI8;
6+
7+
use Doctrine\DBAL\DriverManager;
8+
use Doctrine\DBAL\Exception\DriverException;
9+
use Doctrine\DBAL\Tests\FunctionalTestCase;
10+
use Doctrine\DBAL\Tests\TestUtil;
11+
use Throwable;
12+
13+
class ConnectionTest extends FunctionalTestCase
14+
{
15+
public static function setUpBeforeClass(): void
16+
{
17+
if (TestUtil::isDriverOneOf('oci8')) {
18+
return;
19+
}
20+
21+
self::markTestSkipped('This test requires the oci8 driver.');
22+
}
23+
24+
public function testPrepareThrowsErrorOnConnectionLost(): void
25+
{
26+
$this->markConnectionNotReusable();
27+
$this->killCurrentSession();
28+
29+
$this->expectException(DriverException::class);
30+
31+
$this->connection->prepare('SELECT * FROM 1');
32+
}
33+
34+
/**
35+
* Kill the current session, by using another connection
36+
* Oracle doesn't allow you to terminate the current session, so we use a second connection
37+
*/
38+
private function killCurrentSession(): void
39+
{
40+
$row = $this->connection->fetchNumeric(
41+
<<<'SQL'
42+
SELECT SID, SERIAL#
43+
FROM V$SESSION
44+
WHERE AUDSID = USERENV('SESSIONID')
45+
SQL,
46+
);
47+
48+
self::assertNotFalse($row);
49+
/** @psalm-suppress PossiblyUndefinedArrayOffset */
50+
[$sid, $serialNumber] = $row;
51+
52+
self::assertNotNull($sid, 'SID is missing.');
53+
self::assertNotNull($serialNumber, 'Serial number is missing.');
54+
55+
$params = TestUtil::getConnectionParams();
56+
$params['driverOptions']['exclusive'] = true;
57+
$secondConnection = DriverManager::getConnection($params);
58+
59+
$sessionParam = $this->connection->quote($sid . ', ' . $serialNumber);
60+
$secondConnection->executeStatement('ALTER SYSTEM DISCONNECT SESSION ' . $sessionParam . ' IMMEDIATE');
61+
62+
// Ensure OCI driver is aware of connection state change by executing any statement
63+
try {
64+
$this->connection->executeStatement('INVALID SQL');
65+
} catch (Throwable) {
66+
}
67+
}
68+
}

0 commit comments

Comments
 (0)