reapack

Package manager for REAPER
Log | Files | Refs | Submodules | README | LICENSE

commit fa3998b58ec65948e5ac4102cd0e7e0233bb1b91
parent f7423af0e1d53f1e867550bb5f18559eb8327248
Author: cfillion <cfillion@users.noreply.github.com>
Date:   Wed, 21 Jun 2017 01:28:28 -0400

move savepoint logic to Database and add unit tests

Diffstat:
Msrc/database.cpp | 25+++++++++++++++++++++++++
Msrc/database.hpp | 5+++++
Msrc/registry.cpp | 39+++++----------------------------------
Msrc/registry.hpp | 10++++------
Mtest/database.cpp | 47+++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 86 insertions(+), 40 deletions(-)

diff --git a/src/database.cpp b/src/database.cpp @@ -25,6 +25,7 @@ using namespace std; Database::Database(const string &filename) + : m_savePoint(0) { const char *file = ":memory:"; @@ -113,6 +114,30 @@ void Database::commit() exec("COMMIT"); } +void Database::savepoint() +{ + char sql[64]; + sprintf(sql, "SAVEPOINT sp%zu", m_savePoint++); + + exec(sql); +} + +void Database::restore() +{ + char sql[64]; + sprintf(sql, "ROLLBACK TO SAVEPOINT sp%zu", --m_savePoint); + + exec(sql); +} + +void Database::release() +{ + char sql[64]; + sprintf(sql, "RELEASE SAVEPOINT sp%zu", --m_savePoint); + + exec(sql); +} + Statement::Statement(const char *sql, const Database *db) : m_db(db) { diff --git a/src/database.hpp b/src/database.hpp @@ -53,8 +53,12 @@ public: Version version() const; void setVersion(const Version &); int errorCode() const; + void begin(); void commit(); + void savepoint(); + void restore(); + void release(); private: friend Statement; @@ -63,6 +67,7 @@ private: sqlite3 *m_db; std::vector<Statement *> m_statements; + size_t m_savePoint; }; class Statement { diff --git a/src/registry.cpp b/src/registry.cpp @@ -28,7 +28,7 @@ using namespace std; Registry::Registry(const Path &path) - : m_db(path.join()), m_savePoint(0) + : m_db(path.join()) { migrate(); @@ -141,7 +141,7 @@ void Registry::migrate() auto Registry::push(const Version *ver, vector<Path> *conflicts) -> Entry { - savepoint(); + m_db.savepoint(); bool hasConflicts = false; @@ -196,18 +196,18 @@ auto Registry::push(const Version *ver, vector<Path> *conflicts) -> Entry conflicts->push_back(path); } else { - restore(); + m_db.restore(); throw; } } } if(hasConflicts) { - restore(); + m_db.restore(); return {}; } else { - release(); + m_db.release(); return {entryId, ri->name(), cat->name(), pkg->name(), pkg->description(), pkg->type(), ver->name(), ver->author()}; } @@ -319,35 +319,6 @@ void Registry::forget(const Entry &entry) m_forgetEntry->exec(); } -void Registry::savepoint() -{ - char sql[64]; - sprintf(sql, "SAVEPOINT sp%zu", m_savePoint++); - - m_db.exec(sql); -} - -void Registry::restore() -{ - char sql[64]; - sprintf(sql, "ROLLBACK TO SAVEPOINT sp%zu", --m_savePoint); - - m_db.exec(sql); -} - -void Registry::release() -{ - char sql[64]; - sprintf(sql, "RELEASE SAVEPOINT sp%zu", --m_savePoint); - - m_db.exec(sql); -} - -void Registry::commit() -{ - m_db.commit(); -} - void Registry::convertImplicitSections() { // convert from v1.0 main=true format to v1.1 flag format diff --git a/src/registry.hpp b/src/registry.hpp @@ -63,10 +63,10 @@ public: Entry push(const Version *, std::vector<Path> *conflicts = nullptr); void setPinned(const Entry &, bool pinned); void forget(const Entry &); - void savepoint(); - void restore(); - void release(); - void commit(); + + void savepoint() { m_db.savepoint(); } + void restore() { m_db.restore(); } + void commit() { m_db.commit(); } private: void migrate(); @@ -86,8 +86,6 @@ private: Statement *m_insertFile; Statement *m_clearFiles; Statement *m_forgetFiles; - - size_t m_savePoint; }; namespace std { diff --git a/test/database.cpp b/test/database.cpp @@ -227,3 +227,50 @@ TEST_CASE("invalid string column", M) { return false; }); } + +TEST_CASE("database transaction locking", M) { + Database db; + db.begin(); + + try { + db.begin(); + FAIL("created a transaction within a transaction"); + } + catch(const reapack_error &) {} + + db.commit(); + db.begin(); +} + +TEST_CASE("save points", M) { + Database db; + db.exec("CREATE TABLE test (value INTEGER NOT NULL);"); + + Statement *insert = db.prepare("INSERT INTO test VALUES (1);"); + Statement *select = db.prepare("SELECT COUNT(*) FROM test"); + + auto count = [select] { + int count = -255; + select->exec([&] { count = select->intColumn(0); return false; }); + return count; + }; + + db.savepoint(); + + insert->exec(); + REQUIRE(count() == 1); + + SECTION("rollback to savepoint") { + db.restore(); + REQUIRE(count() == 0); + try { db.restore(); FAIL("rolled back unexistant savepoint"); } + catch(const reapack_error &) {} + } + + SECTION("release savepoint") { + db.release(); + REQUIRE(count() == 1); + try { db.release(); FAIL("released unexistant savepoint"); } + catch(const reapack_error &) {} + } +}