# # patch "database.ml" # from [f1bb243b8ab4e391f3f8ef9bc39f956ac881785c] # to [0a59a5a2fdccf2a72da9bb14afc92d709932e6dc] # # patch "mlsqlite/ocaml-sqlite3.c" # from [91b05b4b9f6dc8e1320b24d06f821ea9f080dc43] # to [2625b402bdfbf6c64f5fccc95417fb400eff5751] # # patch "mlsqlite/sqlite3.ml" # from [b33ce0ac0c67b7d64039f2a9322128e8d38d49ee] # to [eb012c8336ff254b7d50af97f4aa7cb68559f5be] # # patch "mlsqlite/sqlite3.mli" # from [8c9624c03f134ddb2a0c1876f8e6b1c5accefd71] # to [3cc1e7b6268c2fdf367ecdc0f4e5b6c8b2fe54c8] # ======================================================================== --- database.ml f1bb243b8ab4e391f3f8ef9bc39f956ac881785c +++ database.ml 0a59a5a2fdccf2a72da9bb14afc92d709932e6dc @@ -151,18 +151,18 @@ | _ -> g -let with_fetch_children db f = - Sqlite3.with_stmt - db "SELECT child FROM revision_ancestry WHERE parent = ?" - (fun stmt -> - f - (fun id f init -> - Sqlite3.reset stmt ; - Sqlite3.bind stmt 1 (`TEXT id) ; - Sqlite3.fold_rows - (fun acc stmt -> f acc (Sqlite3.column_text stmt 0)) - init - stmt)) +let fetch_children db = + let stmt = lazy + (Sqlite3.prepare_one + db "SELECT child FROM revision_ancestry WHERE parent = ?") in + fun id f init -> + let stmt = Lazy.force stmt in + Sqlite3.reset stmt ; + Sqlite3.bind stmt 1 (`TEXT id) ; + Sqlite3.fold_rows + (fun acc stmt -> f acc (Sqlite3.column_text stmt 0)) + init + stmt let fetch_agraph_with_view db query = let agraph = Viz_types.empty_agraph in @@ -211,10 +211,7 @@ let agraph = if query = ALL then agraph - else - with_fetch_children db - (fun fetch_children -> - Components.reconnect fetch_children agraph) in + else Components.reconnect (fetch_children db) agraph in agraph @@ -390,7 +387,6 @@ v let close_db { db = db ; stmts = stmts } = - Array.iter Sqlite3.finalize_noerr stmts ; Sqlite3.close_db db let with_progress prg f db = ======================================================================== --- mlsqlite/ocaml-sqlite3.c 91b05b4b9f6dc8e1320b24d06f821ea9f080dc43 +++ mlsqlite/ocaml-sqlite3.c 2625b402bdfbf6c64f5fccc95417fb400eff5751 @@ -68,6 +68,7 @@ struct ml_sqlite3_data { sqlite3 *db; value callbacks; + value stmt_store; struct user_function *user_functions; }; @@ -124,6 +125,7 @@ struct user_function *list, *next;; struct ml_sqlite3_data *data = Sqlite3_data_val(v); caml_remove_global_root (&data->callbacks); + caml_remove_global_root (&data->stmt_store); list = data->user_functions; while (list != NULL) { @@ -155,8 +157,10 @@ *store = data; data->db = db; data->callbacks = caml_alloc (NUM_CALLBACKS, 0); + data->stmt_store = Val_unit; data->user_functions = NULL; caml_register_global_root (&data->callbacks); + caml_register_global_root (&data->stmt_store); CAMLreturn(v); } @@ -193,7 +197,27 @@ return Val_unit; } +CAMLprim value +ml_sqlite3_set_stmt_store (value db, value s) +{ + struct ml_sqlite3_data *data = Sqlite3_data_val (db); + if (Is_block (s)) + data->stmt_store = Field (s, 0); + else + data->stmt_store = Val_unit; + return Val_unit; +} +CAMLprim value +ml_sqlite3_get_stmt_store (value db, value s) +{ + struct ml_sqlite3_data *data = Sqlite3_data_val (db); + if (data->stmt_store == Val_unit) + caml_raise_not_found(); + return data->stmt_store; +} + + /* Misc general functions */ @@ -399,18 +423,6 @@ } CAMLprim value -ml_sqlite3_finalize (value v) -{ - int status; - sqlite3 *db; - - status = ml_sqlite3_finalize_stmt (v, &db); - if (status != SQLITE_OK) - ml_sqlite3_raise_exn (status, sqlite3_errmsg (db), TRUE); - return Val_unit; -} - -CAMLprim value ml_sqlite3_finalize_noerr (value v) { ml_sqlite3_finalize_stmt (v, NULL); ======================================================================== --- mlsqlite/sqlite3.ml b33ce0ac0c67b7d64039f2a9322128e8d38d49ee +++ mlsqlite/sqlite3.ml eb012c8336ff254b7d50af97f4aa7cb68559f5be @@ -1,3 +1,39 @@ +module Weak_store = struct + type 'a t = + { mutable w : 'a Weak.t ; mutable free : int } + + let create () = + { w = Weak.create 8 ; free = 0 } + + let register s v = + let len = Weak.length s.w in + assert (len > 0) ; + if s.free < len + then begin + Weak.set s.w s.free (Some v) ; + s.free <- s.free + 1 + end + else begin + let i = ref 0 in + let full = ref true in + while !full && !i < Weak.length s.w do + full := Weak.check s.w !i ; + if !full then incr i + done ; + if !full + then begin + let n_s = Weak.create (2 * len) in + Weak.blit s.w 0 n_s 0 len ; + s.w <- n_s ; + s.free <- len + 1 ; + i := len + end ; + Weak.set s.w !i (Some v) + end +end + + + type db type stmt type argument @@ -45,8 +81,40 @@ external open_db : string -> db = "ml_sqlite3_open" -external close_db : db -> unit = "ml_sqlite3_close" +external _close_db : db -> unit = "ml_sqlite3_close" +external set_stmt_store : db -> stmt Weak_store.t option -> unit = "ml_sqlite3_set_stmt_store" +external get_stmt_store : db -> stmt Weak_store.t = "ml_sqlite3_get_stmt_store" + +external finalize_stmt : stmt -> unit = "ml_sqlite3_finalize_noerr" + +let stmt_store db = + try get_stmt_store db + with Not_found -> + let s = Weak_store.create () in + set_stmt_store db (Some s) ; + s +let register_stmt db stmt = + Gc.finalise finalize_stmt stmt ; + Weak_store.register (stmt_store db) stmt + +let close_db db = + begin + try + let store = (get_stmt_store db).Weak_store.w in + for i = 0 to Weak.length store - 1 do + match Weak.get store i with + | Some stmt -> finalize_stmt stmt + | None -> () + done ; + set_stmt_store db None ; + with Not_found -> () + end ; + _close_db db + + + + external interrupt : db -> unit = "ml_sqlite3_interrupt" external is_complete : string -> bool = "ml_sqlite3_complete" external _version : unit -> string = "ml_sqlite3_version" @@ -77,13 +145,13 @@ (* sql_off : int *) (* } *) -external finalize : stmt -> unit = "ml_sqlite3_finalize" -external finalize_noerr : stmt -> unit = "ml_sqlite3_finalize_noerr" external prepare : db -> string -> int -> stmt option * int = "ml_sqlite3_prepare" let _prepare_one db sql = match prepare db sql 0 with - | Some stmt, _ -> stmt + | Some stmt, _ -> + register_stmt db stmt ; + stmt | None, _ -> failwith "Sqlite3.prepare_one: empty statement" let prepare_one db sql = @@ -92,15 +160,7 @@ let prepare_one_f db fmt = Printf.kprintf (_prepare_one db) fmt -let with_stmt db sql f = - let stmt = prepare_one db sql in - let r = - try f stmt - with exn -> finalize_noerr stmt ; raise exn in - finalize_noerr stmt ; - r - -let prepare_all db sql = +let _prepare_all db sql = let rec proc acc off = if off >= String.length sql then List.rev acc @@ -108,13 +168,18 @@ match try prepare db sql off with exn -> - List.iter finalize_noerr acc ; + List.iter finalize_stmt acc ; raise exn with | Some stmt, nxt -> proc (stmt :: acc) nxt | None, nxt -> proc acc nxt in proc [] 0 +let prepare_all db sql = + let stmts = _prepare_all db (String.copy sql) in + List.iter (register_stmt db) stmts ; + stmts + external reset : stmt -> unit = "ml_sqlite3_reset" external expired : stmt -> bool = "ml_sqlite3_expired" external step : stmt -> [`DONE|`ROW] = "ml_sqlite3_step" @@ -172,9 +237,9 @@ let r = try f acc stmt with exn -> - List.iter finalize_noerr stmts ; + List.iter finalize_stmt stmts ; raise exn in - finalize_noerr stmt ; + finalize_stmt stmt ; fold_stmts f r tl let rec fold_rows f acc stmt = @@ -189,7 +254,7 @@ (fold_rows (fun () _ -> ())) () - (prepare_all db sql) + (_prepare_all db sql) let exec db sql = _exec db (String.copy sql) @@ -219,7 +284,7 @@ fold_stmts (fetch_one ?column_names f) init - (prepare_all db sql) + (_prepare_all db sql) let fetch db sql ?column_names f init = _fetch db (String.copy sql) ?column_names f init ======================================================================== --- mlsqlite/sqlite3.mli 8c9624c03f134ddb2a0c1876f8e6b1c5accefd71 +++ mlsqlite/sqlite3.mli 3cc1e7b6268c2fdf367ecdc0f4e5b6c8b2fe54c8 @@ -44,7 +44,7 @@ val init : unit external open_db : string -> db = "ml_sqlite3_open" -external close_db : db -> unit = "ml_sqlite3_close" +val close_db : db -> unit external interrupt : db -> unit = "ml_sqlite3_interrupt" external is_complete : string -> bool = "ml_sqlite3_complete" @@ -69,15 +69,10 @@ = "ml_sqlite3_progress_handler_unset" -external finalize : stmt -> unit = "ml_sqlite3_finalize" -external finalize_noerr : stmt -> unit = "ml_sqlite3_finalize_noerr" -external prepare : db -> string -> int -> stmt option * int - = "ml_sqlite3_prepare" +external finalize_stmt : stmt -> unit = "ml_sqlite3_finalize_noerr" val prepare_one : db -> string -> stmt val prepare_all : db -> string -> stmt list -val with_stmt : db -> string -> (stmt -> 'a) -> 'a - external reset : stmt -> unit = "ml_sqlite3_reset" external expired : stmt -> bool = "ml_sqlite3_expired" external step : stmt -> [ `DONE | `ROW ] = "ml_sqlite3_step"