diff --git a/main/DB/DBAppOnly.swift b/main/DB/DBAppOnly.swift index 240af6f..4319ed5 100644 --- a/main/DB/DBAppOnly.swift +++ b/main/DB/DBAppOnly.swift @@ -33,11 +33,9 @@ extension SQLiteDatabase { do { try run(sql: "SELECT 1 FROM req LIMIT 1;") // fails if req doesnt exist createFunction("domainof") { ($0.first as! String).extractDomain() } - try run(sql: """ - BEGIN TRANSACTION; + transaction(""" INSERT INTO heap(ts,fqdn,domain,opt) SELECT ts,domain,domainof(domain),nullif(logOpt,0) FROM req; DROP TABLE req; - COMMIT; """) } catch { /* no need to migrate */ } } @@ -119,13 +117,12 @@ extension SQLiteDatabase { /// - Returns: `nil` in case no entries were transmitted. @discardableResult func dnsLogsPersist() -> SQLiteRowRange? { guard lastRowId(.cache) > 0 else { return nil } + transaction("ALTER TABLE cache RENAME TO tmp_cache; \(CreateTable.cache)") let before = lastRowId(.heap) + 1 createFunction("domainof") { ($0.first as! String).extractDomain() } - try? run(sql:""" - BEGIN TRANSACTION; - INSERT INTO heap(ts,fqdn,domain,opt) SELECT ts,dns,domainof(dns),nullif(opt&1,0) FROM cache; - DELETE FROM cache; - COMMIT; + transaction(""" + INSERT INTO heap(ts,fqdn,domain,opt) SELECT ts,dns,domainof(dns),nullif(opt&1,0) FROM tmp_cache; + DROP TABLE tmp_cache; """) let after = lastRowId(.heap) return (before > after) ? nil : (before, after) diff --git a/main/DB/DBCore.swift b/main/DB/DBCore.swift index 85a2d3e..14ebe80 100644 --- a/main/DB/DBCore.swift +++ b/main/DB/DBCore.swift @@ -91,15 +91,20 @@ class SQLiteDatabase { } } + /// `BEGIN TRANSACTION; \(sql); COMMIT;` on exception rollback. + func transaction(_ sql: String) { + do { try run(sql: "BEGIN TRANSACTION; \(sql); COMMIT;") } + catch { rollback() } + } + func ifStep(_ stmt: OpaquePointer, _ expected: Int32) throws { guard sqlite3_step(stmt) == expected else { throw SQLiteError.Step(message: errorMessage) } } - func vacuum() { - try? run(sql: "VACUUM;") - } + func vacuum() { NSLog("[SQL] VACUUM"); try? run(sql: "VACUUM;"); } + func rollback() { NSLog("[SQL] ROLLBACK"); try? run(sql: "ROLLBACK;"); } }