From baa210d1a9d1055f62ff14cd2533a4b908be22db Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 22 Jan 2017 12:57:25 +0100 Subject: [PATCH] Revert "remove sqlite3 code and dependency" This reverts commit 7b55a57610b3e8d54ad2b1a6d6f8642ca9ae391f. --- CMakeLists.txt | 1 + process/sendreport.sh | 6 ++ src/CMakeLists.txt | 12 +++ src/bind_sqlite.c | 95 ++++++++++++++++++++ src/bindings.c | 3 + src/bindings.h | 1 + src/sqlite.c | 204 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 322 insertions(+) create mode 100644 src/bind_sqlite.c create mode 100644 src/sqlite.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f6953b7f..15629bf4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,7 @@ project (eressea-server C) enable_testing() find_package (LibXml2) +find_package (SQLite3) find_package (Curses) find_package (Lua REQUIRED) find_package (ToLua REQUIRED) diff --git a/process/sendreport.sh b/process/sendreport.sh index 81d16813c..93d52f0b4 100755 --- a/process/sendreport.sh +++ b/process/sendreport.sh @@ -39,3 +39,9 @@ fi source ${FACTION}.sh $EMAIL || reply "Unbekannte Partei $FACTION" +if [ -e $ERESSEA/game-$GAME/eressea.db ]; then + SQL="select email from faction f left join faction_data fd on fd.faction_id=f.id where f.game_id=$GAME AND fd.code='$FACTION' and fd.turn=(select max(turn) from faction_data fx where fx.faction_id=f.id)" + OWNER=$(sqlite3 $ERESSEA/game-$GAME/eressea.db "$SQL") + echo "Der Report Deiner Partei wurde an ${EMAIL} gesandt." \ + | mutt -s "Reportnachforderung Partei ${FACTION}" $OWNER +fi diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 499b36409..81a43e002 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -157,6 +157,13 @@ set(SERVER_SRC bind_unit.c ) +if (SQLITE3_FOUND) +set (SERVER_SRC ${SERVER_SRC} + sqlite.c + bind_sqlite.c +) +endif (SQLITE3_FOUND) + if (CURSES_FOUND) set (SERVER_SRC ${SERVER_SRC} gmtool.c @@ -248,6 +255,11 @@ add_test(server test_eressea) install(TARGETS eressea DESTINATION "bin") +if (SQLITE3_FOUND) +target_link_libraries(eressea ${SQLITE3_LIBRARIES}) +add_definitions(-DUSE_SQLITE) +endif(SQLITE3_FOUND) + if (CURSES_FOUND) include_directories (${CURSES_INCLUDE_DIR}) target_link_libraries(eressea ${CURSES_LIBRARIES}) diff --git a/src/bind_sqlite.c b/src/bind_sqlite.c new file mode 100644 index 000000000..e8c9b7565 --- /dev/null +++ b/src/bind_sqlite.c @@ -0,0 +1,95 @@ +/* ++-------------------+ +| | Enno Rehling +| Eressea PBEM host | Christian Schlittchen +| (c) 1998 - 2008 | Katja Zedel +| | Henning Peters ++-------------------+ + +This program may not be used, modified or distributed +without prior permission by the authors of Eressea. +*/ + +#include + +#include "bind_unit.h" +#include "bindings.h" + +#include +#include +#include + +#define LTYPE_DB TOLUA_CAST "db" + +extern int db_update_factions(sqlite3 * db, bool force, int game); +static int tolua_db_update_factions(lua_State * L) +{ + sqlite3 *db = (sqlite3 *)tolua_tousertype(L, 1, 0); + db_update_factions(db, tolua_toboolean(L, 2, 0), game_id()); + return 0; +} + +extern int db_update_scores(sqlite3 * db, bool force); +static int tolua_db_update_scores(lua_State * L) +{ + sqlite3 *db = (sqlite3 *)tolua_tousertype(L, 1, 0); + db_update_scores(db, tolua_toboolean(L, 2, 0)); + return 0; +} + +static int tolua_db_execute(lua_State * L) +{ + sqlite3 *db = (sqlite3 *)tolua_tousertype(L, 1, 0); + const char *sql = tolua_tostring(L, 2, 0); + + int res = sqlite3_exec(db, sql, 0, 0, 0); + + lua_pushinteger(L, res); + return 1; +} + +static int tolua_db_close(lua_State * L) +{ + sqlite3 *db = (sqlite3 *)tolua_tousertype(L, 1, 0); + sqlite3_close(db); + return 0; +} + +static int tolua_db_create(lua_State * L) +{ + sqlite3 *db; + const char *dbname = tolua_tostring(L, 1, 0); + int result = sqlite3_open_v2(dbname, &db, SQLITE_OPEN_READWRITE, 0); + if (result == SQLITE_OK) { + tolua_pushusertype(L, (void *)db, LTYPE_DB); + return 1; + } + return 0; +} + +int tolua_sqlite_open(lua_State * L) +{ + /* register user types */ + + tolua_usertype(L, LTYPE_DB); + + tolua_module(L, NULL, 0); + tolua_beginmodule(L, NULL); + { + tolua_cclass(L, LTYPE_DB, LTYPE_DB, TOLUA_CAST "", NULL); + tolua_beginmodule(L, LTYPE_DB); + { + tolua_function(L, TOLUA_CAST "open", &tolua_db_create); + tolua_function(L, TOLUA_CAST "close", &tolua_db_close); + + tolua_function(L, TOLUA_CAST "update_factions", + &tolua_db_update_factions); + tolua_function(L, TOLUA_CAST "update_scores", &tolua_db_update_scores); + tolua_function(L, TOLUA_CAST "execute", &tolua_db_execute); + } + tolua_endmodule(L); + + } + tolua_endmodule(L); + return 0; +} diff --git a/src/bindings.c b/src/bindings.c index b466ce35f..14eae1c56 100755 --- a/src/bindings.c +++ b/src/bindings.c @@ -1149,6 +1149,9 @@ lua_State *lua_init(const dictionary *inifile) { register_tolua_helpers(); tolua_bindings_open(L, inifile); tolua_eressea_open(L); +#ifdef USE_SQLITE + tolua_sqlite_open(L); +#endif tolua_unit_open(L); tolua_building_open(L); tolua_ship_open(L); diff --git a/src/bindings.h b/src/bindings.h index be60102a2..2db83248d 100755 --- a/src/bindings.h +++ b/src/bindings.h @@ -18,6 +18,7 @@ extern "C" { struct quicklist; struct _dictionary_; + int tolua_sqlite_open(struct lua_State *L); int tolua_bindings_open(struct lua_State *L, const struct _dictionary_ *d); int tolua_itemlist_next(struct lua_State *L); int tolua_orderlist_next(struct lua_State *L); diff --git a/src/sqlite.c b/src/sqlite.c new file mode 100644 index 000000000..aea0f5d20 --- /dev/null +++ b/src/sqlite.c @@ -0,0 +1,204 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +faction *get_faction_by_id(int uid) +{ + faction *f; + for (f = factions; f; f = f->next) { + if (f->subscription == uid) { + return f; + } + } + return NULL; +} + +/* +typedef struct stmt_cache { +sqlite3 *db; +sqlite3_stmt *stmt; +const char *sql; +int inuse; +} stmt_cache; + +#define MAX_STMT_CACHE 64 +static stmt_cache cache[MAX_STMT_CACHE]; +static int cache_insert; + +static sqlite3_stmt *stmt_cache_get(sqlite3 * db, const char *sql) +{ +int i; +sqlite3_stmt *stmt; + +for (i = 0; i != MAX_STMT_CACHE && cache[i].db; ++i) { +if (cache[i].sql == sql && cache[i].db == db) { +cache[i].inuse = 1; +stmt = cache[i].stmt; +sqlite3_reset(stmt); +sqlite3_clear_bindings(stmt); +return stmt; +} +} +if (i == MAX_STMT_CACHE) { +while (cache[cache_insert].inuse) { +cache[cache_insert].inuse = 0; +cache_insert = (cache_insert + 1) & (MAX_STMT_CACHE - 1); +} +i = cache_insert; +stmt = cache[i].stmt; +sqlite3_finalize(stmt); +} +cache[i].inuse = 1; +cache[i].db = db; +cache[i].sql = sql; +sqlite3_prepare_v2(db, sql, -1, &cache[i].stmt, NULL); +return cache[i].stmt; +} +*/ +typedef struct db_faction { + int uid; + int no; + char *email; + char *name; +} db_faction; + +static struct quicklist * +read_factions(sqlite3 * db, int game_id) { + int res; + quicklist *result = 0; + const char * sql = + "SELECT f.id, fd.code, fd.name, fd.email FROM faction f" + " LEFT OUTER JOIN faction_data fd" + " WHERE f.id=fd.faction_id AND f.game_id=? AND" + " fd.turn=(SELECT MAX(turn) FROM faction_data fx WHERE fx.faction_id=f.id)" + " ORDER BY f.id"; + sqlite3_stmt *stmt = 0; + sqlite3_prepare_v2(db, sql, -1, &stmt, 0); + sqlite3_bind_int(stmt, 1, game_id); + + res = sqlite3_step(stmt); + while (res == SQLITE_ROW) { + const char * text; + db_faction * dbf = (db_faction*)calloc(1, sizeof(db_faction)); + dbf->uid = (int)sqlite3_column_int64(stmt, 0); + text = (const char *)sqlite3_column_text(stmt, 1); + if (text) dbf->no = atoi36(text); + text = (const char *)sqlite3_column_text(stmt, 2); + if (text) dbf->name = strdup(text); + text = (const char *)sqlite3_column_text(stmt, 3); + if (text) dbf->email = strdup(text); + ql_push(&result, dbf); + res = sqlite3_step(stmt); + } + sqlite3_finalize(stmt); + return result; +} + +static int insert_faction(sqlite3 *db, int game_id, faction *f) { + const char *sql = "INSERT INTO faction (game_id, race) VALUES (?, ?)"; + sqlite3_stmt *stmt = 0; + sqlite3_prepare_v2(db, sql, -1, &stmt, 0); + sqlite3_bind_int(stmt, 1, game_id); + sqlite3_bind_text(stmt, 2, f->race->_name, -1, SQLITE_STATIC); + sqlite3_step(stmt); + sqlite3_finalize(stmt); + return (int)sqlite3_last_insert_rowid(db); +} + +static void update_faction(sqlite3 *db, const faction *f) { + char code[5]; + const char *sql = + "INSERT INTO faction_data (faction_id, code, name, email, lang, turn)" + " VALUES (?, ?, ?, ?, ?, ?)"; + sqlite3_stmt *stmt = 0; + strcpy(code, itoa36(f->no)); + sqlite3_prepare_v2(db, sql, -1, &stmt, 0); + sqlite3_bind_int(stmt, 1, f->subscription); + sqlite3_bind_text(stmt, 2, code, -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 3, f->name, -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 4, f->email, -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 5, locale_name(f->locale), -1, SQLITE_STATIC); + sqlite3_bind_int(stmt, 6, turn); + sqlite3_step(stmt); + sqlite3_finalize(stmt); +} + +int db_update_factions(sqlite3 * db, bool force, int game_id) { + quicklist *ql = read_factions(db, game_id); + faction *f; + sqlite3_exec(db, "BEGIN", 0, 0, 0); + for (f = factions; f; f = f->next) { + bool update = force; + db_faction *dbf = 0; + ql_iter it = qli_init(&ql); + while (qli_more(it)) { + db_faction *df = (db_faction*)qli_next(&it); + if (f->no == df->no || strcmp(f->email, df->email) == 0 || strcmp(f->name, df->name) == 0) { + dbf = df; + } + if (f->subscription == df->uid) { + dbf = df; + break; + } + } + if (dbf) { + if (dbf->uid != f->subscription) { + log_warning("faction %s(%d) not found in database, but matches %d\n", itoa36(f->no), f->subscription, dbf->uid); + f->subscription = dbf->uid; + } + update = (dbf->no != f->no) || (strcmp(f->email, dbf->email) != 0) || (strcmp(f->name, dbf->name) != 0); + } + else { + f->subscription = insert_faction(db, game_id, f); + log_warning("faction %s not found in database, created as %d\n", itoa36(f->no), f->subscription); + update = true; + } + if (update) { + update_faction(db, f); + log_debug("faction %s updated\n", itoa36(f->no)); + } + } + sqlite3_exec(db, "COMMIT", 0, 0, 0); + return SQLITE_OK; +} + +int db_update_scores(sqlite3 * db, bool force) +{ + /* + const char *sql_ins = + "INSERT OR FAIL INTO score (value,faction_id,turn) VALUES (?,?,?)"; + sqlite3_stmt *stmt_ins = stmt_cache_get(db, sql_ins); + const char *sql_upd = + "UPDATE score set value=? WHERE faction_id=? AND turn=?"; + sqlite3_stmt *stmt_upd = stmt_cache_get(db, sql_upd); + faction *f; + sqlite3_exec(db, "BEGIN", 0, 0, 0); + for (f = factions; f; f = f->next) { + int res; + sqlite3_bind_int(stmt_ins, 1, f->score); + sqlite3_bind_int64(stmt_ins, 2, f->subscription); + sqlite3_bind_int(stmt_ins, 3, turn); + res = sqlite3_step(stmt_ins); + if (res == SQLITE_CONSTRAINT) { + sqlite3_bind_int(stmt_upd, 1, f->score); + sqlite3_bind_int64(stmt_upd, 2, f->subscription); + sqlite3_bind_int(stmt_upd, 3, turn); + res = sqlite3_step(stmt_upd); + sqlite3_reset(stmt_upd); + } + sqlite3_reset(stmt_ins); + } + sqlite3_exec(db, "COMMIT", 0, 0, 0); + */ + return SQLITE_OK; +}