From 0b766c60aa2eb38d43401e06136ac1daa28abe5f Mon Sep 17 00:00:00 2001 From: Roger Sen Date: Sun, 15 Apr 2018 21:06:46 +0200 Subject: [PATCH 1/2] Create db.h and update c source files so they can find it. --- src/db.h | 23 +++++++++++++++++++++++ src/mud.h | 11 +---------- src/save.c | 1 + 3 files changed, 25 insertions(+), 10 deletions(-) create mode 100644 src/db.h diff --git a/src/db.h b/src/db.h new file mode 100644 index 0000000..89c5ccf --- /dev/null +++ b/src/db.h @@ -0,0 +1,23 @@ +/* file: db.h + * + * Headerfile for sqlite interface + */ + +#ifndef _DB_HEADER +#define _DB_HEADER + +#include +#include + +/* + * db.c + */ +bool db_open ( void ); +bool db_close ( void ); +bool db_execute ( const char *sql, ... ); +sqlite3_stmt *db_prepare (const char *sql, ...); +int db_step (sqlite3_stmt *stmt); +int db_finalize (sqlite3_stmt *stmt); +void db_migrate ( void ); + +#endif diff --git a/src/mud.h b/src/mud.h index db2422f..6c16590 100644 --- a/src/mud.h +++ b/src/mud.h @@ -13,6 +13,7 @@ #include "list.h" #include "stack.h" #include "crypt_blowfish-1.3-mini/ow-crypt.h" +#include "db.h" /************************ * Standard definitions * @@ -317,16 +318,6 @@ void save_player ( D_M *dMob ); D_M *load_player ( char *player ); D_M *load_profile ( char *player ); -/* - * db.c - */ -bool db_open ( void ); -bool db_close ( void ); -bool db_execute ( const char *sql, ... ); -sqlite3_stmt *db_prepare (const char *sql, ...); -int db_step (sqlite3_stmt *stmt); -int db_finalize (sqlite3_stmt *stmt); -void db_migrate ( void ); /******************************* * End of prototype declartion * diff --git a/src/save.c b/src/save.c index 5040d26..b2fbedd 100644 --- a/src/save.c +++ b/src/save.c @@ -7,6 +7,7 @@ /* main header file */ #include "mud.h" +#include "db.h" void save_player(D_MOBILE *dMob) { From e974d23197d351b961c2503a32d1a41c9adbef39 Mon Sep 17 00:00:00 2001 From: Roger Sen Date: Sun, 15 Apr 2018 21:07:19 +0200 Subject: [PATCH 2/2] Update db_migrate logic so it can handle schema upgrades. --- src/db.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 108 insertions(+), 4 deletions(-) diff --git a/src/db.c b/src/db.c index f4cf28c..9f0bb5d 100644 --- a/src/db.c +++ b/src/db.c @@ -6,10 +6,37 @@ /* main header file */ #include "mud.h" +#include "db.h" sqlite3 * db; sqlite3_stmt *db_prepare_internal(const char *sql, va_list vars); +int get_db_schema(); + +/* + * Array of commands to be executed by db_migrate to apply changes to the database. + * + */ + +typedef struct migration_commands { + int schema; + char *action; +} migration_commands; + +migration_commands command[] = { +/* { DB_SCHEMA, Action to upgrade the database to the DB_SCHEMA } */ + { 0, "CREATE TABLE IF NOT EXISTS players (id INTEGER PRIMARY KEY, name TEXT NOT NULL UNIQUE, password TEXT NOT NULL, level INTEGER)" }, + { 1, "CREATE TABLE IF NOT EXISTS NEXT_ID (ID DECIMAL(9,0) NOT NULL)" }, + { 1, "INSERT INTO NEXT_ID (ID) VALUES(1)"}, + {-1, NULL } // Sentinel to identify end of commands. DO NOT REMOVE. +}; + + + +/* + * Open the global database. + * + */ bool db_open() { @@ -25,6 +52,11 @@ bool db_open() return true; } +/* + * Close the global database. + * + */ + bool db_close() { if (sqlite3_close(db) != SQLITE_OK ) @@ -37,6 +69,11 @@ bool db_close() return true; } +/* + * Execute a query to the database expecting no answer. + * Used for things like DROP, INSERT, CREATE TABLE... + */ + bool db_execute(const char *sql, ...) { va_list vars; @@ -52,7 +89,6 @@ bool db_execute(const char *sql, ...) return false; } - if ( db_step(stmt) != SQLITE_DONE ) { bug("Failed to step through statement: %s", sqlite3_errmsg(db)); @@ -174,18 +210,86 @@ sqlite3_stmt *db_prepare_internal(const char *sql, va_list vars) void db_migrate() { + int db_schema = get_db_schema(); + int i = 0; + + if ( !db_open() ) + { + abort(); + } + + if (-1 == db_schema) { + if( !db_execute("CREATE TABLE IF NOT EXISTS DB_SCHEMA (db_version DECIMAL(6,0) NOT NULL)") + || !db_execute("INSERT INTO DB_SCHEMA (db_version) VALUES(1)")) { + abort(); + } + } + + db_execute("BEGIN EXCLUSIVE TRANSACTION"); + while(command[i].schema != -1) { + if (command[i].schema > db_schema) { + if ( !db_execute(command[i].action) ) { + db_execute("ROLLBACK TRANSACTION"); + abort(); + } + } + if( !db_execute("UPDATE DB_SCHEMA SET db_version = %i", command[i].schema) ) { + db_execute("ROLLBACK TRANSACTION"); + abort(); + } + i++; + } + db_execute("COMMIT TRANSACTION"); + + + if(command[i-1].schema > db_schema ) { + log_string("db_schema updated to version %d", command[i-1].schema); + } else { + log_string("Current db_schema: %d", db_schema); + } + + db_close(); + + return; +} + + +/* + * Retrieve the schema version. + * + * SELECT db_version FROM DB_SCHEMA + * + */ + +int get_db_schema() +{ + sqlite3_stmt *stmt; + int db_schema = -1; + if ( !db_open() ) { abort(); } - /* players table */ - if ( !db_execute("CREATE TABLE IF NOT EXISTS players (id INTEGER PRIMARY KEY, name TEXT NOT NULL UNIQUE, password TEXT NOT NULL, level INTEGER)") ) + stmt = db_prepare("SELECT db_version FROM DB_SCHEMA"); + + if ( stmt == NULL ) { + db_close(); + return db_schema; + } + + if ( db_step(stmt) == SQLITE_ROW ) { + db_schema = sqlite3_column_int(stmt, 0); + } + + if ( db_finalize(stmt) != SQLITE_OK ) { + bug("Failed to finalize statement: %s", sqlite3_errmsg(db)); + abort(); } db_close(); - return; + return db_schema; }