diff --git a/tests/cases/Db/BaseDriver.php b/tests/cases/Db/BaseDriver.php index 46244080..e918fa99 100644 --- a/tests/cases/Db/BaseDriver.php +++ b/tests/cases/Db/BaseDriver.php @@ -11,51 +11,69 @@ use JKingWeb\Arsse\Db\Result; use JKingWeb\Arsse\Test\DatabaseInformation; abstract class BaseDriver extends \JKingWeb\Arsse\Test\AbstractTest { + protected static $dbInfo; + protected static $interface; protected $drv; - protected $interface; protected $create; protected $lock; protected $setVersion; - protected $conf = [ + protected static $conf = [ 'dbTimeoutExec' => 0.5, 'dbSQLite3Timeout' => 0, + //'dbSQLite3File' => "(temporary file)", ]; + + public static function setUpBeforeClass() { + // establish a clean baseline + static::clearData(); + static::$dbInfo = new DatabaseInformation(static::$implementation); + static::setConf(static::$conf); + static::$interface = (static::$dbInfo->interfaceConstructor)(); + } public function setUp() { self::clearData(); - self::setConf($this->conf); - $info = new DatabaseInformation($this->implementation); - $this->interface = ($info->interfaceConstructor)(); - if (!$this->interface) { - $this->markTestSkipped("$this->implementation database driver not available"); + self::setConf(static::$conf); + if (!static::$interface) { + $this->markTestSkipped(static::$implementation." database driver not available"); } - $this->drv = new $info->driverClass; - $this->exec("DROP TABLE IF EXISTS arsse_test"); - $this->exec("DROP TABLE IF EXISTS arsse_meta"); - $this->exec("CREATE TABLE arsse_meta(key varchar(255) primary key not null, value text)"); - $this->exec("INSERT INTO arsse_meta(key,value) values('schema_version','0')"); + // completely clear the database and ensure the schema version can easily be altered + (static::$dbInfo->razeFunction)(static::$interface, [ + "CREATE TABLE arsse_meta(key varchar(255) primary key not null, value text)", + "INSERT INTO arsse_meta(key,value) values('schema_version','0')", + ]); + // construct a fresh driver for each test + $this->drv = new static::$dbInfo->driverClass; } public function tearDown() { - self::clearData(); + // deconstruct the driver unset($this->drv); - try { - $this->exec("ROLLBACK"); - } catch(\Throwable $e) { + if (static::$interface) { + // completely clear the database + (static::$dbInfo->razeFunction)(static::$interface); } - $this->exec("DROP TABLE IF EXISTS arsse_meta"); - $this->exec("DROP TABLE IF EXISTS arsse_test"); + self::clearData(); } - protected function exec(string $q): bool { + public static function tearDownAfterClass() { + static::$implementation = null; + static::$dbInfo = null; + self::clearData(); + } + + protected function exec($q): bool { // PDO implementation - $this->interface->exec($q); + $q = (!is_array($q)) ? [$q] : $q; + foreach ($q as $query) { + static::$interface->exec((string) $query); + } return true; } protected function query(string $q) { // PDO implementation - return $this->interface->query($q)->fetchColumn(); + return static::$interface->query($q)->fetchColumn(); } # TESTS @@ -87,7 +105,8 @@ abstract class BaseDriver extends \JKingWeb\Arsse\Test\AbstractTest { $this->exec($this->create); $this->exec($this->lock); $this->assertException("general", "Db", "ExceptionTimeout"); - $this->drv->exec($this->lock); + $lock = is_array($this->lock) ? implode("; ",$this->lock) : $this->lock; + $this->drv->exec($lock); } public function testExecConstraintViolation() { @@ -115,7 +134,8 @@ abstract class BaseDriver extends \JKingWeb\Arsse\Test\AbstractTest { $this->exec($this->create); $this->exec($this->lock); $this->assertException("general", "Db", "ExceptionTimeout"); - $this->drv->exec($this->lock); + $lock = is_array($this->lock) ? implode("; ",$this->lock) : $this->lock; + $this->drv->exec($lock); } public function testQueryConstraintViolation() { @@ -342,12 +362,20 @@ abstract class BaseDriver extends \JKingWeb\Arsse\Test\AbstractTest { $this->assertSame(1, $this->drv->schemaVersion()); $this->drv->exec(str_replace("#", "2", $this->setVersion)); $this->assertSame(2, $this->drv->schemaVersion()); + // SQLite is unaffected by the removal of the metadata table; other backends are + // in neither case should a query for the schema version produce an error, however + $this->exec("DROP TABLE IF EXISTS arsse_meta"); + $exp = (static::$dbInfo->backend == "SQLite 3") ? 2 : 0; + $this->assertSame($exp, $this->drv->schemaVersion()); } public function testLockTheDatabase() { + // PostgreSQL doesn't actually lock the whole database, only the metadata table + // normally the application will first query this table to ensure the schema version is correct, + // so the effect is usually the same $this->drv->savepointCreate(true); $this->assertException(); - $this->exec($this->create); + $this->exec(str_replace("#", "3", $this->setVersion)); } public function testUnlockTheDatabase() { @@ -355,6 +383,6 @@ abstract class BaseDriver extends \JKingWeb\Arsse\Test\AbstractTest { $this->drv->savepointRelease(); $this->drv->savepointCreate(true); $this->drv->savepointUndo(); - $this->assertTrue($this->exec($this->create)); + $this->assertTrue($this->exec(str_replace("#", "3", $this->setVersion))); } } diff --git a/tests/cases/Db/BaseResult.php b/tests/cases/Db/BaseResult.php index 96dae042..de1ddf22 100644 --- a/tests/cases/Db/BaseResult.php +++ b/tests/cases/Db/BaseResult.php @@ -10,29 +10,45 @@ use JKingWeb\Arsse\Db\Result; use JKingWeb\Arsse\Test\DatabaseInformation; abstract class BaseResult extends \JKingWeb\Arsse\Test\AbstractTest { + protected static $dbInfo; + protected static $interface; protected $resultClass; protected $stringOutput; - protected $interface; - abstract protected function exec(string $q); abstract protected function makeResult(string $q): array; + public static function setUpBeforeClass() { + // establish a clean baseline + static::clearData(); + static::$dbInfo = new DatabaseInformation(static::$implementation); + static::setConf(); + static::$interface = (static::$dbInfo->interfaceConstructor)(); + } + public function setUp() { self::clearData(); self::setConf(); - $info = new DatabaseInformation($this->implementation); - $this->interface = ($info->interfaceConstructor)(); - if (!$this->interface) { - $this->markTestSkipped("$this->implementation database driver not available"); + if (!static::$interface) { + $this->markTestSkipped(static::$implementation." database driver not available"); } - $this->resultClass = $info->resultClass; - $this->stringOutput = $info->stringOutput; - $this->exec("DROP TABLE IF EXISTS arsse_meta"); + // completely clear the database + (static::$dbInfo->razeFunction)(static::$interface); + $this->resultClass = static::$dbInfo->resultClass; + $this->stringOutput = static::$dbInfo->stringOutput; } public function tearDown() { + if (static::$interface) { + // completely clear the database + (static::$dbInfo->razeFunction)(static::$interface); + } + self::clearData(); + } + + public static function tearDownAfterClass() { + static::$implementation = null; + static::$dbInfo = null; self::clearData(); - $this->exec("DROP TABLE IF EXISTS arsse_meta"); } public function testConstructResult() { diff --git a/tests/cases/Db/BaseStatement.php b/tests/cases/Db/BaseStatement.php index 4369f7ac..c7da01ee 100644 --- a/tests/cases/Db/BaseStatement.php +++ b/tests/cases/Db/BaseStatement.php @@ -10,29 +10,45 @@ use JKingWeb\Arsse\Db\Statement; use JKingWeb\Arsse\Test\DatabaseInformation; abstract class BaseStatement extends \JKingWeb\Arsse\Test\AbstractTest { + protected static $dbInfo; + protected static $interface; protected $statementClass; protected $stringOutput; - protected $interface; - abstract protected function exec(string $q); abstract protected function makeStatement(string $q, array $types = []): array; abstract protected function decorateTypeSyntax(string $value, string $type): string; + public static function setUpBeforeClass() { + // establish a clean baseline + static::clearData(); + static::$dbInfo = new DatabaseInformation(static::$implementation); + static::setConf(); + static::$interface = (static::$dbInfo->interfaceConstructor)(); + } + public function setUp() { self::clearData(); self::setConf(); - $info = new DatabaseInformation($this->implementation); - $this->interface = ($info->interfaceConstructor)(); - if (!$this->interface) { - $this->markTestSkipped("$this->implementation database driver not available"); + if (!static::$interface) { + $this->markTestSkipped(static::$implementation." database driver not available"); } - $this->statementClass = $info->statementClass; - $this->stringOutput = $info->stringOutput; - $this->exec("DROP TABLE IF EXISTS arsse_meta"); + // completely clear the database + (static::$dbInfo->razeFunction)(static::$interface); + $this->statementClass = static::$dbInfo->statementClass; + $this->stringOutput = static::$dbInfo->stringOutput; } public function tearDown() { - $this->exec("DROP TABLE IF EXISTS arsse_meta"); + if (static::$interface) { + // completely clear the database + (static::$dbInfo->razeFunction)(static::$interface); + } + self::clearData(); + } + + public static function tearDownAfterClass() { + static::$implementation = null; + static::$dbInfo = null; self::clearData(); } @@ -56,7 +72,7 @@ abstract class BaseStatement extends \JKingWeb\Arsse\Test\AbstractTest { /** @dataProvider provideBinaryBindings */ public function testHandleBinaryData($value, string $type, string $exp) { - if (in_array($this->implementation, ["PostgreSQL", "PDO PostgreSQL"])) { + if (in_array(static::$implementation, ["PostgreSQL", "PDO PostgreSQL"])) { $this->markTestSkipped("Correct handling of binary data with PostgreSQL is currently unknown"); } if ($exp=="null") { diff --git a/tests/cases/Db/PostgreSQL/TestDatabase.php b/tests/cases/Db/PostgreSQL/TestDatabase.php new file mode 100644 index 00000000..5ba3d04d --- /dev/null +++ b/tests/cases/Db/PostgreSQL/TestDatabase.php @@ -0,0 +1,19 @@ + + * @covers \JKingWeb\Arsse\Misc\Query + */ +class TestDatabase extends \JKingWeb\Arsse\TestCase\Database\Base { + protected static $implementation = "PDO PostgreSQL"; + + protected function nextID(string $table): int { + return static::$drv->query("SELECT select cast(last_value as bigint) + 1 from pg_sequences where sequencename = '{$table}_id_seq'")->getValue(); + } +} diff --git a/tests/cases/Db/PostgreSQL/TestDriver.php b/tests/cases/Db/PostgreSQL/TestDriver.php index 497488f7..63e73c6b 100644 --- a/tests/cases/Db/PostgreSQL/TestDriver.php +++ b/tests/cases/Db/PostgreSQL/TestDriver.php @@ -11,13 +11,8 @@ namespace JKingWeb\Arsse\TestCase\Db\PostgreSQL; * @covers \JKingWeb\Arsse\Db\PDODriver * @covers \JKingWeb\Arsse\Db\PDOError */ class TestDriver extends \JKingWeb\Arsse\TestCase\Db\BaseDriver { - protected $implementation = "PDO PostgreSQL"; + protected static $implementation = "PDO PostgreSQL"; protected $create = "CREATE TABLE arsse_test(id bigserial primary key)"; - protected $lock = "BEGIN; LOCK TABLE arsse_test IN EXCLUSIVE MODE NOWAIT"; + protected $lock = ["BEGIN", "LOCK TABLE arsse_test IN EXCLUSIVE MODE NOWAIT"]; protected $setVersion = "UPDATE arsse_meta set value = '#' where key = 'schema_version'"; - - public function tearDown() { - parent::tearDown(); - unset($this->interface); - } } diff --git a/tests/cases/Db/PostgreSQL/TestStatement.php b/tests/cases/Db/PostgreSQL/TestStatement.php index 2c8586fc..cfa42b47 100644 --- a/tests/cases/Db/PostgreSQL/TestStatement.php +++ b/tests/cases/Db/PostgreSQL/TestStatement.php @@ -10,19 +10,10 @@ namespace JKingWeb\Arsse\TestCase\Db\PostgreSQL; * @covers \JKingWeb\Arsse\Db\PDOStatement * @covers \JKingWeb\Arsse\Db\PDOError */ class TestStatement extends \JKingWeb\Arsse\TestCase\Db\BaseStatement { - protected $implementation = "PDO PostgreSQL"; - - public function tearDown() { - parent::tearDown(); - unset($this->interface); - } - - protected function exec(string $q) { - $this->interface->exec($q); - } + protected static $implementation = "PDO PostgreSQL"; protected function makeStatement(string $q, array $types = []): array { - return [$this->interface, $this->interface->prepare($q), $types]; + return [static::$interface, static::$interface->prepare($q), $types]; } protected function decorateTypeSyntax(string $value, string $type): string { diff --git a/tests/cases/Db/SQLite3/TestDriver.php b/tests/cases/Db/SQLite3/TestDriver.php index df802106..9b2348a6 100644 --- a/tests/cases/Db/SQLite3/TestDriver.php +++ b/tests/cases/Db/SQLite3/TestDriver.php @@ -10,92 +10,39 @@ namespace JKingWeb\Arsse\TestCase\Db\SQLite3; * @covers \JKingWeb\Arsse\Db\SQLite3\Driver * @covers \JKingWeb\Arsse\Db\SQLite3\ExceptionBuilder */ class TestDriver extends \JKingWeb\Arsse\TestCase\Db\BaseDriver { - protected $implementation = "SQLite 3"; + protected static $implementation = "SQLite 3"; protected $create = "CREATE TABLE arsse_test(id integer primary key)"; protected $lock = "BEGIN EXCLUSIVE TRANSACTION"; protected $setVersion = "PRAGMA user_version=#"; protected static $file; public static function setUpBeforeClass() { - self::$file = tempnam(sys_get_temp_dir(), 'ook'); + // create a temporary database file rather than using a memory database + // some tests require one connection to block another, so a memory database is not suitable + static::$file = tempnam(sys_get_temp_dir(), 'ook'); + static::$conf['dbSQLite3File'] = static::$file; + parent::setUpBeforeclass(); } public static function tearDownAfterClass() { - @unlink(self::$file); - self::$file = null; - } - - public function setUp() { - $this->conf['dbSQLite3File'] = self::$file; - parent::setUp(); - $this->exec("PRAGMA user_version=0"); + if (static::$interface) { + static::$interface->close(); + } + parent::tearDownAfterClass(); + @unlink(static::$file); + static::$file = null; } - public function tearDown() { - parent::tearDown(); - $this->exec("PRAGMA user_version=0"); - $this->interface->close(); - unset($this->interface); - } - - protected function exec(string $q): bool { - $this->interface->exec($q); + protected function exec($q): bool { + // SQLite's implementation coincidentally matches PDO's, but we reproduce it here for correctness' sake + $q = (!is_array($q)) ? [$q] : $q; + foreach ($q as $query) { + static::$interface->exec((string) $query); + } return true; } protected function query(string $q) { - return $this->interface->querySingle($q); - } - - public function provideDrivers() { - self::clearData(); - self::setConf([ - 'dbTimeoutExec' => 0.5, - 'dbSQLite3Timeout' => 0, - 'dbSQLite3File' => tempnam(sys_get_temp_dir(), 'ook'), - ]); - $i = $this->provideDbInterfaces(); - $d = $this->provideDbDrivers(); - $pdoExec = function (string $q) { - $this->interface->exec($q); - return true; - }; - $pdoQuery = function (string $q) { - return $this->interface->query($q)->fetchColumn(); - }; - return [ - 'SQLite 3' => [ - $i['SQLite 3']['interface'], - $d['SQLite 3'], - "CREATE TABLE arsse_test(id integer primary key)", - "BEGIN EXCLUSIVE TRANSACTION", - "PRAGMA user_version=#", - function (string $q) { - $this->interface->exec($q); - return true; - }, - function (string $q) { - return $this->interface->querySingle($q); - }, - ], - 'PDO SQLite 3' => [ - $i['PDO SQLite 3']['interface'], - $d['PDO SQLite 3'], - "CREATE TABLE arsse_test(id integer primary key)", - "BEGIN EXCLUSIVE TRANSACTION", - "PRAGMA user_version=#", - $pdoExec, - $pdoQuery, - ], - 'PDO PostgreSQL' => [ - $i['PDO PostgreSQL']['interface'], - $d['PDO PostgreSQL'], - "CREATE TABLE arsse_test(id bigserial primary key)", - "BEGIN; LOCK TABLE arsse_test IN EXCLUSIVE MODE NOWAIT", - "UPDATE arsse_meta set value = '#' where key = 'schema_version'", - $pdoExec, - $pdoQuery, - ], - ]; + return static::$interface->querySingle($q); } } diff --git a/tests/cases/Db/SQLite3/TestResult.php b/tests/cases/Db/SQLite3/TestResult.php index 2f655e7e..4109b8f1 100644 --- a/tests/cases/Db/SQLite3/TestResult.php +++ b/tests/cases/Db/SQLite3/TestResult.php @@ -12,22 +12,19 @@ use JKingWeb\Arsse\Test\DatabaseInformation; * @covers \JKingWeb\Arsse\Db\SQLite3\Result */ class TestResult extends \JKingWeb\Arsse\TestCase\Db\BaseResult { - protected $implementation = "SQLite 3"; + protected static $implementation = "SQLite 3"; - public function tearDown() { - parent::tearDown(); - $this->interface->close(); - unset($this->interface); - } - - protected function exec(string $q) { - $this->interface->exec($q); + public static function tearDownAfterClass() { + if (static::$interface) { + static::$interface->close(); + } + parent::tearDownAfterClass(); } protected function makeResult(string $q): array { - $set = $this->interface->query($q); - $rows = $this->interface->changes(); - $id = $this->interface->lastInsertRowID(); + $set = static::$interface->query($q); + $rows = static::$interface->changes(); + $id = static::$interface->lastInsertRowID(); return [$set, [$rows, $id]]; } } diff --git a/tests/cases/Db/SQLite3/TestStatement.php b/tests/cases/Db/SQLite3/TestStatement.php index fc06dbd0..1684e832 100644 --- a/tests/cases/Db/SQLite3/TestStatement.php +++ b/tests/cases/Db/SQLite3/TestStatement.php @@ -10,20 +10,15 @@ namespace JKingWeb\Arsse\TestCase\Db\SQLite3; * @covers \JKingWeb\Arsse\Db\SQLite3\Statement * @covers \JKingWeb\Arsse\Db\SQLite3\ExceptionBuilder */ class TestStatement extends \JKingWeb\Arsse\TestCase\Db\BaseStatement { - protected $implementation = "SQLite 3"; + protected static $implementation = "SQLite 3"; - public function tearDown() { - parent::tearDown(); - $this->interface->close(); - unset($this->interface); - } - - protected function exec(string $q) { - $this->interface->exec($q); + public static function tearDownAfterClass() { + static::$interface->close(); + parent::tearDownAfterClass(); } protected function makeStatement(string $q, array $types = []): array { - return [$this->interface, $this->interface->prepare($q), $types]; + return [static::$interface, static::$interface->prepare($q), $types]; } protected function decorateTypeSyntax(string $value, string $type): string { diff --git a/tests/cases/Db/SQLite3PDO/TestDriver.php b/tests/cases/Db/SQLite3PDO/TestDriver.php index 73ae773e..475d5756 100644 --- a/tests/cases/Db/SQLite3PDO/TestDriver.php +++ b/tests/cases/Db/SQLite3PDO/TestDriver.php @@ -11,30 +11,23 @@ namespace JKingWeb\Arsse\TestCase\Db\SQLite3PDO; * @covers \JKingWeb\Arsse\Db\PDODriver * @covers \JKingWeb\Arsse\Db\PDOError */ class TestDriver extends \JKingWeb\Arsse\TestCase\Db\BaseDriver { - protected $implementation = "PDO SQLite 3"; + protected static $implementation = "PDO SQLite 3"; protected $create = "CREATE TABLE arsse_test(id integer primary key)"; protected $lock = "BEGIN EXCLUSIVE TRANSACTION"; protected $setVersion = "PRAGMA user_version=#"; protected static $file; public static function setUpBeforeClass() { - self::$file = tempnam(sys_get_temp_dir(), 'ook'); + // create a temporary database file rather than using a memory database + // some tests require one connection to block another, so a memory database is not suitable + static::$file = tempnam(sys_get_temp_dir(), 'ook'); + static::$conf['dbSQLite3File'] = static::$file; + parent::setUpBeforeclass(); } public static function tearDownAfterClass() { + parent::tearDownAfterClass(); @unlink(self::$file); self::$file = null; } - - public function setUp() { - $this->conf['dbSQLite3File'] = self::$file; - parent::setUp(); - $this->exec("PRAGMA user_version=0"); - } - - public function tearDown() { - parent::tearDown(); - $this->exec("PRAGMA user_version=0"); - unset($this->interface); - } } diff --git a/tests/cases/Db/SQLite3PDO/TestStatement.php b/tests/cases/Db/SQLite3PDO/TestStatement.php index 74f05f19..9e2e06c6 100644 --- a/tests/cases/Db/SQLite3PDO/TestStatement.php +++ b/tests/cases/Db/SQLite3PDO/TestStatement.php @@ -10,19 +10,10 @@ namespace JKingWeb\Arsse\TestCase\Db\SQLite3PDO; * @covers \JKingWeb\Arsse\Db\PDOStatement * @covers \JKingWeb\Arsse\Db\PDOError */ class TestStatement extends \JKingWeb\Arsse\TestCase\Db\BaseStatement { - protected $implementation = "PDO SQLite 3"; - - public function tearDown() { - parent::tearDown(); - unset($this->interface); - } - - protected function exec(string $q) { - $this->interface->exec($q); - } + protected static $implementation = "PDO SQLite 3"; protected function makeStatement(string $q, array $types = []): array { - return [$this->interface, $this->interface->prepare($q), $types]; + return [static::$interface, static::$interface->prepare($q), $types]; } protected function decorateTypeSyntax(string $value, string $type): string { diff --git a/tests/cases/Db/TestResultPDO.php b/tests/cases/Db/TestResultPDO.php index f4d2eec7..f1792f84 100644 --- a/tests/cases/Db/TestResultPDO.php +++ b/tests/cases/Db/TestResultPDO.php @@ -12,41 +12,30 @@ use JKingWeb\Arsse\Test\DatabaseInformation; * @covers \JKingWeb\Arsse\Db\PDOResult */ class TestResultPDO extends \JKingWeb\Arsse\TestCase\Db\BaseResult { - protected static $firstAvailableDriver; + protected static $implementation; public static function setUpBeforeClass() { self::setConf(); // we only need to test one PDO implementation (they all use the same result class), so we find the first usable one $drivers = DatabaseInformation::listPDO(); - self::$firstAvailableDriver = $drivers[0]; + self::$implementation = $drivers[0]; foreach ($drivers as $driver) { $info = new DatabaseInformation($driver); $interface = ($info->interfaceConstructor)(); if ($interface) { - self::$firstAvailableDriver = $driver; + self::$implementation = $driver; break; } } - } - - public function setUp() { - $this->implementation = self::$firstAvailableDriver; - parent::setUp(); - } - - public function tearDown() { - parent::tearDown(); - unset($this->interface); - } - - protected function exec(string $q) { - $this->interface->exec($q); + unset($interface); + unset($info); + parent::setUpBeforeClass(); } protected function makeResult(string $q): array { - $set = $this->interface->query($q); + $set = static::$interface->query($q); $rows = $set->rowCount(); - $id = $this->interface->lastInsertID(); + $id = static::$interface->lastInsertID(); return [$set, [$rows, $id]]; } } diff --git a/tests/lib/DatabaseInformation.php b/tests/lib/DatabaseInformation.php index 4b1d950e..0ec4d1d2 100644 --- a/tests/lib/DatabaseInformation.php +++ b/tests/lib/DatabaseInformation.php @@ -59,7 +59,12 @@ class DatabaseInformation { $tables = $db->query($listTables)->getAll(); $tables = sizeof($tables) ? array_column($tables, "name") : []; } elseif ($db instanceof \PDO) { - $tables = $db->query($listTables)->fetchAll(\PDO::FETCH_ASSOC); + retry: + try { + $tables = $db->query($listTables)->fetchAll(\PDO::FETCH_ASSOC); + } catch (\PDOException $e) { + goto retry; + } $tables = sizeof($tables) ? array_column($tables, "name") : []; } else { $tables = []; @@ -72,6 +77,11 @@ class DatabaseInformation { return $tables; }; $sqlite3TruncateFunction = function($db, array $afterStatements = []) use ($sqlite3TableList) { + // rollback any pending transaction + try { + $db->exec("ROLLBACK"); + } catch(\Throwable $e) { + } foreach ($sqlite3TableList($db) as $table) { if ($table == "arsse_meta") { $db->exec("DELETE FROM $table where key <> 'schema_version'"); @@ -84,6 +94,11 @@ class DatabaseInformation { } }; $sqlite3RazeFunction = function($db, array $afterStatements = []) use ($sqlite3TableList) { + // rollback any pending transaction + try { + $db->exec("ROLLBACK"); + } catch(\Throwable $e) { + } $db->exec("PRAGMA foreign_keys=0"); foreach ($sqlite3TableList($db) as $table) { $db->exec("DROP TABLE IF EXISTS $table"); @@ -163,7 +178,12 @@ class DatabaseInformation { return $d; }, 'truncateFunction' => function($db, array $afterStatements = []) use ($pgObjectList) { - foreach ($objectList($db) as $obj) { + // rollback any pending transaction + try { + $db->exec("ROLLBACK"); + } catch(\Throwable $e) { + } + foreach ($pgObjectList($db) as $obj) { if ($obj['type'] != "TABLE") { continue; } elseif ($obj['name'] == "arsse_meta") { @@ -177,8 +197,8 @@ class DatabaseInformation { } }, 'razeFunction' => function($db, array $afterStatements = []) use ($pgObjectList) { - foreach ($objectList($db) as $obj) { - $db->exec("DROP {$obj['type']} {$obj['name']} IF EXISTS cascade"); + foreach ($pgObjectList($db) as $obj) { + $db->exec("DROP {$obj['type']} IF EXISTS {$obj['name']} cascade"); } foreach ($afterStatements as $st) {