[MLton-commit] r5192
Wesley Terpstra
wesley at mlton.org
Wed Feb 14 08:20:21 PST 2007
use pool allocation for prepared statements
----------------------------------------------------------------------
U mltonlib/trunk/ca/terpstra/sqlite3/query.sml
U mltonlib/trunk/ca/terpstra/sqlite3/sql.sml
----------------------------------------------------------------------
Modified: mltonlib/trunk/ca/terpstra/sqlite3/query.sml
===================================================================
--- mltonlib/trunk/ca/terpstra/sqlite3/query.sml 2007-02-14 15:33:12 UTC (rev 5191)
+++ mltonlib/trunk/ca/terpstra/sqlite3/query.sml 2007-02-14 16:20:20 UTC (rev 5192)
@@ -15,15 +15,49 @@
('j, 'o, 'a, 'b, ('j, 'k) pair, 'k) acc,
'x, 'y, 'z) Fold.step1
-(*
- type ('i, 'o) t = { Word8Vector.vector,
- pool: Prim.query list ref,
- used: int ref,
- iF: Prim.query * 'i -> unit,
- oF: Prim.query -> 'o }
-*)
- type ('i, 'o) t = Prim.query * (Prim.query * 'i -> unit) * (Prim.query -> 'o)
+ (* We need to be able to create new queries for recursive usage.
+ * Each prepared statement has only a single VM, so we need a factory
+ * to support reentrant processing. The used counter records how many
+ * outstanding queries there are (-1 means closed). The pool saves
+ * previously allocated prepared statements for quick re-use.
+ *)
+ type ('i, 'o) t = { db: Prim.db,
+ query: string,
+ pool: Prim.query list ref,
+ used: int ref,
+ iF: Prim.query * 'i -> unit,
+ oF: Prim.query -> 'o }
+ fun peek { db, query, pool, used, iF, oF } =
+ case !pool of
+ x :: r => x
+ | [] =>
+ let
+ val pq = Prim.prepare (db, query)
+ val () = pool := pq :: !pool
+ in
+ pq
+ end
+
+ fun alloc ({ db, query, pool, used, iF, oF }, i) =
+ let
+ val () = if !used = ~1 then raise Prim.Error "Query.t is closed" else ()
+ val pq = case !pool of
+ [] => Prim.prepare (db, query)
+ | x :: r => (pool := r; x)
+ val () = used := !used + 1
+ val () = iF (pq, i)
+ in
+ (pq, oF)
+ end
+
+ fun release ({ db, query, pool, used, iF, oF }, pq) = (
+ if !used = 0 then raise Prim.Error "wrapper bug: too many released statements" else
+ Prim.reset pq;
+ Prim.clearbindings pq;
+ used := !used - 1;
+ pool := pq :: !pool)
+
fun oF0 _ = ()
fun oN0 (q, n) = n ()
val oI0 = 0
@@ -36,13 +70,20 @@
val q = Prim.prepare (db, qs)
in if Prim.cols q < oI
then (Prim.finalize q;
- raise Fail "insufficient output columns")
- else (q, iF, oF)
+ raise Prim.Error "insufficient output columns")
+ else { db = db,
+ query = qs,
+ pool = ref [q],
+ used = ref 0,
+ iF = iF,
+ oF = oF }
end)
(* terminate an expression with this: *)
val $ = $
- fun close (q, _, _) = Prim.finalize q
+ fun close { db, query, pool, used, iF, oF } =
+ if !used = 0 then raise Prim.Error "Query is being processed; cannot close" else
+ (List.app Prim.finalize (!pool); pool := [] ; used := ~1)
fun iFx f iN (q, a) = case iN (q, a) of (i, x) => f (q, i, x)
fun iNx f iN (q, a & y) = case iN (q, a) of (i, x) => (f (q, i, x); (i+1, y))
Modified: mltonlib/trunk/ca/terpstra/sqlite3/sql.sml
===================================================================
--- mltonlib/trunk/ca/terpstra/sqlite3/sql.sml 2007-02-14 15:33:12 UTC (rev 5191)
+++ mltonlib/trunk/ca/terpstra/sqlite3/sql.sml 2007-02-14 16:20:20 UTC (rev 5192)
@@ -12,41 +12,37 @@
val version = Prim.version
- fun columns (q, _, _) = Prim.meta q
+ fun columns q = Prim.meta (Query.peek q)
val openDB = Prim.openDB
val closeDB = Prim.closeDB
datatype 'v stop = STOP | CONTINUE of 'v
- fun iterStop (q, iF, oF) i =
+ fun iterStop q i =
let
- val () = iF (q, i)
val ok = ref true
-
+ val (pq, oF) = Query.alloc (q, i)
fun stop () = (
- Prim.reset q;
- Prim.clearbindings q;
+ Query.release (q, pq);
ok := false)
in
fn STOP => (stop (); NONE)
| (CONTINUE ()) =>
if not (!ok) then NONE else
- if Prim.step q then SOME (oF q) else (stop (); NONE)
+ if Prim.step pq then SOME (oF pq) else (stop (); NONE)
end
- fun mapStop f (q, iF, oF) i =
+ fun mapStop f q i =
let
- val () = iF (q, i)
-
+ val (pq, oF) = Query.alloc (q, i)
fun stop l = (
- Prim.reset q;
- Prim.clearbindings q;
+ Query.release (q, pq);
Vector.fromList (List.rev l))
fun helper l =
- if Prim.step q
- then case f (oF q) of
+ if Prim.step pq
+ then case f (oF pq) of
STOP => stop l
| CONTINUE r => helper (r :: l)
else stop l
@@ -54,17 +50,14 @@
helper []
end
- fun appStop f (q, iF, oF) i =
+ fun appStop f q i =
let
- val () = iF (q, i)
+ val (pq, oF) = Query.alloc (q, i)
+ fun stop () = Query.release (q, pq)
- fun stop () = (
- Prim.reset q;
- Prim.clearbindings q)
-
fun helper () =
- if Prim.step q
- then case f (oF q) of
+ if Prim.step pq
+ then case f (oF pq) of
STOP => stop ()
| CONTINUE () => helper ()
else stop ()
More information about the MLton-commit
mailing list