From aab234a3f4c30c1b16ca24ae1059a2c4a38e4a2f Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 23 Apr 2019 13:18:51 +0200 Subject: [PATCH] update to schema version 1 - factions table is now faction - no turn column - new update logic --- process/epasswd.py | 4 +- src/creport.c | 2 +- src/gamedb.c | 29 +++++--- src/kernel/database.test.c | 17 +++-- src/kernel/db/driver.h | 14 +++- src/kernel/db/sqlite.c | 132 +++++++++++++++++++++++++------------ tests/runtests.bat | 6 +- 7 files changed, 139 insertions(+), 65 deletions(-) diff --git a/process/epasswd.py b/process/epasswd.py index bdb3c4a6d..c5e1712b9 100755 --- a/process/epasswd.py +++ b/process/epasswd.py @@ -45,9 +45,7 @@ class EPasswd: def load_database(self, file): conn = sqlite3.connect(file) c = conn.cursor() - c.execute('SELECT MAX(turn) FROM factions') - args = c.fetchone() - for row in c.execute('SELECT no, email, password FROM factions WHERE turn=?', args): + for row in c.execute('SELECT `no`, `email`, `password` FROM `faction`'): (no, email, passwd) = row self.set_data(baseconvert(no, 36), email, passwd) conn.close() diff --git a/src/creport.c b/src/creport.c index 23e0f7c8a..fce3b8bff 100644 --- a/src/creport.c +++ b/src/creport.c @@ -100,7 +100,7 @@ struct locale *crtag_locale(void) { static int config; if (config_changed(&config)) { const char *lname = config_get("creport.tags"); - lang = get_locale(lname ? lname : "de"); + lang = lname ? get_locale(lname) : default_locale; } return lang; } diff --git a/src/gamedb.c b/src/gamedb.c index 5f53d9120..9af580a9f 100644 --- a/src/gamedb.c +++ b/src/gamedb.c @@ -9,9 +9,25 @@ #include "kernel/faction.h" #include "kernel/db/driver.h" +#include "util/strings.h" + +static int generate_factions(void *data, db_faction *results, int nresults) +{ + int i; + faction **iter = (faction **)data; + for (i = 0; *iter && i != nresults; ++i) { + faction *f = *iter; + results[i].p_uid = &f->uid; + results[i].no = f->no; + results[i].email = faction_getemail(f); + str_strlcpy(results[i].pwhash, faction_getpassword(f), sizeof(results[i].pwhash)); + *iter = f->next; + } + return i; +} + int gamedb_update(void) { - faction *f; int err; const char *dbname; @@ -19,14 +35,9 @@ int gamedb_update(void) err = db_driver_open(DB_GAME, dbname); if (err == 0) { - for (f = factions; f; f = f->next) { - int uid = db_driver_faction_save(f->uid, f->no, turn, - faction_getemail(f), - faction_getpassword(f)); - if (uid > 0) { - f->uid = uid; - } - } + faction *list = factions; + db_driver_update_factions(generate_factions, &list); + db_driver_compact(turn); db_driver_close(DB_GAME); } return err; diff --git a/src/kernel/database.test.c b/src/kernel/database.test.c index c5aae1af6..a84a4b286 100644 --- a/src/kernel/database.test.c +++ b/src/kernel/database.test.c @@ -47,19 +47,26 @@ static void test_save_load_order(CuTest *tc) { static void test_update_faction(CuTest *tc) { faction *f; - int uid; + int err; + dbrow_id id; test_setup(); db_driver_open(DB_GAME, NULL); f = test_create_faction(NULL); - uid = db_driver_faction_save(f->uid, f->no, 0, + CuAssertIntEquals(tc, 0, f->uid); + id = 0; + err = db_driver_faction_save(&id, f->no, faction_getemail(f), faction_getpassword(f)); - f->uid = uid; - uid = db_driver_faction_save(f->uid, f->no, 0, + CuAssertTrue(tc, 0 != id); + f->uid = (int)id; + db_driver_close(DB_GAME); + + db_driver_open(DB_GAME, NULL); + db_driver_faction_save(&id, f->no, faction_getemail(f), faction_getpassword(f)); - CuAssertIntEquals(tc, f->uid, uid); + CuAssertIntEquals(tc, f->uid, id); db_driver_close(DB_GAME); test_teardown(); } diff --git a/src/kernel/db/driver.h b/src/kernel/db/driver.h index 341653991..91fcfbb27 100644 --- a/src/kernel/db/driver.h +++ b/src/kernel/db/driver.h @@ -1,6 +1,7 @@ #pragma once #include +#include struct order_data; @@ -17,6 +18,17 @@ int db_driver_open(database_t db, const char *dbname); void db_driver_close(database_t db); dbrow_id db_driver_order_save(const char *str); struct order_data *db_driver_order_load(dbrow_id id); -dbrow_id db_driver_faction_save(dbrow_id id, int no, int turn, const char *email, const char *password); dbrow_id db_driver_string_save(const char *s); const char *db_driver_string_load(dbrow_id id, size_t *size); +void db_driver_compact(int turn); + +typedef struct db_faction { + int *p_uid; + int no; + const char *email; + char pwhash[128]; +} db_faction; + +typedef int (*db_faction_generator)(void *, db_faction *, int); +int db_driver_update_factions(db_faction_generator gen, void *data); +int db_driver_faction_save(dbrow_id * p_id, int no, const char *email, const char *password); diff --git a/src/kernel/db/sqlite.c b/src/kernel/db/sqlite.c index 29638d900..676dc5028 100644 --- a/src/kernel/db/sqlite.c +++ b/src/kernel/db/sqlite.c @@ -95,68 +95,104 @@ dbrow_id db_driver_order_save(const char *str) { return (dbrow_id)id; } - -dbrow_id db_driver_faction_save(dbrow_id id, int no, int turn, const char *email, const char *password) +int db_driver_faction_save(dbrow_id * p_id, int no, const char *email, const char *password) { - sqlite3_int64 row_id; + dbrow_id id = *p_id; int err; + sqlite3_stmt *stmt = (id > 0) ? g_stmt_update_faction : g_stmt_insert_faction; assert(g_game_db); - if (id != 0) { - int rows; - err = sqlite3_reset(g_stmt_update_faction); - assert(err == SQLITE_OK); - err = sqlite3_bind_int(g_stmt_update_faction, 1, no); - assert(err == SQLITE_OK); - err = sqlite3_bind_int(g_stmt_update_faction, 2, turn); - assert(err == SQLITE_OK); - err = sqlite3_bind_text(g_stmt_update_faction, 3, email, -1, SQLITE_STATIC); - assert(err == SQLITE_OK); - err = sqlite3_bind_text(g_stmt_update_faction, 4, password, -1, SQLITE_STATIC); - assert(err == SQLITE_OK); - err = sqlite3_bind_int(g_stmt_update_faction, 5, id); - assert(err == SQLITE_OK); - err = sqlite3_step(g_stmt_update_faction); - assert(err == SQLITE_DONE); - rows = sqlite3_changes(g_game_db); - if (rows != 0) { - return id; - } + err = sqlite3_reset(stmt); + if (err != SQLITE_OK) return err; + err = sqlite3_bind_int(stmt, 1, no); + if (err != SQLITE_OK) return err; + err = sqlite3_bind_text(stmt, 2, email, -1, SQLITE_STATIC); + if (err != SQLITE_OK) return err; + err = sqlite3_bind_text(stmt, 3, password, -1, SQLITE_STATIC); + if (err != SQLITE_OK) return err; + + if (id > 0) { + err = sqlite3_bind_int(stmt, 4, id); + if (err != SQLITE_OK) return err; } - err = sqlite3_reset(g_stmt_insert_faction); - assert(err == SQLITE_OK); - err = sqlite3_bind_int(g_stmt_insert_faction, 1, no); - assert(err == SQLITE_OK); - err = sqlite3_bind_int(g_stmt_insert_faction, 2, turn); - assert(err == SQLITE_OK); - err = sqlite3_bind_text(g_stmt_insert_faction, 3, email, -1, SQLITE_STATIC); - assert(err == SQLITE_OK); - err = sqlite3_bind_text(g_stmt_insert_faction, 4, password, -1, SQLITE_STATIC); - assert(err == SQLITE_OK); - err = sqlite3_step(g_stmt_insert_faction); - assert(err == SQLITE_DONE); + err = sqlite3_step(stmt); + if (err != SQLITE_DONE) return err; ERRNO_CHECK(); - row_id = sqlite3_last_insert_rowid(g_game_db); - assert(row_id>0 && row_id <= UINT_MAX); - return (dbrow_id)row_id; + if (id <= 0) { + sqlite3_int64 row_id; + row_id = sqlite3_last_insert_rowid(g_game_db); + assert(row_id > 0 && row_id <= UINT_MAX); + *p_id = (dbrow_id)row_id; + } + return SQLITE_OK; +} + +int db_driver_update_factions(db_faction_generator gen, void *data) +{ + db_faction results[32]; + int num, err; + + err = sqlite3_exec(g_game_db, "BEGIN TRANSACTION", NULL, NULL, NULL); + assert(err == SQLITE_OK); + err = sqlite3_exec(g_game_db, "DELETE FROM `faction`", NULL, NULL, NULL); + if (err != SQLITE_OK) { + sqlite3_exec(g_game_db, "ROLLBACK", NULL, NULL, NULL); + return err; + } + num = gen(data, results, 32); + while (num > 0) { + int i; + for (i = 0; i != num; ++i) { + db_faction *dbf = results + i; + dbrow_id id = (dbrow_id)*dbf->p_uid; + err = db_driver_faction_save(&id, dbf->no, dbf->email, dbf->pwhash); + if (err != SQLITE_OK) { + sqlite3_exec(g_game_db, "ROLLBACK", NULL, NULL, NULL); + return err; + } + assert(id > 0 && id <= INT_MAX); + *dbf->p_uid = (int)id; + } + num = gen(data, results, 32); + } + err = sqlite3_exec(g_game_db, "COMMIT", NULL, NULL, NULL); + return err; +} + +static int cb_int_col(void *data, int ncols, char **text, char **name) { + int *p_int = (int *)data; + *p_int = atoi(text[0]); + return SQLITE_OK; } static int db_open_game(const char *dbname) { - int err; + int err, version = 0; err = sqlite3_open(dbname, &g_game_db); assert(err == SQLITE_OK); - err = sqlite3_exec(g_game_db, "CREATE TABLE IF NOT EXISTS factions (id INTEGER PRIMARY KEY, no INTEGER NOT NULL, email VARCHAR(128), password VARCHAR(128), turn INTEGER NOT NULL)", NULL, NULL, NULL); + + err = sqlite3_exec(g_game_db, "PRAGMA user_version", cb_int_col, &version, NULL); assert(err == SQLITE_OK); - err = sqlite3_prepare_v2(g_game_db, "UPDATE factions SET no=?, turn=?, email=?, password=? WHERE id=?", -1, &g_stmt_update_faction, NULL); + if (version < 1) { + /* drop deprecated table */ + err = sqlite3_exec(g_game_db, "DROP TABLE IF EXISTS `factions`", NULL, NULL, NULL); + assert(err == SQLITE_OK); + /* install schema version 1: */ + err = sqlite3_exec(g_game_db, "CREATE TABLE IF NOT EXISTS `faction` (`id` INTEGER PRIMARY KEY, `no` INTEGER NOT NULL UNIQUE, `email` VARCHAR(128), `password` VARCHAR(128))", NULL, NULL, NULL); + assert(err == SQLITE_OK); + err = sqlite3_exec(g_game_db, "PRAGMA user_version = 1", NULL, NULL, NULL); + assert(err == SQLITE_OK); + } + /* create prepared statments: */ + err = sqlite3_prepare_v2(g_game_db, "INSERT INTO `faction` (`no`, `email`, `password`, `id`) VALUES (?,?,?,?)", -1, &g_stmt_update_faction, NULL); assert(err == SQLITE_OK); - err = sqlite3_prepare_v2(g_game_db, "INSERT INTO factions (no, turn, email, password) VALUES (?,?,?,?)", -1, &g_stmt_insert_faction, NULL); + err = sqlite3_prepare_v2(g_game_db, "INSERT INTO `faction` (`no`, `email`, `password`) VALUES (?,?,?)", -1, &g_stmt_insert_faction, NULL); assert(err == SQLITE_OK); ERRNO_CHECK(); - return 0; + return err; } static int db_open_swap(const char *dbname) { @@ -303,3 +339,13 @@ const char *db_driver_string_load(dbrow_id id, size_t *size) { ERRNO_CHECK(); return NULL; } + +void db_driver_compact(int turn) +{ + int err; + + /* repack database: */ + err = sqlite3_exec(g_game_db, "VACUUM", 0, 0, 0); + assert(err == SQLITE_OK); +} + diff --git a/tests/runtests.bat b/tests/runtests.bat index 88afc8d31..e73580851 100644 --- a/tests/runtests.bat +++ b/tests/runtests.bat @@ -7,9 +7,9 @@ IF EXIST ..\build-vs15 SET BUILD=..\build-vs15\eressea\Debug SET SERVER=%BUILD%\eressea.exe %BUILD%\test_eressea.exe -%SERVER% ..\scripts\run-tests.lua -%SERVER% -re2 ..\scripts\run-tests-e2.lua -%SERVER% -re3 ..\scripts\run-tests-e3.lua +%SERVER% -v1 ..\scripts\run-tests.lua +%SERVER% -v1 -re2 ..\scripts\run-tests-e2.lua +%SERVER% -v1 -re3 ..\scripts\run-tests-e3.lua %SERVER% --version PAUSE RMDIR /s /q reports