From 0dbe21683a25992b6b268b693e4e2c027bf16c07 Mon Sep 17 00:00:00 2001 From: flashwave Date: Sat, 19 Oct 2024 14:51:55 +0000 Subject: [PATCH] Revised the transaction API. --- VERSION | 2 +- src/Db/DbConnection.php | 10 +++- src/Db/DbTools.php | 24 +------- src/Db/DbTransaction.php | 47 ++++++++++++++++ src/Db/DbTransactions.php | 57 ------------------- src/Db/MariaDb/MariaDbConnection.php | 55 ++++++++----------- src/Db/MariaDb/MariaDbTransaction.php | 45 +++++++++++++++ src/Db/NullDb/NullDbConnection.php | 8 ++- src/Db/NullDb/NullDbTransaction.php | 22 ++++++++ src/Db/Sqlite/SqliteConnection.php | 79 +++++++++++---------------- src/Db/Sqlite/SqliteTransaction.php | 43 +++++++++++++++ 11 files changed, 229 insertions(+), 163 deletions(-) create mode 100644 src/Db/DbTransaction.php delete mode 100644 src/Db/DbTransactions.php create mode 100644 src/Db/MariaDb/MariaDbTransaction.php create mode 100644 src/Db/NullDb/NullDbTransaction.php create mode 100644 src/Db/Sqlite/SqliteTransaction.php diff --git a/VERSION b/VERSION index db4d9b4..a49f880 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.2410.182054 +0.2410.191450 diff --git a/src/Db/DbConnection.php b/src/Db/DbConnection.php index 4690aba..209de9b 100644 --- a/src/Db/DbConnection.php +++ b/src/Db/DbConnection.php @@ -1,10 +1,11 @@ beginTransaction(); - $result = $callable($connection) ?? null; - if(is_bool($result)) { - if($result) - $connection->commit(); - else - $connection->rollback(); - } - } - /** * Detects the DbType of the passed argument. Should be used for DbType::AUTO. * diff --git a/src/Db/DbTransaction.php b/src/Db/DbTransaction.php new file mode 100644 index 0000000..17bc417 --- /dev/null +++ b/src/Db/DbTransaction.php @@ -0,0 +1,47 @@ +getMessage(), $ex->getCode(), $ex); } + + $this->connection->autocommit(true); } public function getAffectedRows(): int|string { @@ -189,7 +191,7 @@ class MariaDbConnection implements DbConnection, DbTransactions { */ public function switchUser(string $userName, string $password, string|null $database = null): void { if(!$this->connection->change_user($userName, $password, $database === null ? null : $database)) - throw new RuntimeException($this->getLastErrorString(), $this->getLastErrorCode()); + $this->throwLastError(); } /** @@ -200,7 +202,7 @@ class MariaDbConnection implements DbConnection, DbTransactions { */ public function switchDatabase(string $database): void { if(!$this->connection->select_db($database)) - throw new RuntimeException($this->getLastErrorString(), $this->getLastErrorCode()); + $this->throwLastError(); } /** @@ -230,6 +232,15 @@ class MariaDbConnection implements DbConnection, DbTransactions { return $this->connection->error; } + /** + * Throws the last error as a RuntimeException. + * + * @throws RuntimeException Based on the last error code and string. + */ + public function throwLastError(): never { + throw new RuntimeException((string)$this->getLastErrorString(), $this->getLastErrorCode()); + } + /** * Gets the current SQL State of the connection. * @@ -302,33 +313,11 @@ class MariaDbConnection implements DbConnection, DbTransactions { $this->connection->refresh($flags); } - public function setAutoCommit(bool $state): void { - $this->connection->autocommit($state); - } - - public function beginTransaction(): void { + public function beginTransaction(): DbTransaction { if(!$this->connection->begin_transaction()) - throw new RuntimeException((string)$this->getLastErrorString(), $this->getLastErrorCode()); - } + $this->throwLastError(); - public function commit(): void { - if(!$this->connection->commit()) - throw new RuntimeException((string)$this->getLastErrorString(), $this->getLastErrorCode()); - } - - public function rollback(?string $name = null): void { - if(!$this->connection->rollback(0, $name)) - throw new RuntimeException((string)$this->getLastErrorString(), $this->getLastErrorCode()); - } - - public function savePoint(string $name): void { - if(!$this->connection->savepoint($name)) - throw new RuntimeException((string)$this->getLastErrorString(), $this->getLastErrorCode()); - } - - public function releaseSavePoint(string $name): void { - if(!$this->connection->release_savepoint($name)) - throw new RuntimeException((string)$this->getLastErrorString(), $this->getLastErrorCode()); + return new MariaDbTransaction($this, $this->connection); } /** @@ -360,7 +349,7 @@ class MariaDbConnection implements DbConnection, DbTransactions { throw new RuntimeException($ex->getMessage(), $ex->getCode(), $ex); } if($statement === false) - throw new RuntimeException($this->getLastErrorString(), $this->getLastErrorCode()); + $this->throwLastError(); return new MariaDbStatement($statement); } @@ -375,7 +364,7 @@ class MariaDbConnection implements DbConnection, DbTransactions { } if($result === false) - throw new RuntimeException($this->getLastErrorString(), $this->getLastErrorCode()); + $this->throwLastError(); // the mysql library is very adorable if($result === true) @@ -388,7 +377,7 @@ class MariaDbConnection implements DbConnection, DbTransactions { public function execute(string $query): int|string { try { if(!$this->connection->real_query($query)) - throw new RuntimeException($this->getLastErrorString(), $this->getLastErrorCode()); + $this->throwLastError(); } catch(mysqli_sql_exception $ex) { throw new RuntimeException($ex->getMessage(), $ex->getCode(), $ex); } diff --git a/src/Db/MariaDb/MariaDbTransaction.php b/src/Db/MariaDb/MariaDbTransaction.php new file mode 100644 index 0000000..cb38708 --- /dev/null +++ b/src/Db/MariaDb/MariaDbTransaction.php @@ -0,0 +1,45 @@ +connRaw->commit()) + $this->conn->throwLastError(); + } + + public function save(string $name): void { + if(!$this->connRaw->savepoint($name)) + $this->conn->throwLastError(); + } + + public function release(string $name): void { + if(!$this->connRaw->release_savepoint($name)) + $this->conn->throwLastError(); + } + + public function rollback(?string $name = null): void { + if(!$this->connRaw->rollback(0, $name)) + $this->conn->throwLastError(); + } + + public function close(): void {} +} diff --git a/src/Db/NullDb/NullDbConnection.php b/src/Db/NullDb/NullDbConnection.php index 3661d5d..7cb87c7 100644 --- a/src/Db/NullDb/NullDbConnection.php +++ b/src/Db/NullDb/NullDbConnection.php @@ -1,11 +1,11 @@ connection->lastErrorCode(); } + /** + * Throws the last error as a RuntimeException. + * + * @throws RuntimeException Based on the last error code and string. + */ + public function throwLastError(): never { + throw new RuntimeException((string)$this->getLastErrorString(), $this->getLastErrorCode()); + } + /** * Opens a BLOB field as a resource. * @@ -468,7 +476,7 @@ class SqliteConnection implements DbConnection, DbTransactions { public function getBlobStream(string $table, string $column, int $rowId): mixed { $handle = $this->connection->openBlob($table, $column, $rowId); if(!is_resource($handle)) - throw new RuntimeException((string)$this->getLastErrorString(), $this->getLastErrorCode()); + $this->throwLastError(); return $handle; } @@ -480,63 +488,42 @@ class SqliteConnection implements DbConnection, DbTransactions { public function prepare(string $query): DbStatement { $statement = $this->connection->prepare($query); if($statement === false) - throw new RuntimeException((string)$this->getLastErrorString(), $this->getLastErrorCode()); + $this->throwLastError(); + return new SqliteStatement($this, $statement); } public function query(string $query): DbResult { $result = $this->connection->query($query); if($result === false) - throw new RuntimeException($this->getLastErrorString(), $this->getLastErrorCode()); + $this->throwLastError(); + return new SqliteResult($result); } + /** + * Tries to execute a query but throws an exception if it fails. + * + * @param string $query Command to execute. + * @throws RuntimeException If the command failed to execute. + */ + public function executeThrow(string $query): void { + if(!$this->connection->exec($query)) + $this->throwLastError(); + } + public function execute(string $query): int|string { if(!$this->connection->exec($query)) - throw new RuntimeException($this->getLastErrorString(), $this->getLastErrorCode()); + $this->throwLastError(); + return $this->connection->changes(); } - public function setAutoCommit(bool $state): void { - // there's not really a completely reliable way to set a persistent auto commit disable state - if($state === $this->autoCommit) - return; - $this->autoCommit = $state; - - if($state) { - $this->commit(); - } else { - $this->beginTransaction(); - } - } - - public function beginTransaction(): void { + public function beginTransaction(): DbTransaction { if(!$this->connection->exec('BEGIN;')) - throw new RuntimeException((string)$this->getLastErrorString(), $this->getLastErrorCode()); - } + $this->throwLastError(); - public function commit(): void { - if(!$this->connection->exec('COMMIT;')) - throw new RuntimeException((string)$this->getLastErrorString(), $this->getLastErrorCode()); - if(!$this->autoCommit) - $this->beginTransaction(); - } - - public function rollback(?string $name = null): void { - if(!$this->connection->exec(empty($name) ? 'ROLLBACK;' : "ROLLBACK TO {$name};")) - throw new RuntimeException((string)$this->getLastErrorString(), $this->getLastErrorCode()); - if(!$this->autoCommit) - $this->beginTransaction(); - } - - public function savePoint(string $name): void { - if(!$this->connection->exec("SAVEPOINT {$name};")) - throw new RuntimeException((string)$this->getLastErrorString(), $this->getLastErrorCode()); - } - - public function releaseSavePoint(string $name): void { - if(!$this->connection->exec("RELEASE SAVEPOINT {$name};")) - throw new RuntimeException((string)$this->getLastErrorString(), $this->getLastErrorCode()); + return new SqliteTransaction($this); } public function close(): void { diff --git a/src/Db/Sqlite/SqliteTransaction.php b/src/Db/Sqlite/SqliteTransaction.php new file mode 100644 index 0000000..c02208e --- /dev/null +++ b/src/Db/Sqlite/SqliteTransaction.php @@ -0,0 +1,43 @@ +conn->executeThrow('COMMIT;'); + } + + public function save(string $name): void { + $this->conn->executeThrow(sprintf('SAVEPOINT %s;', SQLite3::escapeString($name))); + } + + public function release(string $name): void { + $this->conn->executeThrow(sprintf('RELEASE SAVEPOINT %s;', SQLite3::escapeString($name))); + } + + public function rollback(?string $name = null): void { + $this->conn->executeThrow( + $name === null + ? 'ROLLBACK;' + : sprintf('ROLLBACK TO SAVEPOINT %s;', SQLite3::escapeString($name)) + ); + } + + public function close(): void {} +}