From 7c1df71acd911b0b5e79ddf35707028c1a6f7af2 Mon Sep 17 00:00:00 2001 From: "J. King" Date: Wed, 8 Mar 2017 09:55:16 -0500 Subject: [PATCH] Make db throw specific exceptions Needs testing and fleshing out; not all exception codes and messages have been defined --- lib/AbstractException.php | 7 ++++--- lib/Db/SQLite3/Driver.php | 29 +++++++++++++++++++++++------ lib/Db/SQLite3/ExceptionBuilder.php | 23 +++++++++++++++++++++++ lib/Db/SQLite3/Statement.php | 15 ++++++++++++++- locale/en.php | 2 +- 5 files changed, 65 insertions(+), 11 deletions(-) create mode 100644 lib/Db/SQLite3/ExceptionBuilder.php diff --git a/lib/AbstractException.php b/lib/AbstractException.php index 04bb2c0..ac3be83 100644 --- a/lib/AbstractException.php +++ b/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, diff --git a/lib/Db/SQLite3/Driver.php b/lib/Db/SQLite3/Driver.php index 826e288..7029919 100644 --- a/lib/Db/SQLite3/Driver.php +++ b/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); } } \ No newline at end of file diff --git a/lib/Db/SQLite3/ExceptionBuilder.php b/lib/Db/SQLite3/ExceptionBuilder.php new file mode 100644 index 0000000..9f5c855 --- /dev/null +++ b/lib/Db/SQLite3/ExceptionBuilder.php @@ -0,0 +1,23 @@ +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()]; + } + } +} \ No newline at end of file diff --git a/lib/Db/SQLite3/Statement.php b/lib/Db/SQLite3/Statement.php index fda5675..a1cdde9 100644 --- a/lib/Db/SQLite3/Statement.php +++ b/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); } } \ No newline at end of file diff --git a/locale/en.php b/locale/en.php index 4e13834..c85293d 100644 --- a/locale/en.php +++ b/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}