/* * Created by PyramIDE. * User: David René * Date: 31/08/2011 * Time: 2:09 * */ read tools/basis.anubis read system/files.anubis read system/logger.anubis read system/string.anubis read data_base/sqlite.anubis read xlib/database/alter_table.anubis read xlib/database/db_utils.anubis read xlib/database/db_get_helpers.anubis //read xlib/net_services_protocols/logger_client.anubis read xlib/types/version.anubis read migration_common_sqlite3.anubis public type Migration: migration(DB_Version version, (SQLite3DataBase, (LogLevel, String) -> One) -> Maybe(One) migrate_to, (SQLite3DataBase, (LogLevel, String) -> One) -> Maybe(One) create_tables, (SQLite3DataBase, (LogLevel, String) -> One) -> Maybe(One) create_indexes, ). define String dir_save_database = "backup/". public define Bool migration_less ( Migration a, Migration b )= db_version_less(a.version, b.version) . public define Maybe(One) backup_database ( (LogLevel, String) -> One logger, // String current_version, String db_path, String main_db_name, List(String) other_db_names, ) = // with should_copy = if file_exists(db_path + main_db_name) then // if sqlite3_open(db_path + main_db_name) is // { // error(sql_error) then false, // maybe not created yet // ok(Database db) then // with ver = get_version_settings(db), // ver != current_version // } // else false, //if should_copy then with dir_save = db_path + dir_save_database, if (Maybe(String))make_directory(dir_save) is { failure then logger(logError, "Can't create directory '"+db_path + dir_save_database+"'"); failure, success(_) then with copy_with_log = (String src, String dst) |-> if file_exists(src) then if copy_file(src, dst) is { cant_read_file then logger(logError, "Can't read source file '" + src + "'."); failure, cant_create_file then logger(logError, "Can't create destination file '" + dst + "'."); failure, copy_error then logger(logError, "Can't copy file '" + src + "' to file '" + dst + "'."); failure, copy_file_mode_error then logger(logError, "Can't get file mode for source file '" + src + "'."); failure, copy_file_times_error then logger(logError, "Can't set file times into file '" + dst + "'."); failure, copy_ok(_) then logger(logInfo, "File '" + dst + "' saved"); success(unique) } else success(unique), with copy_db = (List(String) names) |-copy_db-> if names is { [] then success(unique), [h . t] then if copy_with_log(db_path + h, dir_save + h) is { failure then failure, success(_) then copy_db(t) } }, copy_db([main_db_name . other_db_names]) } //else success(unique) . public define Maybe(One) backup_database ( (LogLevel, String) -> One logger, SQLite3DataBase db, String db_path, String main_db_name )= //we use SQLite 3.27.0 feature to backup the database. So we check the running SQLite engine version before //to proceed with v3_27 = version(3,27,0,0), with sqlite_version = if sql_query_timeout(db, "SELECT sqlite_version();", "backup_database get version") is { error(_) then logger(logError, "Can't get sqlite version for backup");failure, ok(_, cursor, _) then with sqlite_version_str = db_get_String(cursor), to_Version(sqlite_version_str) }, if sqlite_version is { failure then logger(logError, "Can't get sqlite version for backup ");failure, success(sqlite_v) then //if the SQLite engine version is < 3.27 we use old method for backup if sqlite_v.numeric +< v3_27.numeric then logger(logWarning, "The current SQLite engine v"+sqlite_v+" doesn't support vaccum into. Fallback to previous method"); backup_database(logger, db_path, main_db_name, []) else //construct the target folder for backup with dir_save = db_path + dir_save_database, if (Maybe(String))make_directory(dir_save) is { failure then logger(logError, "Can't create directory '"+db_path + dir_save_database+"'"); failure, success(_) then with filename = db_path + dir_save_database+get_current_datetime_condensed+"-"+main_db_name, if sql_query(db, "VACUUM INTO '"+filename+"';") is { error(err) then logger(logError,db_error(err, "Can't backup database into "+filename));failure, ok(_,) then logger(logInfo, "database backuped into "+filename);success(unique) } } } . // //define Maybe(One) // do_migration_loop // ( // SQLite3DataBase db, // Logger logger, // String current_version, //current version of app // String db_ver, //version found in db settings // List(Migration) migrations, // Maybe(Migration) need_to_create_table, // success in case of new DB or when no migration have been done // (SQLite3DataBase, String) -> One update_db_version, // ) = // if migrations is // { // [] then // if need_to_create_table is // { // failure then // update_db_version(db, current_version); // success(unique), // success(last) then // if last is migration(_, _, create_tables, create_indexes) then // if create_tables(db, logger) is success(_) then // if create_indexes(db, logger) is success(_) then // update_db_version(db, current_version); // success(unique) // else // failure // else // failure // }, // [h . t] then // since h is migration(version, migrate_to, _, _), // if compare_db_version(db_ver, version) < 0 then // logInfo(logger, "Migrating Database from version " + db_ver + " to version " + version); // if migrate_to(db, logger) is failure then // failure // else // do_migration_loop(db, logger, current_version, version, t, failure, update_db_version) // else // do_migration_loop(db, logger, current_version, db_ver, t, success(h), update_db_version), // }. // ///* SQLite 3 version */ //public define Maybe(One) // do_migration // ( // SQLite3DataBase db, // Logger logger, // String current_version, // (SQLite3DataBase) -> String get_db_version, // (SQLite3DataBase, String) -> One update_db_version, // List(Migration) all_migrations, // )= // if is_empty_database(db) then // new empty database // logInfo(logger, "No database found. Creating a new one..."); // do_migration_loop(db, logger, current_version, "", [], last(all_migrations), update_db_version) // else // ( // with db_version = get_db_version(db), // //if app required db version is same as db_version, there is nothing to migrate // if compare_db_version(db_version, current_version) = 0 then // logInfo(logger, "Database version "+db_version+". No database migration found."); // success(unique) // else // do_migration_loop(db, logger, current_version, db_version, all_migrations, failure, update_db_version) // ). /* SQLite 3 version hk_settings with DB_Version*/ define Maybe(One) do_table_indexes ( SQLite3DataBase db, (LogLevel, String) -> One logger, Migration _migration, (DB_Version) -> One update_db_version )= since _migration is migration(mig_version, _, create_tables, create_indexes), if create_tables(db, logger) is success(_) then if create_indexes(db, logger) is success(_) then update_db_version(mig_version); success(unique) else failure else failure . define Maybe(One) do_migration_loop ( SQLite3DataBase db, (LogLevel, String) -> One logger, // String current_version, //current version of app DB_Version db_ver, //version found in db settings List(Migration) migrations, (DB_Version) -> One update_db_version ) = if migrations is { [] then success(unique), [h . t] then since h is migration(migration_version, migrate_to, create_tables, create_indexes), if compare_db_version(db_ver, migration_version) is { less then logger(logInfo, "[less] Migrating Database from version " + db_ver + " to version " + migration_version); if migrate_to(db, logger) is failure then failure else update_db_version(migration_version); do_migration_loop(db, logger, migration_version, t, update_db_version) more then logger(logInfo, "[more] No Database migration found from version " + db_ver + " to version " + migration_version); do_migration_loop(db, logger, db_ver, t, update_db_version) equal then logger(logInfo, "[equal] No Database migration found from version " + db_ver + " to version " + migration_version); do_migration_loop(db, logger, db_ver, t, update_db_version) equal_but_sign then logger(logInfo, "Database migration found from version " + db_ver + " to version " + migration_version+ " by hash difference "); if migrate_to(db, logger) is failure then failure else update_db_version(migration_version); do_migration_loop(db, logger, migration_version, t, update_db_version) } }. public define Maybe(One) do_migration ( SQLite3DataBase db, (LogLevel, String) -> One logger, DB_Version current_db_version, (DB_Version) -> One update_db_version, List(Migration) all_migrations, )= if is_empty_database(db) then // new empty database logger(logInfo, "No database found. Creating a new one..."); if last(all_migrations) is success(migration) then do_table_indexes(db, logger, migration, update_db_version) else logger(logError, "No database migration found. Can't create Database"); failure else ( // with db_version = get_db_version, // //if app version is same as db_version, there is nothing to migrate // if compare_db_version(db_version, current_version) = 0 then // logInfo(logger, "Database version "+db_version+". No database migration found."); // success(unique) // else do_migration_loop(db, logger, current_db_version, all_migrations, update_db_version) ). public define Maybe(One) do_create_indexes ( SQLite3DataBase db, (LogLevel, String) -> One logger, List(Migration) all_migrations, )= if last(all_migrations) is { failure then logger(logCriticalError, "Index creation: migration list is empty!"); failure, success(last_migration) then if last_migration is migration(_, _, _, create_indexes) then if create_indexes(db, logger) is success(_) then success(unique) else failure }.