reapack

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

commit 737efda8f1f79b06c4775761789d2fe9c6a39e57
parent 11a7af9b3bdd6af816333819165fa1b28b913993
Author: cfillion <cfillion@users.noreply.github.com>
Date:   Fri, 12 Aug 2016 15:28:46 -0400

registry: accept databases written by compatible newer versions of ReaPack

Diffstat:
Msrc/database.cpp | 30++++++++++++++++++++----------
Msrc/database.hpp | 12++++++++----
Msrc/registry.cpp | 26++++++++++++++++----------
Msrc/registry.hpp | 2+-
Mtest/database.cpp | 37+++++++++++++++++++++++++++++++++----
5 files changed, 78 insertions(+), 29 deletions(-)

diff --git a/src/database.cpp b/src/database.cpp @@ -19,6 +19,7 @@ #include "errors.hpp" +#include <cinttypes> #include <sqlite3.h> using namespace std; @@ -67,22 +68,31 @@ reapack_error Database::lastError() const return reapack_error(sqlite3_errmsg(m_db)); } -int Database::lastInsertId() const +int64_t Database::lastInsertId() const { - return (int)sqlite3_last_insert_rowid(m_db); + return sqlite3_last_insert_rowid(m_db); } -int Database::version() const +auto Database::version() const -> Version { - int version = 0; + int32_t version = 0; Statement stmt("PRAGMA user_version", this); stmt.exec([&] { - version = stmt.intColumn(0); + version = static_cast<int32_t>(stmt.intColumn(0)); return false; }); - return version; + return {static_cast<int16_t>(version >> 16), static_cast<int16_t>(version)}; +} + +void Database::setVersion(const Version &version) +{ + int32_t value = version.minor | (int32_t)version.major << 16; + + char sql[255] = {}; + sprintf(sql, "PRAGMA user_version = %" PRId32, value); + exec(sql); } int Database::errorCode() const @@ -121,9 +131,9 @@ void Statement::bind(const int index, const string &text) throw m_db->lastError(); } -void Statement::bind(const int index, const int integer) +void Statement::bind(const int index, const int64_t integer) { - if(sqlite3_bind_int(m_stmt, index, integer)) + if(sqlite3_bind_int64(m_stmt, index, integer)) throw m_db->lastError(); } @@ -151,9 +161,9 @@ void Statement::exec(const ExecCallback &callback) } } -int Statement::intColumn(const int index) const +int64_t Statement::intColumn(const int index) const { - return sqlite3_column_int(m_stmt, index); + return sqlite3_column_int64(m_stmt, index); } string Statement::stringColumn(const int index) const diff --git a/src/database.hpp b/src/database.hpp @@ -18,6 +18,7 @@ #ifndef REAPACK_DATABASE_HPP #define REAPACK_DATABASE_HPP +#include <cstdint> #include <functional> #include <string> #include <vector> @@ -31,13 +32,16 @@ class Statement; class Database { public: + struct Version { int16_t major; int16_t minor; }; + Database(const std::string &filename = std::string()); ~Database(); Statement *prepare(const char *sql); void exec(const char *sql); - int lastInsertId() const; - int version() const; + int64_t lastInsertId() const; + Version version() const; + void setVersion(const Version &); int errorCode() const; void begin(); void commit(); @@ -56,11 +60,11 @@ public: typedef std::function<bool (void)> ExecCallback; void bind(int index, const std::string &text); - void bind(int index, int integer); + void bind(int index, int64_t integer); void exec(); void exec(const ExecCallback &); - int intColumn(int index) const; + int64_t intColumn(int index) const; bool boolColumn(int index) const { return intColumn(index) != 0; } std::string stringColumn(int index) const; diff --git a/src/registry.cpp b/src/registry.cpp @@ -74,10 +74,12 @@ Registry::Registry(const Path &path) void Registry::migrate() { + const Database::Version &version = m_db.version(); + m_db.begin(); + m_db.setVersion({0, 4}); - switch(m_db.version()) { - case 0: + if(!version.major && !version.minor) { // new database! m_db.exec( "CREATE TABLE entries (" @@ -102,22 +104,26 @@ void Registry::migrate() " FOREIGN KEY(entry) REFERENCES entries(id)" ");" ); + } + + switch(version.major) { + case 0: + // current major schema version break; + default: + throw reapack_error( + "The package registry was created by a newer version of ReaPack"); + } + + switch(version.minor) { case 1: m_db.exec("ALTER TABLE entries ADD COLUMN pinned INTEGER NOT NULL DEFAULT 0;"); case 2: m_db.exec("ALTER TABLE files ADD COLUMN type INTEGER NOT NULL DEFAULT 0;"); case 3: m_db.exec("ALTER TABLE entries ADD COLUMN desc TEXT NOT NULL DEFAULT '';"); - case 4: - // schema is up to date - break; - default: - throw reapack_error( - "The package registry was created by a newer version of ReaPack"); } - m_db.exec("PRAGMA user_version = 4"); m_db.commit(); } @@ -136,7 +142,7 @@ auto Registry::push(const Version *ver, vector<Path> *conflicts) -> Entry m_clearFiles->bind(3, pkg->name()); m_clearFiles->exec(); - int entryId = getEntry(ver->package()).id; + auto entryId = getEntry(ver->package()).id; // register or update package and version if(entryId) { diff --git a/src/registry.hpp b/src/registry.hpp @@ -33,7 +33,7 @@ class Version; class Registry { public: struct Entry { - int id; + int64_t id; std::string remote; std::string category; std::string package; diff --git a/test/database.cpp b/test/database.cpp @@ -95,12 +95,18 @@ TEST_CASE("bind values and clear", M) { } } -TEST_CASE("version", M) { +TEST_CASE("database version", M) { Database db; - REQUIRE(db.version() == 0); + REQUIRE(db.version().major == 0); + REQUIRE(db.version().minor == 0); - db.exec("PRAGMA user_version = 1"); - REQUIRE(db.version() == 1); + db.setVersion({0, 1}); + REQUIRE(db.version().major == 0); + REQUIRE(db.version().minor == 1); + + db.setVersion({32767, 32767}); + REQUIRE(db.version().major == 32767); + REQUIRE(db.version().minor == 32767); } TEST_CASE("foreign keys", M) { @@ -161,6 +167,29 @@ TEST_CASE("bind temporary strings", M) { REQUIRE(got == "hello"); } +TEST_CASE("get integers from sqlite", M) { + Database db; + db.exec("CREATE TABLE a(test INTEGER NOT NULL)"); + + Statement *insert = db.prepare("INSERT INTO a VALUES(?)"); + + insert->bind(1, 2147483647); + insert->exec(); + insert->bind(1, 4294967295); + insert->exec(); + + vector<sqlite3_int64> signedVals; + Statement *select = db.prepare("SELECT test FROM a"); + select->exec([&] { + signedVals.push_back(select->intColumn(0)); + return true; + }); + + CHECK(signedVals.size() == 2); + REQUIRE(signedVals[0] == 2147483647); + REQUIRE(signedVals[1] == 4294967295); +} + TEST_CASE("sqlite error code", M) { Database db; db.exec("CREATE TABLE a(b INTEGER UNIQUE); INSERT INTO a VALUES(1)");