Commit e413a2e013eb09010af0dc7231e3f9069f02433e

Authored by Cédric RICARD
1 parent 87837894

Try to rehabilitate SQLITE using SQLAPI

calexium_lib/database/alter_table.anubis 0 → 100644
  1 +
  2 + *Project* Anubis
  3 +
  4 + *Title* SQLite Alter table function
  5 +
  6 + *Copyright* Copyright (c) Cédric Ricard 2007.
  7 +
  8 +
  9 +
  10 + *Author* Cédric Ricard
  11 +
  12 + *Created* 2007 02 17
  13 + *Satus* Released
  14 + *Compatibility* 1.7.10
  15 +
  16 +read tools/basis.anubis
  17 +read data_base/db_tools.anubis
  18 +read data_base/alter_table.anubis
  19 +read system/logger.anubis
  20 +read system/string.anubis
  21 +
  22 +
  23 +
  24 +public define Maybe(One)
  25 + alter_table
  26 + (
  27 + Database db,
  28 + String tableName,
  29 + String newTableQuery,
  30 + Logger log
  31 + ).
  32 +
  33 +
  34 +
  35 +
  36 +
  37 + --- That's all for the public part ! --------------------------------------------------
  38 +
  39 +define String
  40 + to_String
  41 + (
  42 + DbEntityType type
  43 + ) =
  44 + if type is
  45 + {
  46 + table then "table",
  47 + view then "view",
  48 + index then "index",
  49 + trigger then "trigger"
  50 + }.
  51 +
  52 +define One
  53 + print_list
  54 + (
  55 + List(String) l
  56 + ) =
  57 + if l is
  58 + {
  59 + [] then print(" <<<\n"),
  60 + [h . t] then print(h + ", "); print_list(t)
  61 + }.
  62 +
  63 +define Maybe(One)
  64 + my_sql_query
  65 + (
  66 + Database db,
  67 + String sql,
  68 + Logger log
  69 + ) =
  70 + if sql_query(db, sql) is
  71 + {
  72 + error(sql_error) then logError(log, "SQL ERROR: " + sql_error.text + "\n ...executing query [" + sql + "]"); failure,
  73 + ok(_,_,_) then success(unique)
  74 + }.
  75 +
  76 +define Maybe(String)
  77 + get_original_query
  78 + (
  79 + Database db,
  80 + String dbName, // alias for attached database, 'main' for main database.
  81 + DbEntityType object_type,
  82 + String tableName,
  83 + Logger log
  84 + ) =
  85 + if sql_query(db, "SELECT sql FROM " + dbName + ".sqlite_master where (type='"+to_String(object_type)+"') and tbl_name='" + tableName + "'") is
  86 + {
  87 + error(sql_error) then logError(log, "alter_table/get_original_query ERROR '" + sql_error.text + "'"); failure,
  88 + ok(_,table_cursor,_) then
  89 + if table_cursor(unique) is
  90 + {
  91 + error(sql_error) then logError(log, "alter_table/get_original_query ERROR '" + sql_error.text + "'"); failure,
  92 + no_more_row then failure, //can't find the table in sqlite_master, because the table is new
  93 + row(current) then success(text(current)(0))
  94 + }
  95 + }.
  96 +
  97 +define Bool
  98 + has_rows
  99 + (
  100 + Database db,
  101 + String tableName,
  102 + Logger log
  103 + ) =
  104 + if sql_query(db, "SELECT count(*) FROM " + tableName) is
  105 + {
  106 + error(sql_error) then logError(log, "has_rows query ERROR '" + sql_error.text + "'"); false,
  107 + ok(_,table_cursor,_) then
  108 + if table_cursor(unique) is
  109 + {
  110 + error(sql_error) then logError(log, "has_row run ERROR '" + sql_error.text + "'"); false,
  111 + no_more_row then false,
  112 + row(current) then db_integer(current)(0) /= 0
  113 + }
  114 + }.
  115 +
  116 +define List(String)
  117 + alter_table_extract_columns_list_sub
  118 + (
  119 + Int -> SQLite3Datum row,
  120 + Int colIndex
  121 + ) =
  122 + if row(colIndex) is text(name) then [name . alter_table_extract_columns_list_sub(row, colIndex+1)]
  123 + else [].
  124 +
  125 +define List(String)
  126 + alter_table_extract_columns_list
  127 + (
  128 + SQLite3HeadersOrRow -> SQLite3Row table_cursor,
  129 + Logger log
  130 + ) =
  131 + if table_cursor(headers) is
  132 + {
  133 + error(sql_error) then logError(log, "alter_table_extract_columns_list ERROR '" + sql_error.text + "'"); [],
  134 + no_more_row then [],
  135 + row(headers) then alter_table_extract_columns_list_sub(headers, 0)
  136 + }.
  137 +
  138 +define String
  139 + alter_table_extract_column_string
  140 + (
  141 + One -> DbRow table_cursor,
  142 + List(String) oldColumns,
  143 + Logger log
  144 + ) =
  145 + if table_cursor(unique) is
  146 + {
  147 + error(sql_error) then logError(log, "alter_table_extract_columns_list ERROR '" + sql_error.text + "'"); "",
  148 + no_more_row then /*logDebug(log, "Extract columns answers 'no more row'");*/ "",
  149 + row(row) then
  150 + if row(1) is db_text(name) then
  151 + with test = (String name2) |-> logDebug(log, "name: " + name + " / name2: " + name2); if name = name2 then true else false,
  152 + colString = alter_table_extract_column_string(table_cursor, oldColumns, log),
  153 + if find_element(oldColumns, test) is
  154 + {
  155 + failure then colString,
  156 + success(_) then logDebug(log, "found: " + name);
  157 + if is_empty(colString) then name else name + ", " + colString
  158 + }
  159 + else ""
  160 + }.
  161 +
  162 +// false = different, true = same
  163 +define Bool
  164 + compare_creation_queries
  165 + (
  166 + String tableName,
  167 + String query1,
  168 + String query2,
  169 + ) =
  170 + if find(tableName, query1, 0) is
  171 + {
  172 + failure then false,
  173 + success(p1) then
  174 + if find(tableName, query2, 0) is
  175 + {
  176 + failure then false,
  177 + success(p2) then
  178 + if sub_string(query1, p1, length(query1) - p1) is
  179 + {
  180 + failure then false,
  181 + success(s1) then
  182 + if sub_string(query2, p2, length(query2) - p2) is
  183 + {
  184 + failure then false,
  185 + success(s2) then s1 = s2
  186 + }
  187 + }
  188 + }
  189 + }.
  190 +
  191 +public define Maybe(One)
  192 + alter_table
  193 + (
  194 + Database db,
  195 + String dbName, // alias for attached database, 'main' for main database.
  196 + String tableName,
  197 + String newTableQuery,
  198 + Logger log
  199 + ) =
  200 + with fullTableName = dbName + "." + tableName,
  201 + if get_original_query(db, dbName, table, tableName, log) is
  202 + {
  203 + failure then
  204 + logInfo(log, "Creating table '" + fullTableName + "'... ");
  205 + if sql_query(db, newTableQuery) is error(sql_error)
  206 + then logError(log, "ERROR : " + sql_error.text); failure
  207 + else logInfo(log, " --> ok."); success(unique),
  208 + success(originalTableQuery) then
  209 + if compare_creation_queries(tableName, originalTableQuery, newTableQuery) = false then
  210 + logInfo(log, "Updating table '" + fullTableName + "' on database... ");
  211 + println(originalTableQuery);
  212 + println(newTableQuery);
  213 + if has_rows(db, fullTableName, log) is
  214 + {
  215 + false then
  216 + if my_sql_query(db, "DROP TABLE " + fullTableName, log) is failure
  217 + then failure
  218 + else if my_sql_query(db, newTableQuery, log ) is
  219 + {
  220 + failure then failure,
  221 + success(_) then logInfo(log, " --> ok."); success(unique)
  222 + },
  223 + true then
  224 + with tempNameTable = tableName + "_temp",
  225 + forget(sql_query(db, "DROP TABLE " + tempNameTable));
  226 + if my_sql_query(db, "CREATE TEMP TABLE " + tempNameTable + " AS SELECT * from " + fullTableName, log) is failure then failure else
  227 + if my_sql_query(db, "DROP TABLE " + fullTableName, log) is failure then failure else
  228 + if my_sql_query(db, newTableQuery , log) is failure then failure else
  229 + if sql_query(db, "SELECT * FROM " + tempNameTable) is
  230 + {
  231 + error(sql_error) then logError(log, "alter_table: select * tempTable ERROR '" + sql_error.text + "'"); failure,
  232 + ok(get_cols,table_cursor2,_) then
  233 + with oldColumns = get_cols(unique),
  234 + //print_list(oldColumns);
  235 + if sql_query(db, "PRAGMA " + dbName + ".table_info(" + tableName + ")") is
  236 + {
  237 + error(sql_error) then logError(log, "alter_table: pragma table_info() ERROR '" + sql_error.text + "'"); failure,
  238 + ok(_,table_cursor3,_) then
  239 + with newColumnsStr = alter_table_extract_column_string(table_cursor3, oldColumns, log),
  240 + sql = "INSERT INTO " + fullTableName + " (" + newColumnsStr + ") SELECT " + newColumnsStr + " FROM " + tempNameTable,
  241 + if sql_query(db, sql) is
  242 + {
  243 + error(sql_error) then logError(log, "alter_table ERROR '" + sql_error.text + "'\n\tquery = [" + sql + "]"); failure,
  244 + ok(_,_,_) then logInfo(log, " --> ok."); success(unique)
  245 + }
  246 + }
  247 + }
  248 + }
  249 + else
  250 + success(unique)
  251 + }.
  252 +
  253 +public define Maybe(One)
  254 + alter_table
  255 + (
  256 + Database db,
  257 + String tableName,
  258 + String newTableQuery,
  259 + Logger log
  260 + ) =
  261 + alter_table(db, "main", tableName, newTableQuery, log).
  262 +
  263 +
  264 +public define Maybe(One)
  265 + alter_view
  266 + (
  267 + Database db,
  268 + String dbName, // alias for attached database, 'main' for main database.
  269 + String viewName,
  270 + String newViewQuery,
  271 + Logger log
  272 + ) =
  273 + with fullViewName = dbName + "." + viewName,
  274 + if get_original_query(db, dbName, view, viewName, log) is
  275 + {
  276 + failure then
  277 + logInfo(log, "Creating view '" + fullViewName + "'... ");
  278 + if sql_query(db, newViewQuery) is error(sql_error)
  279 + then logError(log, "ERROR : " + sql_error.text); failure
  280 + else logInfo(log, " --> ok."); success(unique),
  281 + success(originalViewQuery) then
  282 + if compare_creation_queries(viewName, originalViewQuery, newViewQuery) = false then
  283 + logInfo(log, "Updating view '" + fullViewName + "' on database... ");
  284 + println(originalViewQuery);
  285 + println(newViewQuery);
  286 + if my_sql_query(db, "DROP VIEW " + fullViewName, log) is failure
  287 + then failure
  288 + else if my_sql_query(db, newViewQuery, log ) is
  289 + {
  290 + failure then failure,
  291 + success(_) then logInfo(log, " --> ok."); success(unique)
  292 + }
  293 + else
  294 + success(unique)
  295 + }.
  296 +
  297 +public define Maybe(One)
  298 + alter_view
  299 + (
  300 + Database db,
  301 + String viewName,
  302 + String newViewQuery,
  303 + Logger log
  304 + ) =
  305 + alter_view(db, "main", viewName, newViewQuery, log).
  306 +
