From 1adb1b605936750dcf160827cf1696874db973f0 Mon Sep 17 00:00:00 2001 From: David RENE Date: Thu, 1 Sep 2011 15:38:58 +0000 Subject: [PATCH] add support of sqlite3 in the migration tools --- calexium_lib/database/db_utils.anubis | 30 +++++++++++++----------------- calexium_lib/database/migration_common_sqlite3.anubis | 195 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ calexium_lib/database/migration_sqlite3.anubis | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ calexium_lib/database/sqlite_foreign_key.anubis | 8 +------- 4 files changed, 413 insertions(+), 24 deletions(-) create mode 100644 calexium_lib/database/migration_common_sqlite3.anubis create mode 100644 calexium_lib/database/migration_sqlite3.anubis diff --git a/calexium_lib/database/db_utils.anubis b/calexium_lib/database/db_utils.anubis index 72ed529..3c102c7 100644 --- a/calexium_lib/database/db_utils.anubis +++ b/calexium_lib/database/db_utils.anubis @@ -11,6 +11,7 @@ read tools/basis.anubis read system/logger.anubis read system/string.anubis read data_base/db_tools.anubis +read data_base/sqlite.anubis read calexium_lib/net_services_protocols/logger_service.anubis @@ -89,29 +90,24 @@ public define DbQueryResult }. // deprecated. Use one of the previous ones. -public define Maybe(SQLite3HeadersOrRow -> DbRow) +public define SQLite3QueryResult sql_query_timeout ( - Database db, //database handle + SQLite3DataBase db, //database handle String sql_query, //sql query itself + List(SQLite3Bind) initial_bindings, String msg //message to be shown if an error occure ) = //we try with 30 sec of timeout with t0 = unow, - if sql_query_timeout(db, sql_query, [], 60, 100, (DbError _) |-> false) is + if sql_query_timeout(db, sql_query, initial_bindings, 60, 100) is { error(sql_error) then logError("DB", db_error(sql_error,msg)); __logLongQueries(t0, sql_query); - failure, + error(sql_error), ok(headers, cursor, reset) then __logLongQueries(t0, sql_query); - success((SQLite3HeadersOrRow h_or_r) |-> if h_or_r is - { - headers then - with cols = map((String c) |-> (DbDatum)db_text(c), headers(unique)), - row((Int n) |-> force(nth(n, cols), no_such_column)), - next_row then cursor(unique) - }) + ok(headers, cursor, reset) }. // -- Extractors HELPERS --------------- @@ -135,10 +131,10 @@ public define List(String) public define List(String) db_get_string_list ( - SQLite3HeadersOrRow -> DbRow table_cursor, - List(String) so_far + One -> SQLite3Row table_cursor, + List(String) so_far ) = - if table_cursor(next_row) is + if table_cursor(unique) is { error(sql_error) then logError("DB", db_error(sql_error, "db_get_string_list")); reverse(so_far), no_more_row then reverse(so_far), //can't find the symbol in the table, because the row is empty @@ -151,10 +147,10 @@ public define List(String) public define List(Int) db_get_integer_list ( - SQLite3HeadersOrRow -> DbRow table_cursor, - List(Int) so_far + One -> SQLite3Row table_cursor, + List(Int) so_far ) = - if table_cursor(next_row) is + if table_cursor(unique) is { error(sql_error) then logError("DB", db_error(sql_error, "db_get_integer_list")); reverse(so_far), no_more_row then reverse(so_far), //can't find the symbol in the table, because the row is empty diff --git a/calexium_lib/database/migration_common_sqlite3.anubis b/calexium_lib/database/migration_common_sqlite3.anubis new file mode 100644 index 0000000..a89db40 --- /dev/null +++ b/calexium_lib/database/migration_common_sqlite3.anubis @@ -0,0 +1,195 @@ +/* + * Created by PyramIDE. + * User: ricard + * Date: 03/12/2008 + * Time: 13:07 + * + */ + +read tools/basis.anubis +read system/logger.anubis +read data_base/sqlite.anubis +read data_base/alter_table.anubis //for sqlite3 version of alter_table +read data_base/db_types.anubis //FK... +read data_base/sqlite_foreign_key.anubis + +read calexium_lib/database/db_utils.anubis +read calexium_lib/net_services_protocols/logger_service.anubis + + read ezmailbox_constants.anubis + + +public type DbTable: + table(String name, String create_query), + table(String db_name, String name, String create_query), + view(String name, String create_query). + + +public define Bool + is_table_exists + ( + SQLite3DataBase db, + String dbName, + String table_name + )= + if sql_query_timeout(db, "SELECT * FROM " + dbName + ".sqlite_master WHERE type ='table' AND tbl_name =:table_name", [bind_String(":table_name", table_name)], "is_table_exists("+table_name+")") is + { + error(_) then false, //error in the SQL request + ok(_, cursor, _) then + if cursor(unique) is + { + error(_) then false, + no_more_row then false, + row(current) then true + } + }. + +public define Bool + is_table_exists + ( + SQLite3DataBase db, + String table_name + )= + is_table_exists(db, "main", table_name). + +public define Bool + is_empty_database + ( + SQLite3DataBase db, + String dbName, + )= + if sql_query_timeout(db, "SELECT * FROM " + dbName + ".sqlite_master", [], "is_empty_database("+dbName+")") is + { + error(_) then true, //error in the SQL request + ok(_, cursor, _) then + if cursor(unique) is + { + error(_) then true, + no_more_row then true, + row(current) then false + } + }. + +public define Bool + is_empty_database + ( + SQLite3DataBase db, + )= + is_empty_database(db, "main"). + +public define Maybe(One) + drop_all_triggers + ( + SQLite3DataBase db, + Logger log + ) = + if sqlite3_query(db, "SELECT name FROM sqlite_master WHERE type = 'trigger'", []) is + { + error(err) then logError(log, db_error(err, "drop_all_triggers")); failure, + ok(_, cursor, _) then + with drop_trigger = (String name) |-> if sqlite3_query(db, "DROP TRIGGER " + name, []) is + { + error(err2) then logError(log, db_error(err2, "Failed to drop trigger '" + name + "'")), + ok(_, cursor, _) then unique + }, + map_forget(drop_trigger, db_get_string_list(cursor, [])); + success(unique) + }. + +public define Maybe(One) + create_tables + ( + SQLite3DataBase db, + Logger logger, + List(DbTable) tables, + String version_string + ) = + if tables is + { + [] then success(unique), + [h . t] then + if h is + { + table(table_name, create_string) then + if alter_table(db, table_name, create_string, logger) is + { + failure then logError(logger, "Version "+version_string+": Can't create '"+table_name+"' table"); failure, + success(_) then create_tables(db, logger, t, version_string) + }, + table(db_name, table_name, create_string) then + if alter_table(db, db_name, table_name, create_string, logger) is + { + failure then logError(logger, "Version "+version_string+": Can't create '"+db_name+"."+table_name+"' table"); failure, + success(_) then create_tables(db, logger, t, version_string) + }, + view(view_name, create_string) then + if alter_view(db, view_name, create_string, logger) is + { + failure then logError(logger, "Version "+version_string+": Can't create '"+view_name+"' view"); failure, + success(_) then create_tables(db, logger, t, version_string) + }, + } + }. + + +public define Maybe(One) + create_indexes + ( + SQLite3DataBase db, + Logger logger, + List(String) indexes, + String version_string + )= + if indexes is + { + [] then success(unique), + [h . t] then + if sql_query_timeout(db, h, [], "Version "+version_string+": create indexes") is + { + error(_) then failure, + ok(_,_,_) then create_indexes(db, logger, t, version_string) + } + }. + + +public define One + make_foreign_key + ( + SQLite3DataBase db, + String table_name, + String field_name, + String foreign_table_name, + String foreign_field_name, + Bool fk_null, + Bool fk_cascade, + Logger log + ) = + if (Maybe(One))make_foreign_key(db, table_name, field_name, foreign_table_name, foreign_field_name, fk_null, fk_cascade, log) is + { + failure then + logError(log, "Can't create foreign key constraint between '"+table_name+"' and '"+foreign_table_name+"' tables"), + success(_) then + unique + }. + +public define Maybe(One) + make_foreign_keys + ( + SQLite3DataBase db, + Logger logger, + List((String, String, String, String, FK_Null, FK_Cascade)) relations, + String version_string + )= + if relations is + { + [] then success(unique), + [h . t] then + if h is (table_name, field_name, foreign_table_name, foreign_field_name, fk_null, fk_cascade) then + if (Maybe(One))make_foreign_key(db, table_name, field_name, foreign_table_name, foreign_field_name, fk_null, fk_cascade, logger) is + { + failure then + logError(logger, "Version "+version_string+": Can't create foreign key constraint between '"+table_name+"' and '"+foreign_table_name+"' tables"); failure, + success(_) then + make_foreign_keys(db, logger, t, version_string) + } + }. diff --git a/calexium_lib/database/migration_sqlite3.anubis b/calexium_lib/database/migration_sqlite3.anubis new file mode 100644 index 0000000..259a023 --- /dev/null +++ b/calexium_lib/database/migration_sqlite3.anubis @@ -0,0 +1,204 @@ +/* + * 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 calexium_lib/database/alter_table.anubis +read calexium_lib/net_services_protocols/logger_service.anubis + +read migration_common_sqlite3.anubis + + +define String dir_save_database = "/db_backup/". + + +/** + * Compare two version string. Returns -1 if first is lower than second, 1 if first is greater than second, and 0 if equals. + */ +public define Int + compare_db_version + ( + String version1, + String version2 + ) = + with compare = (List(String) v1, List(String) v2) |-compare-> (Int) + if v1 is + { + [] then + if v2 is + { + [] then 0, + [h2 . t2] then -1 + }, + [h1 . t1] then + if v2 is + { + [] then 1, + [h2 . t2] then + if h1 = h2 then compare(t1, t2) + else + with v1i = force_Type(decimal_scan(h1), 0), + v2i = force_Type(decimal_scan(h2), 0), + if v1i < v2i then -1 + else if v1i > v2i then 1 + else 0 + }, + }, + compare(split(version1, '.'), split(version2, '.')). + +public define Maybe(One) + backup_database + ( + Logger 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 logError(logger, "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 logError(logger, "Can't read source file '" + src + "'."); failure, + cant_create_file then logError(logger, "Can't create destination file '" + dst + "'."); failure, + copy_error then logError(logger, "Can't copy file '" + src + "' to file '" + dst + "'."); failure, + copy_file_mode_error then logError(logger, "Can't get file mode for source file '" + src + "'."); failure, + copy_file_times_error then logError(logger, "Can't set file times into file '" + dst + "'."); failure, + copy_ok(_) then logInfo(logger, "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 type Migration: + migration(String version, + (SQLite3DataBase, Logger) -> Maybe(One) migrate_to, + (SQLite3DataBase, Logger) -> Maybe(One) create_tables, + (SQLite3DataBase, Logger) -> Maybe(One) create_indexes, + ). + + + +define Maybe(One) + do_migration_loop + ( + SQLite3DataBase db, + Logger logger, + String current_version, + String db_ver, + 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 + if h is migration(version, migrate_to, _, _) then + 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), + do_migration_loop(db, logger, current_version, db_version, all_migrations, failure, update_db_version) + ). + +public define Maybe(One) + do_create_indexes + ( + SQLite3DataBase db, + Logger logger, + String current_version, + List(Migration) all_migrations, + )= + if last(all_migrations) is + { + failure then logCriticalError(logger, "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 + }. diff --git a/calexium_lib/database/sqlite_foreign_key.anubis b/calexium_lib/database/sqlite_foreign_key.anubis index d26c0cf..88b32f3 100644 --- a/calexium_lib/database/sqlite_foreign_key.anubis +++ b/calexium_lib/database/sqlite_foreign_key.anubis @@ -17,6 +17,7 @@ read tools/basis.anubis read data_base/sqlite.anubis read data_base/db_tools.anubis read system/logger.anubis +read data_base/db_types.anubis @@ -64,13 +65,6 @@ public define Maybe(One) }. -public type FK_Null: - null, - not_null. - -public type FK_Cascade: - delete_in_cascade, - block_if_children. public define Maybe(One) make_foreign_key -- libgit2 0.21.4