Skip to content

Commit

Permalink
Show Sqlite error message on failure
Browse files Browse the repository at this point in the history
  • Loading branch information
MisterDA authored and tmcgilchrist committed Oct 17, 2022
1 parent e0a8ad9 commit 4a8530e
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 45 deletions.
54 changes: 27 additions & 27 deletions lib/dao.ml
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ let create db =
rc INTEGER NOT NULL,
parent TEXT,
FOREIGN KEY (parent) REFERENCES builds (id) ON DELETE RESTRICT
) |} |> Db.or_fail ~cmd:"create builds";
) |} |> Db.or_fail db ~cmd:"create builds";
Sqlite3.exec db {| CREATE INDEX IF NOT EXISTS lru
ON builds (rc, used) |} |> Db.or_fail ~cmd:"create lru index";
ON builds (rc, used) |} |> Db.or_fail db ~cmd:"create lru index";
let begin_transaction = Sqlite3.prepare db "BEGIN TRANSACTION" in
let commit = Sqlite3.prepare db "COMMIT" in
let rollback = Sqlite3.prepare db {| ROLLBACK |} in
Expand All @@ -44,30 +44,30 @@ let create db =
{ db; begin_transaction; commit; rollback; add; set_used; update_rc; exists; children; delete; lru; parent }

let with_transaction t fn =
Db.exec t.begin_transaction [];
Db.exec t.db t.begin_transaction [];
match fn () with
| x -> Db.exec t.commit []; x
| exception ex -> Db.exec t.rollback []; raise ex
| x -> Db.exec t.db t.commit []; x
| exception ex -> Db.exec t.db t.rollback []; raise ex

let add ?parent ~id ~now t =
let now = format_timestamp now in
match parent with
| None -> Db.exec t.add Sqlite3.Data.[ TEXT id; TEXT now; TEXT now; NULL ];
| None -> Db.exec t.db t.add Sqlite3.Data.[ TEXT id; TEXT now; TEXT now; NULL ];
| Some parent ->
with_transaction t (fun () ->
Db.exec t.add Sqlite3.Data.[ TEXT id; TEXT now; TEXT now; TEXT parent ];
Db.exec t.update_rc Sqlite3.Data.[ INT 1L; TEXT parent ];
Db.exec t.db t.add Sqlite3.Data.[ TEXT id; TEXT now; TEXT now; TEXT parent ];
Db.exec t.db t.update_rc Sqlite3.Data.[ INT 1L; TEXT parent ];
)

let set_used ~id ~now t =
let now = format_timestamp now in
Db.exec t.set_used Sqlite3.Data.[ TEXT now; TEXT id ]
Db.exec t.db t.set_used Sqlite3.Data.[ TEXT now; TEXT id ]