... ...
calexium_lib/database/migration.anubis
... ... @@ -10,10 +10,10 @@ read tools/basis.anubis
10 10 read system/files.anubis
11 11 read system/logger.anubis
12 12 read system/string.anubis
13   -read data_base/alter_table.anubis
14 13 read data_base/db_tools.anubis
15 14  
16 15 read calexium_lib/database/db_utils.anubis
  16 +read calexium_lib/database/alter_table.anubis
17 17 read calexium_lib/net_services_protocols/logger_service.anubis
18 18  
19 19 read mf_constants.anubis
... ... @@ -60,14 +60,6 @@ public define Int
60 60 },
61 61 compare(split(version1, '.'), split(version2, '.')).
62 62  
63   -public define One
64   - update_version_settings
65   - (
66   - Database db,
67   - String version
68   - )=
69   - update_settings(db, "MF_version", version).
70   -
71 63 public define Maybe(One)
72 64 backup_database
73 65 (
... ... @@ -88,7 +80,7 @@ public define Maybe(One)
88 80 // }
89 81 // else false,
90 82  
91   - if should_copy then
  83 + //if should_copy then
92 84 with dir_save = db_path + dir_save_database,
93 85 if (Maybe(String))make_directory(dir_save) is
94 86 {
... ... @@ -119,7 +111,7 @@ public define Maybe(One)
119 111 },
120 112 copy_db([main_db_name . other_db_names])
121 113 }
122   - else success(unique)
  114 + //else success(unique)
