mirror of
https://code.mensbeam.com/MensBeam/Arsse.git
synced 2024-12-22 21:22:40 +00:00
Change transactions to auto-rollback on exceptions
This commit is contained in:
parent
c2a7ad7b19
commit
2083c6e397
7 changed files with 185 additions and 177 deletions
|
@ -458,7 +458,7 @@ class Database {
|
||||||
public function subscriptionPropertiesSet(string $user, int $id, array $data): bool {
|
public function subscriptionPropertiesSet(string $user, int $id, array $data): bool {
|
||||||
if(!Data::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
|
if(!Data::$user->authorize($user, __FUNCTION__)) throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
|
||||||
if(!$this->userExists($user)) throw new User\Exception("doesNotExist", ["user" => $user, "action" => __FUNCTION__]);
|
if(!$this->userExists($user)) throw new User\Exception("doesNotExist", ["user" => $user, "action" => __FUNCTION__]);
|
||||||
$this->db->begin();
|
$tr = $this->db->begin();
|
||||||
if(!$this->db->prepare("SELECT count(*) from arsse_subscriptions where owner is ? and id is ?", "str", "int")->run($user, $id)->getValue()) {
|
if(!$this->db->prepare("SELECT count(*) from arsse_subscriptions where owner is ? and id is ?", "str", "int")->run($user, $id)->getValue()) {
|
||||||
// if the ID doesn't exist or doesn't belong to the user, throw an exception
|
// if the ID doesn't exist or doesn't belong to the user, throw an exception
|
||||||
throw new Db\ExceptionInput("idMissing", ["action" => __FUNCTION__, "field" => "feed", 'id' => $id]);
|
throw new Db\ExceptionInput("idMissing", ["action" => __FUNCTION__, "field" => "feed", 'id' => $id]);
|
||||||
|
@ -470,12 +470,13 @@ class Database {
|
||||||
'pinned' => "strict bool",
|
'pinned' => "strict bool",
|
||||||
];
|
];
|
||||||
list($setClause, $setTypes, $setValues) = $this->generateSet($data, $valid);
|
list($setClause, $setTypes, $setValues) = $this->generateSet($data, $valid);
|
||||||
return (bool) $this->db->prepare("UPDATE arsse_subscriptions set $setClause where owner is ? and id is ?", $setTypes, "str", "int")->run($setValues, $user, $id)->changes();
|
$out = (bool) $this->db->prepare("UPDATE arsse_subscriptions set $setClause where owner is ? and id is ?", $setTypes, "str", "int")->run($setValues, $user, $id)->changes();
|
||||||
|
$tr->commit();
|
||||||
|
return $out;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function feedUpdate(int $feedID, bool $throwError = false): bool {
|
public function feedUpdate(int $feedID, bool $throwError = false): bool {
|
||||||
$this->db->begin();
|
$tr = $this->db->begin();
|
||||||
try {
|
|
||||||
// check to make sure the feed exists
|
// check to make sure the feed exists
|
||||||
$f = $this->db->prepare('SELECT url, username, password, DATEFORMAT("http", modified) AS lastmodified, etag, err_count FROM arsse_feeds where id is ?', "int")->run($feedID)->getRow();
|
$f = $this->db->prepare('SELECT url, username, password, DATEFORMAT("http", modified) AS lastmodified, etag, err_count FROM arsse_feeds where id is ?', "int")->run($feedID)->getRow();
|
||||||
if(!$f) throw new Db\ExceptionInput("idMissing", ["action" => __FUNCTION__, "field" => "feed", 'id' => $feedID]);
|
if(!$f) throw new Db\ExceptionInput("idMissing", ["action" => __FUNCTION__, "field" => "feed", 'id' => $feedID]);
|
||||||
|
@ -487,7 +488,7 @@ class Database {
|
||||||
if(!$feed->modified) {
|
if(!$feed->modified) {
|
||||||
// if the feed hasn't changed, just compute the next fetch time and record it
|
// if the feed hasn't changed, just compute the next fetch time and record it
|
||||||
$this->db->prepare('UPDATE arsse_feeds SET updated = CURRENT_TIMESTAMP, next_fetch = ? WHERE id is ?', 'datetime', 'int')->run($feed->nextFetch, $feedID);
|
$this->db->prepare('UPDATE arsse_feeds SET updated = CURRENT_TIMESTAMP, next_fetch = ? WHERE id is ?', 'datetime', 'int')->run($feed->nextFetch, $feedID);
|
||||||
$this->db->commit();
|
$tr->commit();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (Feed\Exception $e) {
|
} catch (Feed\Exception $e) {
|
||||||
|
@ -496,12 +497,9 @@ class Database {
|
||||||
'UPDATE arsse_feeds SET updated = CURRENT_TIMESTAMP, next_fetch = ?, err_count = err_count + 1, err_msg = ? WHERE id is ?',
|
'UPDATE arsse_feeds SET updated = CURRENT_TIMESTAMP, next_fetch = ?, err_count = err_count + 1, err_msg = ? WHERE id is ?',
|
||||||
'datetime', 'str', 'int'
|
'datetime', 'str', 'int'
|
||||||
)->run(Feed::nextFetchOnError($f['err_count']), $e->getMessage(),$feedID);
|
)->run(Feed::nextFetchOnError($f['err_count']), $e->getMessage(),$feedID);
|
||||||
$this->db->commit();
|
$tr->commit();
|
||||||
if($throwError) throw $e;
|
if($throwError) throw $e;
|
||||||
return false;
|
return false;
|
||||||
} catch(\Throwable $e) {
|
|
||||||
$this->db->rollback();
|
|
||||||
throw $e;
|
|
||||||
}
|
}
|
||||||
//prepare the necessary statements to perform the update
|
//prepare the necessary statements to perform the update
|
||||||
if(sizeof($feed->newItems) || sizeof($feed->changedItems)) {
|
if(sizeof($feed->newItems) || sizeof($feed->changedItems)) {
|
||||||
|
@ -577,11 +575,7 @@ class Database {
|
||||||
$feed->nextFetch,
|
$feed->nextFetch,
|
||||||
$feedID
|
$feedID
|
||||||
);
|
);
|
||||||
} catch(\Throwable $e) {
|
$tr->commit();
|
||||||
$this->db->rollback();
|
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
$this->db->commit();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,12 +14,16 @@ abstract class AbstractDriver implements Driver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function begin(): bool {
|
public function begin(): Transaction {
|
||||||
|
return new Transaction($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function savepointCreate(): bool {
|
||||||
$this->exec("SAVEPOINT arsse_".(++$this->transDepth));
|
$this->exec("SAVEPOINT arsse_".(++$this->transDepth));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function commit(bool $all = false): bool {
|
public function savepointRelease(bool $all = false): bool {
|
||||||
if($this->transDepth==0) return false;
|
if($this->transDepth==0) return false;
|
||||||
if(!$all) {
|
if(!$all) {
|
||||||
$this->exec("RELEASE SAVEPOINT arsse_".($this->transDepth--));
|
$this->exec("RELEASE SAVEPOINT arsse_".($this->transDepth--));
|
||||||
|
@ -30,7 +34,7 @@ abstract class AbstractDriver implements Driver {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rollback(bool $all = false): bool {
|
public function savepointUndo(bool $all = false): bool {
|
||||||
if($this->transDepth==0) return false;
|
if($this->transDepth==0) return false;
|
||||||
if(!$all) {
|
if(!$all) {
|
||||||
$this->exec("ROLLBACK TRANSACTION TO SAVEPOINT arsse_".($this->transDepth));
|
$this->exec("ROLLBACK TRANSACTION TO SAVEPOINT arsse_".($this->transDepth));
|
||||||
|
|
|
@ -8,12 +8,14 @@ interface Driver {
|
||||||
static function driverName(): string;
|
static function driverName(): string;
|
||||||
// returns the version of the scheme of the opened database; if uninitialized should return 0
|
// returns the version of the scheme of the opened database; if uninitialized should return 0
|
||||||
function schemaVersion(): int;
|
function schemaVersion(): int;
|
||||||
// begin a real or synthetic transactions, with real or synthetic nesting
|
// return a Transaction object
|
||||||
function begin(): bool;
|
function begin(): Transaction;
|
||||||
// commit either the latest or all pending nested transactions; use of this method should assume a partial commit is a no-op
|
// manually begin a real or synthetic transactions, with real or synthetic nesting
|
||||||
function commit(bool $all = false): bool;
|
function savepointCreate(): bool;
|
||||||
// rollback either the latest or all pending nested transactions; use of this method should assume a partial rollback will not work
|
// manually commit either the latest or all pending nested transactions
|
||||||
function rollback(bool $all = false): bool;
|
function savepointRelease(bool $all = false): bool;
|
||||||
|
// manually rollback either the latest or all pending nested transactions
|
||||||
|
function savepointUndo(bool $all = false): bool;
|
||||||
// attempt to advise other processes that they should not attempt to access the database; used during live upgrades
|
// attempt to advise other processes that they should not attempt to access the database; used during live upgrades
|
||||||
function lock(): bool;
|
function lock(): bool;
|
||||||
function unlock(): bool;
|
function unlock(): bool;
|
||||||
|
|
|
@ -69,9 +69,9 @@ class Driver extends \JKingWeb\Arsse\Db\AbstractDriver {
|
||||||
$sep = \DIRECTORY_SEPARATOR;
|
$sep = \DIRECTORY_SEPARATOR;
|
||||||
$path = Data::$conf->dbSchemaBase.$sep."SQLite3".$sep;
|
$path = Data::$conf->dbSchemaBase.$sep."SQLite3".$sep;
|
||||||
$this->lock();
|
$this->lock();
|
||||||
$this->begin();
|
$this->savepointCreate();
|
||||||
for($a = $ver; $a < $to; $a++) {
|
for($a = $ver; $a < $to; $a++) {
|
||||||
$this->begin();
|
$this->savepointCreate();
|
||||||
try {
|
try {
|
||||||
$file = $path.$a.".sql";
|
$file = $path.$a.".sql";
|
||||||
if(!file_exists($file)) throw new Exception("updateFileMissing", ['file' => $file, 'driver_name' => $this->driverName(), 'current' => $a]);
|
if(!file_exists($file)) throw new Exception("updateFileMissing", ['file' => $file, 'driver_name' => $this->driverName(), 'current' => $a]);
|
||||||
|
@ -86,17 +86,17 @@ class Driver extends \JKingWeb\Arsse\Db\AbstractDriver {
|
||||||
if($this->schemaVersion() != $a+1) throw new Exception("updateFileIncomplete", ['file' => $file, 'driver_name' => $this->driverName(), 'current' => $a]);
|
if($this->schemaVersion() != $a+1) throw new Exception("updateFileIncomplete", ['file' => $file, 'driver_name' => $this->driverName(), 'current' => $a]);
|
||||||
} catch(\Throwable $e) {
|
} catch(\Throwable $e) {
|
||||||
// undo any partial changes from the failed update
|
// undo any partial changes from the failed update
|
||||||
$this->rollback();
|
$this->savepointUndo();
|
||||||
$this->unlock();
|
$this->unlock();
|
||||||
// commit any successful updates if updating by more than one version
|
// commit any successful updates if updating by more than one version
|
||||||
$this->commit(true);
|
$this->savepointRelease(true);
|
||||||
// throw the error received
|
// throw the error received
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
$this->commit();
|
$this->savepointRelease();
|
||||||
}
|
}
|
||||||
$this->unlock();
|
$this->unlock();
|
||||||
$this->commit();
|
$this->savepointRelease();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
44
lib/Db/Transaction.php
Normal file
44
lib/Db/Transaction.php
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
declare(strict_types=1);
|
||||||
|
namespace JKingWeb\Arsse\Db;
|
||||||
|
|
||||||
|
class Transaction {
|
||||||
|
protected $pending = false;
|
||||||
|
protected $drv;
|
||||||
|
|
||||||
|
function __construct(Driver $drv) {
|
||||||
|
$drv->savepointCreate();
|
||||||
|
$this->drv = $drv;
|
||||||
|
$this->pending = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function __destruct() {
|
||||||
|
if($this->pending) {
|
||||||
|
try {
|
||||||
|
$this->drv->savepointUndo();
|
||||||
|
} catch(\Throwable $e) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function commit(): bool {
|
||||||
|
if($this->pending) {
|
||||||
|
$this->drv->savepointRelease();
|
||||||
|
$this->pending = false;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function rollback(): bool {
|
||||||
|
if($this->pending) {
|
||||||
|
$this->drv->savepointUndo();
|
||||||
|
$this->pending = false;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -106,7 +106,7 @@ class TestDbDriverSQLite3 extends \PHPUnit\Framework\TestCase {
|
||||||
$insert = "INSERT INTO test(id) values(null)";
|
$insert = "INSERT INTO test(id) values(null)";
|
||||||
$ch = new \SQLite3(Data::$conf->dbSQLite3File);
|
$ch = new \SQLite3(Data::$conf->dbSQLite3File);
|
||||||
$this->drv->exec("CREATE TABLE test(id integer primary key)");
|
$this->drv->exec("CREATE TABLE test(id integer primary key)");
|
||||||
$this->drv->begin();
|
$tr = $this->drv->begin();
|
||||||
$this->drv->query($insert);
|
$this->drv->query($insert);
|
||||||
$this->assertEquals(1, $this->drv->query($select)->getValue());
|
$this->assertEquals(1, $this->drv->query($select)->getValue());
|
||||||
$this->assertEquals(0, $ch->querySingle($select));
|
$this->assertEquals(0, $ch->querySingle($select));
|
||||||
|
@ -120,11 +120,11 @@ class TestDbDriverSQLite3 extends \PHPUnit\Framework\TestCase {
|
||||||
$insert = "INSERT INTO test(id) values(null)";
|
$insert = "INSERT INTO test(id) values(null)";
|
||||||
$ch = new \SQLite3(Data::$conf->dbSQLite3File);
|
$ch = new \SQLite3(Data::$conf->dbSQLite3File);
|
||||||
$this->drv->exec("CREATE TABLE test(id integer primary key)");
|
$this->drv->exec("CREATE TABLE test(id integer primary key)");
|
||||||
$this->drv->begin();
|
$tr = $this->drv->begin();
|
||||||
$this->drv->query($insert);
|
$this->drv->query($insert);
|
||||||
$this->assertEquals(1, $this->drv->query($select)->getValue());
|
$this->assertEquals(1, $this->drv->query($select)->getValue());
|
||||||
$this->assertEquals(0, $ch->querySingle($select));
|
$this->assertEquals(0, $ch->querySingle($select));
|
||||||
$this->drv->commit();
|
$tr->commit();
|
||||||
$this->assertEquals(1, $this->drv->query($select)->getValue());
|
$this->assertEquals(1, $this->drv->query($select)->getValue());
|
||||||
$this->assertEquals(1, $ch->querySingle($select));
|
$this->assertEquals(1, $ch->querySingle($select));
|
||||||
}
|
}
|
||||||
|
@ -134,11 +134,11 @@ class TestDbDriverSQLite3 extends \PHPUnit\Framework\TestCase {
|
||||||
$insert = "INSERT INTO test(id) values(null)";
|
$insert = "INSERT INTO test(id) values(null)";
|
||||||
$ch = new \SQLite3(Data::$conf->dbSQLite3File);
|
$ch = new \SQLite3(Data::$conf->dbSQLite3File);
|
||||||
$this->drv->exec("CREATE TABLE test(id integer primary key)");
|
$this->drv->exec("CREATE TABLE test(id integer primary key)");
|
||||||
$this->drv->begin();
|
$tr = $this->drv->begin();
|
||||||
$this->drv->query($insert);
|
$this->drv->query($insert);
|
||||||
$this->assertEquals(1, $this->drv->query($select)->getValue());
|
$this->assertEquals(1, $this->drv->query($select)->getValue());
|
||||||
$this->assertEquals(0, $ch->querySingle($select));
|
$this->assertEquals(0, $ch->querySingle($select));
|
||||||
$this->drv->rollback();
|
$tr->rollback();
|
||||||
$this->assertEquals(0, $this->drv->query($select)->getValue());
|
$this->assertEquals(0, $this->drv->query($select)->getValue());
|
||||||
$this->assertEquals(0, $ch->querySingle($select));
|
$this->assertEquals(0, $ch->querySingle($select));
|
||||||
}
|
}
|
||||||
|
@ -148,11 +148,11 @@ class TestDbDriverSQLite3 extends \PHPUnit\Framework\TestCase {
|
||||||
$insert = "INSERT INTO test(id) values(null)";
|
$insert = "INSERT INTO test(id) values(null)";
|
||||||
$ch = new \SQLite3(Data::$conf->dbSQLite3File);
|
$ch = new \SQLite3(Data::$conf->dbSQLite3File);
|
||||||
$this->drv->exec("CREATE TABLE test(id integer primary key)");
|
$this->drv->exec("CREATE TABLE test(id integer primary key)");
|
||||||
$this->drv->begin();
|
$tr1 = $this->drv->begin();
|
||||||
$this->drv->query($insert);
|
$this->drv->query($insert);
|
||||||
$this->assertEquals(1, $this->drv->query($select)->getValue());
|
$this->assertEquals(1, $this->drv->query($select)->getValue());
|
||||||
$this->assertEquals(0, $ch->querySingle($select));
|
$this->assertEquals(0, $ch->querySingle($select));
|
||||||
$this->drv->begin();
|
$tr2 = $this->drv->begin();
|
||||||
$this->drv->query($insert);
|
$this->drv->query($insert);
|
||||||
$this->assertEquals(2, $this->drv->query($select)->getValue());
|
$this->assertEquals(2, $this->drv->query($select)->getValue());
|
||||||
$this->assertEquals(0, $ch->querySingle($select));
|
$this->assertEquals(0, $ch->querySingle($select));
|
||||||
|
@ -163,17 +163,17 @@ class TestDbDriverSQLite3 extends \PHPUnit\Framework\TestCase {
|
||||||
$insert = "INSERT INTO test(id) values(null)";
|
$insert = "INSERT INTO test(id) values(null)";
|
||||||
$ch = new \SQLite3(Data::$conf->dbSQLite3File);
|
$ch = new \SQLite3(Data::$conf->dbSQLite3File);
|
||||||
$this->drv->exec("CREATE TABLE test(id integer primary key)");
|
$this->drv->exec("CREATE TABLE test(id integer primary key)");
|
||||||
$this->drv->begin();
|
$tr1 = $this->drv->begin();
|
||||||
$this->drv->query($insert);
|
$this->drv->query($insert);
|
||||||
$this->assertEquals(1, $this->drv->query($select)->getValue());
|
$this->assertEquals(1, $this->drv->query($select)->getValue());
|
||||||
$this->assertEquals(0, $ch->querySingle($select));
|
$this->assertEquals(0, $ch->querySingle($select));
|
||||||
$this->drv->begin();
|
$tr2 = $this->drv->begin();
|
||||||
$this->drv->query($insert);
|
$this->drv->query($insert);
|
||||||
$this->assertEquals(2, $this->drv->query($select)->getValue());
|
$this->assertEquals(2, $this->drv->query($select)->getValue());
|
||||||
$this->assertEquals(0, $ch->querySingle($select));
|
$this->assertEquals(0, $ch->querySingle($select));
|
||||||
$this->drv->commit();
|
$tr2->commit();
|
||||||
$this->assertEquals(0, $ch->querySingle($select));
|
$this->assertEquals(0, $ch->querySingle($select));
|
||||||
$this->drv->commit();
|
$tr1->commit();
|
||||||
$this->assertEquals(2, $ch->querySingle($select));
|
$this->assertEquals(2, $ch->querySingle($select));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,18 +182,18 @@ class TestDbDriverSQLite3 extends \PHPUnit\Framework\TestCase {
|
||||||
$insert = "INSERT INTO test(id) values(null)";
|
$insert = "INSERT INTO test(id) values(null)";
|
||||||
$ch = new \SQLite3(Data::$conf->dbSQLite3File);
|
$ch = new \SQLite3(Data::$conf->dbSQLite3File);
|
||||||
$this->drv->exec("CREATE TABLE test(id integer primary key)");
|
$this->drv->exec("CREATE TABLE test(id integer primary key)");
|
||||||
$this->drv->begin();
|
$tr1 = $this->drv->begin();
|
||||||
$this->drv->query($insert);
|
$this->drv->query($insert);
|
||||||
$this->assertEquals(1, $this->drv->query($select)->getValue());
|
$this->assertEquals(1, $this->drv->query($select)->getValue());
|
||||||
$this->assertEquals(0, $ch->querySingle($select));
|
$this->assertEquals(0, $ch->querySingle($select));
|
||||||
$this->drv->begin();
|
$tr2 = $this->drv->begin();
|
||||||
$this->drv->query($insert);
|
$this->drv->query($insert);
|
||||||
$this->assertEquals(2, $this->drv->query($select)->getValue());
|
$this->assertEquals(2, $this->drv->query($select)->getValue());
|
||||||
$this->assertEquals(0, $ch->querySingle($select));
|
$this->assertEquals(0, $ch->querySingle($select));
|
||||||
$this->drv->rollback();
|
$tr2->rollback();
|
||||||
$this->assertEquals(1, $this->drv->query($select)->getValue());
|
$this->assertEquals(1, $this->drv->query($select)->getValue());
|
||||||
$this->assertEquals(0, $ch->querySingle($select));
|
$this->assertEquals(0, $ch->querySingle($select));
|
||||||
$this->drv->rollback();
|
$tr1->rollback();
|
||||||
$this->assertEquals(0, $this->drv->query($select)->getValue());
|
$this->assertEquals(0, $this->drv->query($select)->getValue());
|
||||||
$this->assertEquals(0, $ch->querySingle($select));
|
$this->assertEquals(0, $ch->querySingle($select));
|
||||||
}
|
}
|
||||||
|
@ -203,58 +203,22 @@ class TestDbDriverSQLite3 extends \PHPUnit\Framework\TestCase {
|
||||||
$insert = "INSERT INTO test(id) values(null)";
|
$insert = "INSERT INTO test(id) values(null)";
|
||||||
$ch = new \SQLite3(Data::$conf->dbSQLite3File);
|
$ch = new \SQLite3(Data::$conf->dbSQLite3File);
|
||||||
$this->drv->exec("CREATE TABLE test(id integer primary key)");
|
$this->drv->exec("CREATE TABLE test(id integer primary key)");
|
||||||
$this->drv->begin();
|
$tr1 = $this->drv->begin();
|
||||||
$this->drv->query($insert);
|
$this->drv->query($insert);
|
||||||
$this->assertEquals(1, $this->drv->query($select)->getValue());
|
$this->assertEquals(1, $this->drv->query($select)->getValue());
|
||||||
$this->assertEquals(0, $ch->querySingle($select));
|
$this->assertEquals(0, $ch->querySingle($select));
|
||||||
$this->drv->begin();
|
$tr2 = $this->drv->begin();
|
||||||
$this->drv->query($insert);
|
$this->drv->query($insert);
|
||||||
$this->assertEquals(2, $this->drv->query($select)->getValue());
|
$this->assertEquals(2, $this->drv->query($select)->getValue());
|
||||||
$this->assertEquals(0, $ch->querySingle($select));
|
$this->assertEquals(0, $ch->querySingle($select));
|
||||||
$this->drv->rollback();
|
$tr2->rollback();
|
||||||
$this->assertEquals(1, $this->drv->query($select)->getValue());
|
$this->assertEquals(1, $this->drv->query($select)->getValue());
|
||||||
$this->assertEquals(0, $ch->querySingle($select));
|
$this->assertEquals(0, $ch->querySingle($select));
|
||||||
$this->drv->commit();
|
$tr1->commit();
|
||||||
$this->assertEquals(1, $this->drv->query($select)->getValue());
|
$this->assertEquals(1, $this->drv->query($select)->getValue());
|
||||||
$this->assertEquals(1, $ch->querySingle($select));
|
$this->assertEquals(1, $ch->querySingle($select));
|
||||||
}
|
}
|
||||||
|
|
||||||
function testFullyRollbackChainedTransactions() {
|
|
||||||
$select = "SELECT count(*) FROM test";
|
|
||||||
$insert = "INSERT INTO test(id) values(null)";
|
|
||||||
$ch = new \SQLite3(Data::$conf->dbSQLite3File);
|
|
||||||
$this->drv->exec("CREATE TABLE test(id integer primary key)");
|
|
||||||
$this->drv->begin();
|
|
||||||
$this->drv->query($insert);
|
|
||||||
$this->assertEquals(1, $this->drv->query($select)->getValue());
|
|
||||||
$this->assertEquals(0, $ch->querySingle($select));
|
|
||||||
$this->drv->begin();
|
|
||||||
$this->drv->query($insert);
|
|
||||||
$this->assertEquals(2, $this->drv->query($select)->getValue());
|
|
||||||
$this->assertEquals(0, $ch->querySingle($select));
|
|
||||||
$this->drv->rollback(true);
|
|
||||||
$this->assertEquals(0, $this->drv->query($select)->getValue());
|
|
||||||
$this->assertEquals(0, $ch->querySingle($select));
|
|
||||||
}
|
|
||||||
|
|
||||||
function testFullyCommitChainedTransactions() {
|
|
||||||
$select = "SELECT count(*) FROM test";
|
|
||||||
$insert = "INSERT INTO test(id) values(null)";
|
|
||||||
$ch = new \SQLite3(Data::$conf->dbSQLite3File);
|
|
||||||
$this->drv->exec("CREATE TABLE test(id integer primary key)");
|
|
||||||
$this->drv->begin();
|
|
||||||
$this->drv->query($insert);
|
|
||||||
$this->assertEquals(1, $this->drv->query($select)->getValue());
|
|
||||||
$this->assertEquals(0, $ch->querySingle($select));
|
|
||||||
$this->drv->begin();
|
|
||||||
$this->drv->query($insert);
|
|
||||||
$this->assertEquals(2, $this->drv->query($select)->getValue());
|
|
||||||
$this->assertEquals(0, $ch->querySingle($select));
|
|
||||||
$this->drv->commit(true);
|
|
||||||
$this->assertEquals(2, $this->drv->query($select)->getValue());
|
|
||||||
$this->assertEquals(2, $ch->querySingle($select));
|
|
||||||
}
|
|
||||||
|
|
||||||
function testFetchSchemaVersion() {
|
function testFetchSchemaVersion() {
|
||||||
$this->assertSame(0, $this->drv->schemaVersion());
|
$this->assertSame(0, $this->drv->schemaVersion());
|
||||||
$this->drv->exec("PRAGMA user_version=1");
|
$this->drv->exec("PRAGMA user_version=1");
|
||||||
|
|
|
@ -52,7 +52,7 @@ trait Setup {
|
||||||
}
|
}
|
||||||
|
|
||||||
function primeDatabase(array $data): bool {
|
function primeDatabase(array $data): bool {
|
||||||
$this->drv->begin();
|
$tr = $this->drv->begin();
|
||||||
foreach($data as $table => $info) {
|
foreach($data as $table => $info) {
|
||||||
$cols = implode(",", array_keys($info['columns']));
|
$cols = implode(",", array_keys($info['columns']));
|
||||||
$bindings = array_values($info['columns']);
|
$bindings = array_values($info['columns']);
|
||||||
|
@ -62,7 +62,7 @@ trait Setup {
|
||||||
$this->assertEquals(1, $s->runArray($row)->changes());
|
$this->assertEquals(1, $s->runArray($row)->changes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->drv->commit();
|
$tr->commit();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue