Browse Source

Add tests for transactions and savepoints

Existing code had subtle bugs; using increment and decrement operators actually makes things easier to understand (for once)
microsub
J. King 7 years ago
parent
commit
f0663e99c3
  1. 12
      lib/Db/AbstractDriver.php
  2. 154
      tests/Db/SQLite3/TestDbDriverSQLite3.php

12
lib/Db/AbstractDriver.php

@ -15,16 +15,14 @@ abstract class AbstractDriver implements Driver {
}
public function begin(): bool {
$this->exec("SAVEPOINT newssync_".($this->transDepth));
$this->transDepth += 1;
$this->exec("SAVEPOINT newssync_".(++$this->transDepth));
return true;
}
public function commit(bool $all = false): bool {
if($this->transDepth==0) return false;
if(!$all) {
$this->exec("RELEASE SAVEPOINT newssync_".($this->transDepth - 1));
$this->transDepth -= 1;
$this->exec("RELEASE SAVEPOINT newssync_".($this->transDepth--));
} else {
$this->exec("COMMIT TRANSACTION");
$this->transDepth = 0;
@ -35,11 +33,9 @@ abstract class AbstractDriver implements Driver {
public function rollback(bool $all = false): bool {
if($this->transDepth==0) return false;
if(!$all) {
$this->exec("ROLLBACK TRANSACTION TO SAVEPOINT newssync_".($this->transDepth - 1));
$this->exec("ROLLBACK TRANSACTION TO SAVEPOINT newssync_".($this->transDepth));
// rollback to savepoint does not collpase the savepoint
$this->commit();
$this->transDepth -= 1;
if($this->transDepth==0) $this->exec("ROLLBACK TRANSACTION");
$this->exec("RELEASE SAVEPOINT newssync_".($this->transDepth--));
} else {
$this->exec("ROLLBACK TRANSACTION");
$this->transDepth = 0;

154
tests/Db/SQLite3/TestDbDriverSQLite3.php

@ -92,4 +92,158 @@ class TestDbDriverSQLite3 extends \PHPUnit\Framework\TestCase {
$this->assertException("engineErrorGeneral", "Db");
$s = $this->drv->prepare("This is an invalid query", "int", "int");
}
function testBeginTransaction() {
$select = "SELECT count(*) FROM test";
$insert = "INSERT INTO test(id) values(null)";
$ch = new \SQLite3($this->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->query($insert);
$this->assertEquals(2, $this->drv->query($select)->getValue());
$this->assertEquals(0, $ch->querySingle($select));
}
function testCommitTransaction() {
$select = "SELECT count(*) FROM test";
$insert = "INSERT INTO test(id) values(null)";
$ch = new \SQLite3($this->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->commit();
$this->assertEquals(1, $this->drv->query($select)->getValue());
$this->assertEquals(1, $ch->querySingle($select));
}
function testRollbackTransaction() {
$select = "SELECT count(*) FROM test";
$insert = "INSERT INTO test(id) values(null)";
$ch = new \SQLite3($this->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->rollback();
$this->assertEquals(0, $this->drv->query($select)->getValue());
$this->assertEquals(0, $ch->querySingle($select));
}
function testBeginChainedTransactions() {
$select = "SELECT count(*) FROM test";
$insert = "INSERT INTO test(id) values(null)";
$ch = new \SQLite3($this->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));
}
function testCommitChainedTransactions() {
$select = "SELECT count(*) FROM test";
$insert = "INSERT INTO test(id) values(null)";
$ch = new \SQLite3($this->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();
$this->assertEquals(0, $ch->querySingle($select));
$this->drv->commit();
$this->assertEquals(2, $ch->querySingle($select));
}
function testRollbackChainedTransactions() {
$select = "SELECT count(*) FROM test";
$insert = "INSERT INTO test(id) values(null)";
$ch = new \SQLite3($this->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();
$this->assertEquals(1, $this->drv->query($select)->getValue());
$this->assertEquals(0, $ch->querySingle($select));
$this->drv->rollback();
$this->assertEquals(0, $this->drv->query($select)->getValue());
$this->assertEquals(0, $ch->querySingle($select));
}
function testPartiallyRollbackChainedTransactions() {
$select = "SELECT count(*) FROM test";
$insert = "INSERT INTO test(id) values(null)";
$ch = new \SQLite3($this->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();
$this->assertEquals(1, $this->drv->query($select)->getValue());
$this->assertEquals(0, $ch->querySingle($select));
$this->drv->commit();
$this->assertEquals(1, $this->drv->query($select)->getValue());
$this->assertEquals(1, $ch->querySingle($select));
}
function testFullyRollbackChainedTransactions() {
$select = "SELECT count(*) FROM test";
$insert = "INSERT INTO test(id) values(null)";
$ch = new \SQLite3($this->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($this->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));
}
}
Loading…
Cancel
Save