123 115 .
124 116  
125 117  
... ... @@ -144,7 +136,8 @@ define Maybe(One)
144 136 String current_version,
145 137 String db_ver,
146 138 List(Migration) migrations,
147   - Maybe(Migration) need_to_create_table // success in case of new DB or when no migration have been done
  139 + Maybe(Migration) need_to_create_table, // success in case of new DB or when no migration have been done
  140 + (Database, String) -> One update_db_version,
148 141 ) =
149 142 if migrations is
150 143 {
... ... @@ -152,13 +145,13 @@ define Maybe(One)
152 145 if need_to_create_table is
153 146 {
154 147 failure then
155   - update_version_settings(db, current_version);
  148 + update_db_version(db, current_version);
156 149 success(unique),
157 150 success(last) then
158 151 if last is migration(_, _, create_tables, create_indexes) then
159 152 if create_tables(db, logger) is success(_) then
160 153 if create_indexes(db, logger) is success(_) then
161   - update_version_settings(db, current_version);
  154 + update_db_version(db, current_version);
162 155 success(unique)
163 156 else
164 157 failure
... ... @@ -172,9 +165,9 @@ define Maybe(One)
172 165 if migrate_to(db, logger) is failure then
173 166 failure
174 167 else
175   - do_migration_loop(db, logger, current_version, version, t, failure)
  168 + do_migration_loop(db, logger, current_version, version, t, failure, update_db_version)
176 169 else
177   - do_migration_loop(db, logger, current_version, db_ver, t, success(h)),
  170 + do_migration_loop(db, logger, current_version, db_ver, t, success(h), update_db_version),
178 171 }.
179 172  
180 173  
... ... @@ -185,17 +178,17 @@ public define Maybe(One)
185 178 Database db,
186 179 Logger logger,
187 180 String current_version,
188   - (Database) |-> String get_db_version,
189   - (Database, String) |-> One update_db_version,
  181 + (Database) -> String get_db_version,
  182 + (Database, String) -> One update_db_version,
190 183 List(Migration) all_migrations,
191 184 )=
192 185 if is_empty_database(db) then // new empty database
193 186 logInfo(logger, "No database found. Creating a new one...");
194   - do_migration_loop(db, logger, current_version, "", [], last(all_migrations))
  187 + do_migration_loop(db, logger, current_version, "", [], last(all_migrations), update_db_version)
