]> git.sesse.net Git - nageru/blobdiff - futatabi/db.cpp
Update some error messages.
[nageru] / futatabi / db.cpp
index 39fd55776c40c9f094e84bfbbb4aed906b65fed6..4da0a0a89becb427a0c4991e632c47e76cf30c3e 100644 (file)
@@ -3,6 +3,7 @@
 #include "frame.pb.h"
 
 #include <string>
+#include <unordered_set>
 
 using namespace std;
 
@@ -16,15 +17,27 @@ DB::DB(const string &filename)
 
        sqlite3_exec(db, R"(
                CREATE TABLE IF NOT EXISTS state (state BLOB);
-       )", nullptr, nullptr, nullptr);  // Ignore errors.
+       )",
+                    nullptr, nullptr, nullptr);  // Ignore errors.
+
+       sqlite3_exec(db, "CREATE UNIQUE INDEX only_one_state ON state (1);", nullptr, nullptr, nullptr);  // Ignore errors.
+
+       sqlite3_exec(db, R"(
+               CREATE TABLE IF NOT EXISTS settings (settings BLOB, uniqifier NOT NULL DEFAULT 1 UNIQUE);
+       )",
+                    nullptr, nullptr, nullptr);  // Ignore errors.
+
+       sqlite3_exec(db, "CREATE UNIQUE INDEX only_one_settings ON settings (1);", nullptr, nullptr, nullptr);  // Ignore errors.
 
        sqlite3_exec(db, R"(
                DROP TABLE file;
-       )", nullptr, nullptr, nullptr);  // Ignore errors.
+       )",
+                    nullptr, nullptr, nullptr);  // Ignore errors.
 
        sqlite3_exec(db, R"(
                DROP TABLE frame;
-       )", nullptr, nullptr, nullptr);  // Ignore errors.
+       )",
+                    nullptr, nullptr, nullptr);  // Ignore errors.
 
        sqlite3_exec(db, R"(
                CREATE TABLE IF NOT EXISTS filev2 (
@@ -33,7 +46,8 @@ DB::DB(const string &filename)
                        size BIGINT NOT NULL,
                        frames BLOB NOT NULL
                );
-       )", nullptr, nullptr, nullptr);  // Ignore errors.
+       )",
+                    nullptr, nullptr, nullptr);  // Ignore errors.
 
        sqlite3_exec(db, "PRAGMA journal_mode=WAL", nullptr, nullptr, nullptr);  // Ignore errors.
        sqlite3_exec(db, "PRAGMA synchronous=NORMAL", nullptr, nullptr, nullptr);  // Ignore errors.
@@ -82,16 +96,81 @@ void DB::store_state(const StateProto &state)
                exit(1);
        }
 
-       ret = sqlite3_exec(db, "DELETE FROM state", nullptr, nullptr, nullptr);
+       sqlite3_stmt *stmt;
+       ret = sqlite3_prepare_v2(db, "REPLACE INTO state VALUES (?)", -1, &stmt, 0);
        if (ret != SQLITE_OK) {
-               fprintf(stderr, "DELETE: %s\n", sqlite3_errmsg(db));
+               fprintf(stderr, "REPLACE prepare: %s\n", sqlite3_errmsg(db));
+               exit(1);
+       }
+
+       sqlite3_bind_blob(stmt, 1, serialized.data(), serialized.size(), SQLITE_STATIC);
+
+       ret = sqlite3_step(stmt);
+       if (ret == SQLITE_ROW) {
+               fprintf(stderr, "REPLACE step: %s\n", sqlite3_errmsg(db));
+               exit(1);
+       }
+
+       ret = sqlite3_finalize(stmt);
+       if (ret != SQLITE_OK) {
+               fprintf(stderr, "REPLACE finalize: %s\n", sqlite3_errmsg(db));
+               exit(1);
+       }
+
+       ret = sqlite3_exec(db, "COMMIT", nullptr, nullptr, nullptr);
+       if (ret != SQLITE_OK) {
+               fprintf(stderr, "COMMIT: %s\n", sqlite3_errmsg(db));
                exit(1);
        }