let children t id =
match Db.query_one t.exists Sqlite3.Data.[ TEXT id ] with
match Db.query_one t.db t.exists Sqlite3.Data.[ TEXT id ] with
| [ INT 0L ] -> Error `No_such_id
| [ INT 1L ] ->
Db.query t.children Sqlite3.Data.[ TEXT id ] |> List.map (function
Db.query t.db t.children Sqlite3.Data.[ TEXT id ] |> List.map (function
| Sqlite3.Data.[ TEXT dep ] -> dep
| x -> Fmt.failwith "Invalid row: %a" Db.dump_row x
)
Expand All @@ -76,31 +76,31 @@ let children t id =

let delete t id =
with_transaction t (fun () ->
match Db.query_one t.parent Sqlite3.Data.[ TEXT id ] with
match Db.query_one t.db t.parent Sqlite3.Data.[ TEXT id ] with
| [ TEXT parent ] ->
Db.exec t.delete Sqlite3.Data.[ TEXT id ];
Db.exec t.update_rc Sqlite3.Data.[ INT (-1L); TEXT parent ]
Db.exec t.db t.delete Sqlite3.Data.[ TEXT id ];
Db.exec t.db t.update_rc Sqlite3.Data.[ INT (-1L); TEXT parent ]
| [ NULL ] ->
Db.exec t.delete Sqlite3.Data.[ TEXT id ]
Db.exec t.db t.delete Sqlite3.Data.[ TEXT id ]
| x -> Fmt.failwith "Invalid row: %a" Db.dump_row x
)

let lru t ~before n =
Db.query t.lru Sqlite3.Data.[ TEXT (format_timestamp before); INT (Int64.of_int n) ]
Db.query t.db t.lru Sqlite3.Data.[ TEXT (format_timestamp before); INT (Int64.of_int n) ]
|> List.map @@ function
| Sqlite3.Data.[ TEXT id ] -> id
| x -> Fmt.failwith "Invalid row: %a" Db.dump_row x

let close t =
Sqlite3.finalize t.begin_transaction |> Db.or_fail ~cmd:"finalize";
Sqlite3.finalize t.commit |> Db.or_fail ~cmd:"finalize";
Sqlite3.finalize t.rollback |> Db.or_fail ~cmd:"finalize";
Sqlite3.finalize t.add |> Db.or_fail ~cmd:"finalize";
Sqlite3.finalize t.set_used |> Db.or_fail ~cmd:"finalize";
Sqlite3.finalize t.update_rc |> Db.or_fail ~cmd:"finalize";
Sqlite3.finalize t.exists |> Db.or_fail ~cmd:"finalize";
Sqlite3.finalize t.children |> Db.or_fail ~cmd:"finalize";
Sqlite3.finalize t.delete |> Db.or_fail ~cmd:"finalize";
Sqlite3.finalize t.lru |> Db.or_fail ~cmd:"finalize";
Sqlite3.finalize t.parent |> Db.or_fail ~cmd:"finalize";
Sqlite3.finalize t.begin_transaction |> Db.or_fail t.db ~cmd:"finalize";
Sqlite3.finalize t.commit |> Db.or_fail t.db ~cmd:"finalize";
Sqlite3.finalize t.rollback |> Db.or_fail t.db ~cmd:"finalize";
Sqlite3.finalize t.add |> Db.or_fail t.db ~cmd:"finalize";
Sqlite3.finalize t.set_used |> Db.or_fail t.db ~cmd:"finalize";
Sqlite3.finalize t.update_rc |> Db.or_fail t.db ~cmd:"finalize";
Sqlite3.finalize t.exists |> Db.or_fail t.db ~cmd:"finalize";
Sqlite3.finalize t.children |> Db.or_fail t.db ~cmd:"finalize";
Sqlite3.finalize t.delete |> Db.or_fail t.db ~cmd:"finalize";
Sqlite3.finalize t.lru |> Db.or_fail t.db ~cmd:"finalize";
Sqlite3.finalize t.parent |> Db.or_fail t.db ~cmd:"finalize";
Db.close t.db
36 changes: 18 additions & 18 deletions lib/db.ml
Original file line number Diff line number Diff line change
@@ -1,52 +1,52 @@
type t = Sqlite3.db

let or_fail ~cmd x =
let or_fail db ~cmd x =
match x with
| Sqlite3.Rc.OK -> ()
| err -> Fmt.failwith "Sqlite3: %s (executing %S)" (Sqlite3.Rc.to_string err) cmd
| err -> Fmt.failwith "Sqlite3: [%s] %s (executing %S)" (Sqlite3.Rc.to_string err) (Sqlite3.errmsg db) cmd

let no_callback _ = failwith "[exec] used with a query!"

let exec_stmt ?(cb=no_callback) stmt =
let exec_stmt db ?(cb=no_callback) stmt =
let rec loop () =
match Sqlite3.step stmt with
| Sqlite3.Rc.DONE -> ()
| Sqlite3.Rc.ROW ->
let cols = Sqlite3.data_count stmt in
cb @@ List.init cols (fun i -> Sqlite3.column stmt i);
loop ()
| x -> Fmt.failwith "Sqlite3 exec error: %s" (Sqlite3.Rc.to_string x)
| x -> Fmt.failwith "Sqlite3 exec error: [%s] %s" (Sqlite3.Rc.to_string x) (Sqlite3.errmsg db)
in
loop ()

let exec_literal db sql =
Sqlite3.exec db sql |> or_fail ~cmd:sql
Sqlite3.exec db sql |> or_fail db ~cmd:sql

let bind stmt values =
Sqlite3.reset stmt |> or_fail ~cmd:"reset";
List.iteri (fun i v -> Sqlite3.bind stmt (i + 1) v |> or_fail ~cmd:"bind") values
let bind db stmt values =
Sqlite3.reset stmt |> or_fail db ~cmd:"reset";
List.iteri (fun i v -> Sqlite3.bind stmt (i + 1) v |> or_fail db ~cmd:"bind") values

let exec stmt values =
bind stmt values;
exec_stmt stmt
let exec db stmt values =
bind db stmt values;
exec_stmt db stmt

let query stmt values =
bind stmt values;
let query db stmt values =
bind db stmt values;
let results = ref [] in
let cb row =
results := row :: !results
in
exec_stmt ~cb stmt;
exec_stmt db ~cb stmt;
List.rev !results

let query_one stmt values =
match query stmt values with
let query_one db stmt values =
match query db stmt values with
| [row] -> row
| [] -> failwith "No results from SQL query!"
| _ -> failwith "Multiple results from SQL query!"

let query_some stmt values =
match query stmt values with
let query_some db stmt values =
match query db stmt values with
| [] -> None
| [row] -> Some row
| _ -> failwith "Multiple results from SQL query!"
Expand Down

0 comments on commit 4a8530e

Please sign in to comment.