195 188 else
196 189 (
197   - with db_version = get_version_settings(db),
198   - do_migration_loop(db, logger, current_version, db_version, all_migrations, failure)
  190 + with db_version = get_db_version(db),
  191 + do_migration_loop(db, logger, current_version, db_version, all_migrations, failure, update_db_version)
199 192 ).
200 193  
201 194 public define Maybe(One)
... ...
calexium_lib/database/migration_common.anubis
... ... @@ -9,8 +9,8 @@
9 9 read tools/basis.anubis
10 10 read system/logger.anubis
11 11 read data_base/db_tools.anubis
12   -read data_base/alter_table.anubis
13   -read data_base/sqlite_foreign_key.anubis
  12 +read alter_table.anubis
  13 +read sqlite_foreign_key.anubis
14 14  
15 15 read calexium_lib/database/db_utils.anubis
16 16 read calexium_lib/net_services_protocols/logger_service.anubis
... ... @@ -31,7 +31,7 @@ public define Bool
31 31 String dbName,
32 32 String table_name
33 33 )=
34   - if sql_query_timeout(db, "SELECT * FROM " + dbName + ".sqlite_master WHERE type ='table' AND name = @table_name", [bind_String("@table_name", table_name)], "is_table_exists("+table_name+")") is
  34 + if sql_query_timeout(db, "SELECT * FROM " + dbName + ".sqlite_master WHERE type ='table' AND name = :table_name", [db_bind("table_name", db_text(table_name))], "is_table_exists("+table_name+")") is