+}
+
+SettingsProto DB::get_settings()
+{
+       SettingsProto settings;
 
        sqlite3_stmt *stmt;
-       ret = sqlite3_prepare_v2(db, "INSERT INTO state VALUES (?)", -1, &stmt, 0);
+       int ret = sqlite3_prepare_v2(db, "SELECT settings FROM settings", -1, &stmt, 0);
        if (ret != SQLITE_OK) {
-               fprintf(stderr, "INSERT prepare: %s\n", sqlite3_errmsg(db));
+               fprintf(stderr, "SELECT prepare: %s\n", sqlite3_errmsg(db));
+               exit(1);
+       }
+
+       ret = sqlite3_step(stmt);
+       if (ret == SQLITE_ROW) {
+               bool ok = settings.ParseFromArray(sqlite3_column_blob(stmt, 0), sqlite3_column_bytes(stmt, 0));
+               if (!ok) {
+                       fprintf(stderr, "State in database is corrupted!\n");
+                       exit(1);
+               }
+       } else if (ret != SQLITE_DONE) {
+               fprintf(stderr, "SELECT step: %s\n", sqlite3_errmsg(db));
+               exit(1);
+       }
+
+       ret = sqlite3_finalize(stmt);
+       if (ret != SQLITE_OK) {
+               fprintf(stderr, "SELECT finalize: %s\n", sqlite3_errmsg(db));
+               exit(1);
+       }
+
+       return settings;
+}
+
+void DB::store_settings(const SettingsProto &settings)
+{
+       string serialized;
+       settings.SerializeToString(&serialized);
+
+       int ret = sqlite3_exec(db, "BEGIN", nullptr, nullptr, nullptr);
+       if (ret != SQLITE_OK) {
+               fprintf(stderr, "BEGIN: %s\n", sqlite3_errmsg(db));
+               exit(1);
+       }
+
+       sqlite3_stmt *stmt;
+       ret = sqlite3_prepare_v2(db, "REPLACE INTO settings VALUES (?)", -1, &stmt, 0);
+       if (ret != SQLITE_OK) {
+               fprintf(stderr, "REPLACE prepare: %s\n", sqlite3_errmsg(db));
                exit(1);
        }
 
@@ -99,13 +178,13 @@ void DB::store_state(const StateProto &state)
 
        ret = sqlite3_step(stmt);
        if (ret == SQLITE_ROW) {
-               fprintf(stderr, "INSERT step: %s\n", sqlite3_errmsg(db));
+               fprintf(stderr, "REPLACE step: %s\n", sqlite3_errmsg(db));
                exit(1);
        }
 
        ret = sqlite3_finalize(stmt);
        if (ret != SQLITE_OK) {
-               fprintf(stderr, "INSERT finalize: %s\n", sqlite3_errmsg(db));
+               fprintf(stderr, "REPLACE finalize: %s\n", sqlite3_errmsg(db));
                exit(1);
        }
 
@@ -175,26 +254,6 @@ void DB::store_frame_file(const string &filename, size_t size, const vector<Fram
        // Delete any existing instances with this filename.
        sqlite3_stmt *stmt;
 
-       ret = sqlite3_prepare_v2(db, "DELETE FROM filev2 WHERE filename=?", -1, &stmt, 0);
-       if (ret != SQLITE_OK) {
-               fprintf(stderr, "DELETE prepare: %s\n", sqlite3_errmsg(db));
-               exit(1);
-       }
-
-       sqlite3_bind_text(stmt, 1, filename.data(), filename.size(), SQLITE_STATIC);
-
-       ret = sqlite3_step(stmt);
-       if (ret == SQLITE_ROW) {
-               fprintf(stderr, "DELETE step: %s\n", sqlite3_errmsg(db));
-               exit(1);
-       }
-
-       ret = sqlite3_finalize(stmt);
-       if (ret != SQLITE_OK) {
-               fprintf(stderr, "DELETE finalize: %s\n", sqlite3_errmsg(db));
-               exit(1);
-       }
-
        // Create the protobuf blob for the new row.
        FileContentsProto file_contents;
        unordered_set<unsigned> seen_stream_idx;  // Usually only one.
@@ -220,7 +279,7 @@ void DB::store_frame_file(const string &filename, size_t size, const vector<Fram
        file_contents.SerializeToString(&serialized);
 
        // Insert the new row.
-       ret = sqlite3_prepare_v2(db, "INSERT INTO filev2 (filename, size, frames) VALUES (?, ?, ?)", -1, &stmt, 0);
+       ret = sqlite3_prepare_v2(db, "REPLACE INTO filev2 (filename, size, frames) VALUES (?, ?, ?)", -1, &stmt, 0);
        if (ret != SQLITE_OK) {
                fprintf(stderr, "INSERT prepare: %s\n", sqlite3_errmsg(db));
                exit(1);
@@ -232,13 +291,13 @@ void DB::store_frame_file(const string &filename, size_t size, const vector<Fram
 
        ret = sqlite3_step(stmt);
        if (ret == SQLITE_ROW) {
-               fprintf(stderr, "INSERT step: %s\n", sqlite3_errmsg(db));
+               fprintf(stderr, "REPLACE step: %s\n", sqlite3_errmsg(db));
                exit(1);
        }
 
        ret = sqlite3_finalize(stmt);
        if (ret != SQLITE_OK) {
-               fprintf(stderr, "INSERT finalize: %s\n", sqlite3_errmsg(db));
+               fprintf(stderr, "REPLACE finalize: %s\n", sqlite3_errmsg(db));
                exit(1);
        }
 
@@ -260,7 +319,8 @@ void DB::clean_unused_frame_files(const vector<string> &used_filenames)
 
        ret = sqlite3_exec(db, R"(
                CREATE TEMPORARY TABLE used_filenames ( filename VARCHAR NOT NULL PRIMARY KEY )
-       )", nullptr, nullptr, nullptr);
+       )",
+                          nullptr, nullptr, nullptr);
 
        if (ret != SQLITE_OK) {
                fprintf(stderr, "CREATE TEMPORARY TABLE: %s\n", sqlite3_errmsg(db));
@@ -299,7 +359,8 @@ void DB::clean_unused_frame_files(const vector<string> &used_filenames)
 
        ret = sqlite3_exec(db, R"(
                DELETE FROM filev2 WHERE filename NOT IN ( SELECT filename FROM used_filenames )
-       )", nullptr, nullptr, nullptr);
+       )",
+                          nullptr, nullptr, nullptr);
 
        if (ret != SQLITE_OK) {
                fprintf(stderr, "DELETE: %s\n", sqlite3_errmsg(db));
@@ -308,7 +369,8 @@ void DB::clean_unused_frame_files(const vector<string> &used_filenames)
 
        ret = sqlite3_exec(db, R"(
                DROP TABLE used_filenames
-       )", nullptr, nullptr, nullptr);
+       )",
+                          nullptr, nullptr, nullptr);
 
        if (ret != SQLITE_OK) {
                fprintf(stderr, "DROP TABLE: %s\n", sqlite3_errmsg(db));