2022-07-10 19:40:26 +00:00
# include "MigrationRunner.h"
2022-10-24 22:20:36 +00:00
# include "BrickByBrickFix.h"
2022-10-30 07:38:43 +00:00
# include "CDClientDatabase.h"
# include "Database.h"
# include "Game.h"
2022-07-10 19:40:26 +00:00
# include "GeneralUtils.h"
2022-10-30 07:38:43 +00:00
# include "dLogger.h"
2022-07-10 19:40:26 +00:00
2022-10-30 07:38:43 +00:00
# include <istream>
Migration LoadMigration ( std : : string path ) {
Migration migration { } ;
std : : ifstream file ( " ./migrations/ " + path ) ;
if ( file . is_open ( ) ) {
std : : string line ;
std : : string total = " " ;
while ( std : : getline ( file , line ) ) {
total + = line ;
}
file . close ( ) ;
migration . name = path ;
migration . data = total ;
}
return migration ;
}
2022-07-10 19:40:26 +00:00
void MigrationRunner : : RunMigrations ( ) {
2022-10-24 22:20:36 +00:00
auto * stmt = Database : : CreatePreppedStmt ( " CREATE TABLE IF NOT EXISTS migration_history (name TEXT NOT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP()); " ) ;
stmt - > execute ( ) ;
2022-07-28 13:39:57 +00:00
delete stmt ;
sql : : SQLString finalSQL = " " ;
2022-10-24 22:20:36 +00:00
bool runSd0Migrations = false ;
2022-10-30 07:38:43 +00:00
for ( const auto & entry : GeneralUtils : : GetFileNamesFromFolder ( " ./migrations/dlu/ " ) ) {
auto migration = LoadMigration ( " dlu/ " + entry ) ;
2022-07-28 13:39:57 +00:00
if ( migration . data . empty ( ) ) {
continue ;
}
stmt = Database : : CreatePreppedStmt ( " SELECT name FROM migration_history WHERE name = ?; " ) ;
2022-11-03 03:53:45 +00:00
stmt - > setString ( 1 , migration . name . c_str ( ) ) ;
2022-10-24 22:20:36 +00:00
auto * res = stmt - > executeQuery ( ) ;
2022-07-28 13:39:57 +00:00
bool doExit = res - > next ( ) ;
delete res ;
delete stmt ;
if ( doExit ) continue ;
Game : : logger - > Log ( " MigrationRunner " , " Running migration: %s " , migration . name . c_str ( ) ) ;
2022-10-24 22:20:36 +00:00
if ( migration . name = = " 5_brick_model_sd0.sql " ) {
runSd0Migrations = true ;
} else {
2022-11-03 03:53:45 +00:00
finalSQL . append ( migration . data . c_str ( ) ) ;
2022-10-24 22:20:36 +00:00
}
2022-07-28 13:39:57 +00:00
stmt = Database : : CreatePreppedStmt ( " INSERT INTO migration_history (name) VALUES (?); " ) ;
2022-11-03 03:53:45 +00:00
stmt - > setString ( 1 , migration . name . c_str ( ) ) ;
2022-07-28 13:39:57 +00:00
stmt - > execute ( ) ;
delete stmt ;
}
2022-10-24 22:20:36 +00:00
if ( finalSQL . empty ( ) & & ! runSd0Migrations ) {
Game : : logger - > Log ( " MigrationRunner " , " Server database is up to date. " ) ;
return ;
}
2022-07-28 13:39:57 +00:00
if ( ! finalSQL . empty ( ) ) {
2022-10-24 22:20:36 +00:00
auto migration = GeneralUtils : : SplitString ( static_cast < std : : string > ( finalSQL ) , ' ; ' ) ;
std : : unique_ptr < sql : : Statement > simpleStatement ( Database : : CreateStmt ( ) ) ;
for ( auto & query : migration ) {
try {
if ( query . empty ( ) ) continue ;
2022-11-03 03:53:45 +00:00
simpleStatement - > execute ( query . c_str ( ) ) ;
2022-10-24 22:20:36 +00:00
} catch ( sql : : SQLException & e ) {
Game : : logger - > Log ( " MigrationRunner " , " Encountered error running migration: %s " , e . what ( ) ) ;
}
2022-07-28 13:39:57 +00:00
}
}
2022-10-24 22:20:36 +00:00
// Do this last on the off chance none of the other migrations have been run yet.
if ( runSd0Migrations ) {
uint32_t numberOfUpdatedModels = BrickByBrickFix : : UpdateBrickByBrickModelsToSd0 ( ) ;
Game : : logger - > Log ( " MasterServer " , " %i models were updated from zlib to sd0. " , numberOfUpdatedModels ) ;
uint32_t numberOfTruncatedModels = BrickByBrickFix : : TruncateBrokenBrickByBrickXml ( ) ;
Game : : logger - > Log ( " MasterServer " , " %i models were truncated from the database. " , numberOfTruncatedModels ) ;
}
2022-07-10 19:40:26 +00:00
}
2022-10-30 07:38:43 +00:00
void MigrationRunner : : RunSQLiteMigrations ( ) {
auto * stmt = Database : : CreatePreppedStmt ( " CREATE TABLE IF NOT EXISTS migration_history (name TEXT NOT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP()); " ) ;
stmt - > execute ( ) ;
delete stmt ;
2022-07-10 19:40:26 +00:00
2022-10-30 07:38:43 +00:00
for ( const auto & entry : GeneralUtils : : GetFileNamesFromFolder ( " ./migrations/cdserver/ " ) ) {
auto migration = LoadMigration ( " cdserver/ " + entry ) ;
2022-07-10 19:40:26 +00:00
2022-10-30 07:38:43 +00:00
if ( migration . data . empty ( ) ) continue ;
2022-07-10 19:40:26 +00:00
2022-10-30 07:38:43 +00:00
stmt = Database : : CreatePreppedStmt ( " SELECT name FROM migration_history WHERE name = ?; " ) ;
2022-11-03 03:53:45 +00:00
stmt - > setString ( 1 , migration . name . c_str ( ) ) ;
2022-10-30 07:38:43 +00:00
auto * res = stmt - > executeQuery ( ) ;
bool doExit = res - > next ( ) ;
delete res ;
delete stmt ;
if ( doExit ) continue ;
2022-07-10 19:40:26 +00:00
2022-10-30 07:38:43 +00:00
// Doing these 1 migration at a time since one takes a long time and some may think it is crashing.
// This will at the least guarentee that the full migration needs to be run in order to be counted as "migrated".
Game : : logger - > Log ( " MigrationRunner " , " Executing migration: %s. This may take a while. Do not shut down server. " , migration . name . c_str ( ) ) ;
for ( const auto & dml : GeneralUtils : : SplitString ( migration . data , ' ; ' ) ) {
if ( dml . empty ( ) ) continue ;
try {
CDClientDatabase : : ExecuteDML ( dml . c_str ( ) ) ;
} catch ( CppSQLite3Exception & e ) {
Game : : logger - > Log ( " MigrationRunner " , " Encountered error running DML command: (%i) : %s " , e . errorCode ( ) , e . errorMessage ( ) ) ;
}
}
stmt = Database : : CreatePreppedStmt ( " INSERT INTO migration_history (name) VALUES (?); " ) ;
stmt - > setString ( 1 , migration . name ) ;
stmt - > execute ( ) ;
delete stmt ;
2022-07-28 13:39:57 +00:00
}
2022-10-30 07:38:43 +00:00
Game : : logger - > Log ( " MigrationRunner " , " CDServer database is up to date. " ) ;
2022-07-10 19:40:26 +00:00
}