35 35 {
36 36 error(_) then false, //error in the SQL request
37 37 ok(_, cursor, _) then
... ...
calexium_lib/database/sqlite_foreign_key.anubis 0 → 100644
  1 +
  2 + *Project* Anubis
  3 +
  4 + *Title* SQLite Foreign Key functions
  5 +
  6 + *Copyright* Copyright (c) Cédric Ricard 2007.
  7 +
  8 +
  9 +
  10 + *Author* Cédric Ricard
  11 +
  12 + *Created* 2007 12 21
  13 + *Satus* Released
  14 + *Compatibility* 1.8.4
  15 +
  16 +read tools/basis.anubis
  17 +read data_base/sqlite.anubis
  18 +read data_base/db_tools.anubis
  19 +read system/logger.anubis
  20 +
  21 +
  22 +
  23 +define Maybe(One)
  24 + my_sql_query
  25 + (
  26 + Database db,
  27 + String sql,
  28 + Logger log
  29 + ) =
  30 + if sql_query(db, sql) is
  31 + {
  32 + error(sql_error) then logError(log, "SQL ERROR: " + sql_error.text + "\n ...executing query [" + sql + "]"); failure,
  33 + ok(_,_,_) then success(unique)
  34 + }.
  35 +
  36 +public define Maybe(One)
  37 + alter_trigger
  38 + (
  39 + Database db,
  40 + String trigger_name,
  41 + String sql,
  42 + Logger log
  43 + ) =
  44 + if sql_query(db, "SELECT sql FROM sqlite_master WHERE type = 'trigger' AND name = " + db_make_sql_string(trigger_name)) is
  45 + {
  46 + error(sql_error) then logError(log, "SQL ERROR: " + sql_error.text + "\n ...looking for trigger named [" + trigger_name + "]"); failure,
  47 + ok(_,cursor,_) then
  48 + if cursor(unique) is
  49 + {
  50 + error(sql_error) then logError(log, "alter_trigger ERROR '" + sql_error.text + "'"); failure,
  51 + no_more_row then my_sql_query(db, sql, log),
  52 + row(current) then
  53 + with old_sql = text(current)(0),
  54 + if old_sql /= sql then
  55 + logDebug(log, "Old trigger was:\n" + old_sql + "\n");
  56 + logDebug(log, "New trigger is:\n" + sql + "\n");
  57 + logInfo(log, "Updating trigger '" + trigger_name + "'...");
  58 + forget(my_sql_query(db, "DROP TRIGGER [" + trigger_name + "]", log));
  59 + if my_sql_query(db, sql, log) is success(_) then logInfo (log, " --> ok."); success(unique)
  60 + else logError(log, " --> error!"); failure
  61 + else
  62 + success(unique)
  63 + }
  64 + }.
  65 +
  66 +
  67 +public type FK_Null:
  68 + null,
  69 + not_null.
  70 +
  71 +public type FK_Cascade:
  72 + delete_in_cascade,
  73 + block_if_children.
  74 +
  75 +public define Maybe(One)
  76 + make_foreign_key
  77 + (
  78 + Database db,
  79 + String table_name,
  80 + String field_name,
  81 + String foreign_table_name,
  82 + String foreign_field_name,
  83 + FK_Null fk_null,
  84 + FK_Cascade fk_cascade,
  85 + Logger log
  86 + ) =
  87 + with constrait_name = table_name + "__" + field_name + "__" + foreign_table_name,
  88 + sql_create =
  89 + "CREATE TRIGGER [fki__" + constrait_name + "] \n"
  90 + + "BEFORE INSERT ON [" + table_name + "] \n"
  91 + + "FOR EACH ROW BEGIN \n"
  92 + + " SELECT RAISE(ROLLBACK, 'insert on table \"" + table_name + "\" violates foreign key constraint \"fki__" + constrait_name + "\"') \n"
  93 + + " WHERE " + (if fk_null is null then " NEW.[" + field_name + "] IS NOT NULL AND \n" else "\n")
  94 + + " (SELECT [" + foreign_field_name + "] FROM [" + foreign_table_name + "] WHERE [" + foreign_field_name + "] = NEW.[" + field_name + "]) IS NULL; \n"
  95 + + "END",
  96 + sql_update =
  97 + "CREATE TRIGGER [fku__" + constrait_name + "] \n"
  98 + + "BEFORE UPDATE ON [" + table_name + "] \n"
  99 + + "FOR EACH ROW BEGIN \n"
  100 + + " SELECT RAISE(ROLLBACK, 'update on table \"" + table_name + "\" violates foreign key constraint \"fku__" + constrait_name + "\"') \n"
  101 + + " WHERE " + (if fk_null is null then " NEW.[" + field_name + "] IS NOT NULL AND \n" else "\n")
  102 + + " (SELECT [" + foreign_field_name + "] FROM [" + foreign_table_name + "] WHERE [" + foreign_field_name + "] = NEW.[" + field_name + "]) IS NULL; \n"
  103 + + "END",
  104 + sql_delete =
  105 + "CREATE TRIGGER [fkd__" + constrait_name + "] \n"
  106 + + "BEFORE DELETE ON [" + foreign_table_name + "] \n"
  107 + + "FOR EACH ROW BEGIN \n"
  108 + + if fk_cascade is {
  109 + delete_in_cascade then
  110 + " DELETE from [" + table_name + "] WHERE [" + field_name + "] = OLD.[" + foreign_field_name + "];\n",
  111 + block_if_children then
  112 + " SELECT RAISE(ROLLBACK, 'delete on table \"" + foreign_table_name + "\" violates foreign key constraint \"fku__" + constrait_name + "\"') \n"
  113 + + " WHERE (SELECT [" + field_name + "] FROM [" + table_name + "] WHERE [" + field_name + "] = OLD.[" + foreign_field_name + "]) IS NOT NULL; \n"
  114 + }
  115 + + "END",
  116 + if alter_trigger(db, "fki__" + constrait_name, sql_create, log) is failure
  117 + then failure
  118 + else if alter_trigger(db, "fku__" + constrait_name, sql_update, log) is failure
  119 + then failure
  120 + else if alter_trigger(db, "fkd__" + constrait_name, sql_delete, log) is failure
  121 + then failure
  122 + else
  123 + success(unique).
  124 +
  125 +
  126 +
  127 +public define Maybe(One)
  128 + make_foreign_key
  129 + (
  130 + Database db,
  131 + String table_name,
  132 + String field_name,
  133 + String foreign_table_name,
  134 + String foreign_field_name,
  135 + Bool field_can_be_null,
  136 + Bool delete, //delete_in_cascade ?
  137 + Logger log
  138 + ) =
  139 + make_foreign_key
  140 + (
  141 + db,
  142 + table_name,
  143 + field_name,
  144 + foreign_table_name,
  145 + foreign_field_name,
  146 + if field_can_be_null then null else not_null,
  147 + if delete then delete_in_cascade else block_if_children,
  148 + log
  149 + ).
... ...