Commit e413a2e013eb09010af0dc7231e3f9069f02433e
1 parent
87837894
Try to rehabilitate SQLITE using SQLAPI
Showing
4 changed files
with
472 additions
and
24 deletions
Show diff stats
| 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 | ... | ... |
| 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 | + ). | ... | ... |