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:
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 &) {}
+ }
+}