diff --git a/lib/AbstractException.php b/lib/AbstractException.php index 38ff02bb..4eee0ffe 100644 --- a/lib/AbstractException.php +++ b/lib/AbstractException.php @@ -26,6 +26,7 @@ abstract class AbstractException extends \Exception { "Db/Exception.fileUnwritable" => 10205, "Db/Exception.fileUncreatable" => 10206, "Db/Exception.fileCorrupt" => 10207, + "Db/Exception.connectionFailure" => 10208, "Db/Exception.updateTooNew" => 10211, "Db/Exception.updateManual" => 10212, "Db/Exception.updateManualOnly" => 10213, diff --git a/lib/Db/PostgreSQL/PDODriver.php b/lib/Db/PostgreSQL/PDODriver.php index d6d44769..c4eebd56 100644 --- a/lib/Db/PostgreSQL/PDODriver.php +++ b/lib/Db/PostgreSQL/PDODriver.php @@ -22,10 +22,22 @@ class PDODriver extends Driver { protected function makeConnection(string $user, string $pass, string $db, string $host, int $port, string $service) { $dsn = $this->makeconnectionString(true, $user, $pass, $db, $host, $port, $service); - $this->db = new \PDO("pgsql:$dsn", $user, $pass, [ - \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, - \PDO::ATTR_PERSISTENT => true, - ]); + try { + $this->db = new \PDO("pgsql:$dsn", $user, $pass, [ + \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, + \PDO::ATTR_PERSISTENT => true, + ]); + } catch (\PDOException $e) { + if ($e->getCode() == 7) { + switch (substr($e->getMessage(), 9, 5)) { + case "08006": + throw new Exception("connectionFailure", ["PostgreSQL", substr($e->getMessage(), 28)]); + default: + throw $e; // @codeCoverageIgnore + } + } + throw $e; // @codeCoverageIgnore + } } public function __destruct() { diff --git a/locale/en.php b/locale/en.php index 50b8b5fc..3e63ac69 100644 --- a/locale/en.php +++ b/locale/en.php @@ -122,6 +122,7 @@ return [ 'Exception.JKingWeb/Arsse/Db/Exception.fileUnusable' => 'Insufficient permissions to open database file "{0}" for reading or writing', 'Exception.JKingWeb/Arsse/Db/Exception.fileUncreatable' => 'Insufficient permissions to create new database file "{0}"', 'Exception.JKingWeb/Arsse/Db/Exception.fileCorrupt' => 'Database file "{0}" is corrupt or not a valid database', + 'Exception.JKingWeb/Arsse/Db/Exception.connectionFailure' => 'Could not connect to {0} database: {1}', 'Exception.JKingWeb/Arsse/Db/Exception.paramTypeInvalid' => 'Prepared statement parameter type "{0}" is invalid', 'Exception.JKingWeb/Arsse/Db/Exception.paramTypeUnknown' => 'Prepared statement parameter type "{0}" is valid, but not implemented', 'Exception.JKingWeb/Arsse/Db/Exception.paramTypeMissing' => 'Prepared statement parameter type for parameter #{0} was not specified', diff --git a/tests/cases/Db/PostgreSQL/TestCreation.php b/tests/cases/Db/PostgreSQL/TestCreation.php index 1abdf45d..e22854ad 100644 --- a/tests/cases/Db/PostgreSQL/TestCreation.php +++ b/tests/cases/Db/PostgreSQL/TestCreation.php @@ -7,11 +7,11 @@ declare(strict_types=1); namespace JKingWeb\Arsse\TestCase\Db\PostgreSQL; use JKingWeb\Arsse\Arsse; -use JKingWeb\Arsse\Db\PostgreSQL\Driver; +use JKingWeb\Arsse\Db\PostgreSQL\PDODriver as Driver; /** * @group slow - * @covers \JKingWeb\Arsse\Db\PostgreSQL\Driver */ + * @covers \JKingWeb\Arsse\Db\PostgreSQL\PDODriver */ class TestCreation extends \JKingWeb\Arsse\Test\AbstractTest { /** @dataProvider provideConnectionStrings */ public function testGenerateConnectionString(bool $pdo, string $user, string $pass, string $db, string $host, int $port, string $service, string $exp) { @@ -55,4 +55,13 @@ class TestCreation extends \JKingWeb\Arsse\Test\AbstractTest { [true, "T'Pau of Vulcan", "superman", "datumbase", "somehost", 2112, "arsse", "service='arsse'"], ]; } + + public function testFailToConnect() { + // PDO dies not distinguish between different connection failure modes + self::setConf([ + 'dbPostgreSQLPass' => (string) rand(), + ]); + $this->assertException("connectionFailure", "Db"); + new Driver; + } }