Browse Source

Make db throw specific exceptions

Needs testing and fleshing out; not all exception codes and messages have been defined
microsub
J. King 7 years ago
parent
commit
7c1df71acd
  1. 7
      lib/AbstractException.php
  2. 29
      lib/Db/SQLite3/Driver.php
  3. 23
      lib/Db/SQLite3/ExceptionBuilder.php
  4. 15
      lib/Db/SQLite3/Statement.php
  5. 2
      locale/en.php

7
lib/AbstractException.php

@ -27,9 +27,10 @@ abstract class AbstractException extends \Exception {
"Db/Exception.updateFileUnreadable" => 10214,
"Db/Exception.updateManual" => 10215,
"Db/Exception.updateManualOnly" => 10216,
"Db/Exception.paramTypeInvalid" => 10401,
"Db/Exception.paramTypeUnknown" => 10402,
"Db/Exception.paramTypeMissing" => 10403,
"Db/Exception.paramTypeInvalid" => 10301,
"Db/Exception.paramTypeUnknown" => 10302,
"Db/Exception.paramTypeMissing" => 10303,
"Db/Exception.engineErrorGeneral" => 10401, // this symbol can have engine-specific duplicates to accomodate engine-specific error string construction
"Conf/Exception.fileMissing" => 10302,
"Conf/Exception.fileUnusable" => 10303,
"Conf/Exception.fileUnreadable" => 10304,

29
lib/Db/SQLite3/Driver.php

@ -7,8 +7,9 @@ use JKingWeb\NewsSync\Db\ExceptionInput;
use JKingWeb\NewsSync\Db\ExceptionTimeout;
class Driver extends \JKingWeb\NewsSync\Db\AbstractDriver {
const SQLITE_ERROR = 1;
class Driver extends \JKingWeb\NewsSync\Db\AbstractDriver {
use ExceptionBuilder;
const SQLITE_BUSY = 5;
const SQLITE_CONSTRAINT = 19;
const SQLITE_MISMATCH = 20;
@ -78,7 +79,6 @@ class Driver extends \JKingWeb\NewsSync\Db\AbstractDriver {
// commit any successful updates if updating by more than one version
$this->commit(true);
// throw the error received
// FIXME: This should create the relevant type of SQL exception
throw $e;
}
$this->commit();
@ -89,14 +89,31 @@ class Driver extends \JKingWeb\NewsSync\Db\AbstractDriver {
}
public function exec(string $query): bool {
return (bool) $this->db->exec($query);
try {
return (bool) $this->db->exec($query);
} catch(\Exception $e) {
list($excClass, $excMsg, $excData) = $this->exceptionBuild();
throw new $excClass($excMsg, $excData);
}
}
public function query(string $query): \JKingWeb\NewsSync\Db\Result {
return new Result($this->db->query($query), $this->db->changes());
Try {
$r = $this->db->query($query);
} catch(\Exception $e) {
list($excClass, $excMsg, $excData) = $this->exceptionBuild();
throw new $excClass($excMsg, $excData);
}
return new Result($r, $this->db->changes());
}
public function prepareArray(string $query, array $paramTypes): \JKingWeb\NewsSync\Db\Statement {
return new Statement($this->db, $this->db->prepare($query), $paramTypes);
try {
$s = $this->db->prepare($query);
} catch(\Exception $e) {
list($excClass, $excMsg, $excData) = $this->exceptionBuild();
throw new $excClass($excMsg, $excData);
}
return new Statement($this->db, $s, $paramTypes);
}
}

23
lib/Db/SQLite3/ExceptionBuilder.php

@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace JKingWeb\NewsSync\Db\SQLite3;
use JKingWeb\NewsSync\Db\Exception;
use JKingWeb\NewsSync\Db\ExceptionInput;
use JKingWeb\NewsSync\Db\ExceptionTimeout;
trait ExceptionBuilder {
public function exceptionBuild() {
switch($this->db->lastErrorCode()) {
case self::SQLITE_BUSY:
return [ExceptionTimeout::class, 'sqliteBusy', $this->db->lastErrorMsg()];
case self::SQLITE_CONSTRAINT:
return [ExceptionInput::class, 'constraintViolation', $this->db->lastErrorMsg()];
case self::SQLITE_MISMATCH:
return [ExceptionInput::class, 'typeViolation', $this->db->lastErrorMsg()];
default:
return [Exception::class, 'engineErrorGeneral', $this->db->lastErrorMsg()];
}
}
}

15
lib/Db/SQLite3/Statement.php

@ -2,8 +2,15 @@
declare(strict_types=1);
namespace JKingWeb\NewsSync\Db\SQLite3;
use JKingWeb\NewsSync\Db\Exception;
use JKingWeb\NewsSync\Db\ExceptionInput;
use JKingWeb\NewsSync\Db\ExceptionTimeout;
class Statement extends \JKingWeb\NewsSync\Db\AbstractStatement {
use ExceptionBuilder;
const SQLITE_BUSY = 5;
const SQLITE_CONSTRAINT = 19;
const SQLITE_MISMATCH = 20;
const BINDINGS = [
"null" => \SQLITE3_NULL,
"integer" => \SQLITE3_INTEGER,
@ -59,6 +66,12 @@ class Statement extends \JKingWeb\NewsSync\Db\AbstractStatement {
// perform binding
$this->st->bindValue($a+1, $values[$a], $type);
}
return new Result($this->st->execute(), $this->db->changes(), $this);
try {
$r = $this->st->execute();
} catch(\Exception $e) {
list($excClass, $excMsg, $excData) = $this->exceptionBuild();
throw new $excClass($excMsg, $excData);
}
return new Result($r, $this->db->changes(), $this);
}
}

2
locale/en.php

@ -28,10 +28,10 @@ return [
'Exception.JKingWeb/NewsSync/Db/Exception.fileUnusable' => 'Insufficient permissions to open database file "{0}" for reading or writing',
'Exception.JKingWeb/NewsSync/Db/Exception.fileUncreatable' => 'Insufficient permissions to create new database file "{0}"',
'Exception.JKingWeb/NewsSync/Db/Exception.fileCorrupt' => 'Database file "{0}" is corrupt or not a valid database',
'Exception.JKingWeb/NewsSync/Db/Exception.engineErrorGeneral' => '{0}',
'Exception.JKingWeb/NewsSync/Db/Exception.paramTypeInvalid' => 'Prepared statement parameter type "{0}" is invalid',
'Exception.JKingWeb/NewsSync/Db/Exception.paramTypeUnknown' => 'Prepared statement parameter type "{0}" is valid, but not implemented',
'Exception.JKingWeb/NewsSync/Db/Exception.paramTypeMissing' => 'Prepared statement parameter type for parameter #{0} was not specified',
'Exception.JKingWeb/NewsSync/Db/Exception.updateManual' =>
'{from_version, select,
0 {{driver_name} database is configured for manual updates and is not initialized; please populate the database with the base schema}

Loading…
Cancel
Save