Mercurial > urweb
comparison src/sqlcache.sml @ 2218:f7113855f3b7
More invalidation progress.
author | Ziv Scully <ziv@mit.edu> |
---|---|
date | Tue, 11 Nov 2014 04:25:20 -0500 |
parents | 70ec9bb337be |
children | ff38b3e0cdfd |
comparison
equal
deleted
inserted
replaced
2217:98b87d905601 | 2218:f7113855f3b7 |
---|---|
146 val rec cartesianProduct : 'a list list -> 'a list list = | 146 val rec cartesianProduct : 'a list list -> 'a list list = |
147 fn [] => [[]] | 147 fn [] => [[]] |
148 | (xs :: xss) => bind (cartesianProduct xss) | 148 | (xs :: xss) => bind (cartesianProduct xss) |
149 (fn ys => bind xs (fn x => [x :: ys])) | 149 (fn ys => bind xs (fn x => [x :: ys])) |
150 | 150 |
151 fun normalize (negate : 'atom -> 'atom) (norm : normalForm) = | 151 (* Pushes all negation to the atoms.*) |
152 fun pushNegate (negate : 'atom -> 'atom) (negating : bool) = | |
153 fn Atom x => Atom (if negating then negate x else x) | |
154 | Negate f => pushNegate negate (not negating) f | |
155 | Combo (n, fs) => Combo (if negating then flipNf n else n, map (pushNegate negate negating) fs) | |
156 | |
157 val rec flatten = | |
158 fn Combo (n, fs) => | |
159 Combo (n, List.foldr (fn (f, acc) => | |
160 case f of | |
161 Combo (n', fs') => if n = n' then fs' @ acc else f :: acc | |
162 | _ => f :: acc) | |
163 [] | |
164 (map flatten fs)) | |
165 | f => f | |
166 | |
167 fun normalize' (negate : 'atom -> 'atom) (norm : normalForm) = | |
152 fn Atom x => [[x]] | 168 fn Atom x => [[x]] |
153 | Negate f => map (map negate) (normalize negate (flipNf norm) f) | 169 | Negate f => map (map negate) (normalize' negate (flipNf norm) f) |
154 | Combo (n, fs) => | 170 | Combo (n, fs) => |
155 let | 171 let |
156 val fss = bind fs (normalize negate n) | 172 val fss = bind fs (normalize' negate n) |
157 in | 173 in |
158 if n = norm then fss else cartesianProduct fss | 174 if n = norm then fss else cartesianProduct fss |
159 end | 175 end |
160 | 176 |
161 fun mapFormula mf = | 177 fun normalize negate norm = normalize' negate norm o flatten o pushNegate negate false |
162 fn Atom x => Atom (mf x) | 178 |
163 | Negate f => Negate (mapFormula mf f) | 179 fun mapFormulaSigned positive mf = |
164 | Combo (n, fs) => Combo (n, map (mapFormula mf) fs) | 180 fn Atom x => Atom (mf (positive, x)) |
165 | 181 | Negate f => Negate (mapFormulaSigned (not positive) mf f) |
182 | Combo (n, fs) => Combo (n, map (mapFormulaSigned positive mf) fs) | |
183 | |
184 fun mapFormula mf = mapFormulaSigned true (fn (_, x) => mf x) | |
166 | 185 |
167 (* SQL analysis. *) | 186 (* SQL analysis. *) |
168 | 187 |
169 val rec chooseTwos : 'a list -> ('a * 'a) list = | 188 val rec chooseTwos : 'a list -> ('a * 'a) list = |
170 fn [] => [] | 189 fn [] => [] |
173 datatype atomExp = | 192 datatype atomExp = |
174 QueryArg of int | 193 QueryArg of int |
175 | DmlRel of int | 194 | DmlRel of int |
176 | Prim of Prim.t | 195 | Prim of Prim.t |
177 | Field of string * string | 196 | Field of string * string |
197 | |
198 val equalAtomExp = | |
199 let | |
200 val isEqual = fn EQUAL => true | _ => false | |
201 in | |
202 fn (QueryArg n1, QueryArg n2) => n1 = n2 | |
203 | (DmlRel n1, DmlRel n2) => n1 = n2 | |
204 | (Prim p1, Prim p2) => isEqual (Prim.compare (p1, p2)) | |
205 | (Field (t1, f1), Field (t2, f2)) => isEqual (String.compare (t1 ^ "." ^ f1, t2 ^ "." ^ f2)) | |
206 | _ => false | |
207 end | |
178 | 208 |
179 structure AtomExpKey : ORD_KEY = struct | 209 structure AtomExpKey : ORD_KEY = struct |
180 | 210 |
181 type ord_key = atomExp | 211 type ord_key = atomExp |
182 | 212 |
194 | 224 |
195 end | 225 end |
196 | 226 |
197 structure UF = UnionFindFn(AtomExpKey) | 227 structure UF = UnionFindFn(AtomExpKey) |
198 | 228 |
199 fun conflictMaps (fQuery : (Sql.cmp * Sql.sqexp * Sql.sqexp) formula, | 229 (* val conflictMaps : (Sql.cmp * Sql.sqexp * Sql.sqexp) formula *) |
200 fDml : (Sql.cmp * Sql.sqexp * Sql.sqexp) formula) = | 230 (* * (Sql.cmp * Sql.sqexp * Sql.sqexp) formula *) |
201 let | 231 (* -> Mono.exp' IM.map list = *) |
232 (* let *) | |
202 val toKnownEquality = | 233 val toKnownEquality = |
203 (* [NONE] here means unkown. Anything that isn't a comparison between | 234 (* [NONE] here means unkown. Anything that isn't a comparison between |
204 two knowns shouldn't be used, and simply dropping unused terms is | 235 two knowns shouldn't be used, and simply dropping unused terms is |
205 okay in disjunctive normal form. *) | 236 okay in disjunctive normal form. *) |
206 fn (Sql.Eq, SOME e1, SOME e2) => SOME (e1, e2) | 237 fn (Sql.Eq, SOME e1, SOME e2) => SOME (e1, e2) |
210 o List.foldl UF.union' UF.empty | 241 o List.foldl UF.union' UF.empty |
211 o List.mapPartial toKnownEquality | 242 o List.mapPartial toKnownEquality |
212 fun addToEqs (eqs, n, e) = | 243 fun addToEqs (eqs, n, e) = |
213 case IM.find (eqs, n) of | 244 case IM.find (eqs, n) of |
214 (* Comparing to a constant seems better? *) | 245 (* Comparing to a constant seems better? *) |
215 SOME (EPrim _) => eqs | 246 SOME (Prim _) => eqs |
216 | _ => IM.insert (eqs, n, e) | 247 | _ => IM.insert (eqs, n, e) |
217 val accumulateEqs = | 248 val accumulateEqs = |
218 (* [NONE] means we have a contradiction. *) | 249 (* [NONE] means we have a contradiction. *) |
219 fn (_, NONE) => NONE | 250 fn (_, NONE) => NONE |
220 | ((Prim p1, Prim p2), eqso) => | 251 | ((Prim p1, Prim p2), eqso) => |
221 (case Prim.compare (p1, p2) of | 252 (case Prim.compare (p1, p2) of |
222 EQUAL => eqso | 253 EQUAL => eqso |
223 | _ => NONE) | 254 | _ => NONE) |
224 | ((QueryArg n, Prim p), SOME eqs) => SOME (addToEqs (eqs, n, EPrim p)) | 255 | ((QueryArg n, Prim p), SOME eqs) => SOME (addToEqs (eqs, n, Prim p)) |
225 | ((QueryArg n, DmlRel r), SOME eqs) => SOME (addToEqs (eqs, n, ERel r)) | 256 | ((QueryArg n, DmlRel r), SOME eqs) => SOME (addToEqs (eqs, n, DmlRel r)) |
226 | ((Prim p, QueryArg n), SOME eqs) => SOME (addToEqs (eqs, n, EPrim p)) | 257 | ((Prim p, QueryArg n), SOME eqs) => SOME (addToEqs (eqs, n, Prim p)) |
227 | ((DmlRel r, QueryArg n), SOME eqs) => SOME (addToEqs (eqs, n, ERel r)) | 258 | ((DmlRel r, QueryArg n), SOME eqs) => SOME (addToEqs (eqs, n, DmlRel r)) |
228 (* TODO: deal with equalities involving just [DmlRel]s and [Prim]s. *) | 259 (* TODO: deal with equalities involving just [DmlRel]s and [Prim]s. *) |
229 | (_, eqso) => eqso | 260 | (_, eqso) => eqso |
230 val eqsOfClass : atomExp list -> Mono.exp' IM.map option = | 261 val eqsOfClass : atomExp list -> atomExp IM.map option = |
231 List.foldl accumulateEqs (SOME IM.empty) | 262 List.foldl accumulateEqs (SOME IM.empty) |
232 o chooseTwos | 263 o chooseTwos |
233 fun toAtomExps rel (cmp, e1, e2) = | 264 fun toAtomExps rel (cmp, e1, e2) = |
234 let | 265 let |
235 val qa = | 266 val qa = |
250 | Sql.Lt => Sql.Ge | 281 | Sql.Lt => Sql.Ge |
251 | Sql.Le => Sql.Gt | 282 | Sql.Le => Sql.Gt |
252 | Sql.Gt => Sql.Le | 283 | Sql.Gt => Sql.Le |
253 | Sql.Ge => Sql.Lt, | 284 | Sql.Ge => Sql.Lt, |
254 e1, e2) | 285 e1, e2) |
255 val markQuery = mapFormula (toAtomExps QueryArg) | 286 val markQuery : (Sql.cmp * Sql.sqexp * Sql.sqexp) formula -> |
256 val markDml = mapFormula (toAtomExps DmlRel) | 287 (Sql.cmp * atomExp option * atomExp option) formula = |
257 val dnf = normalize negateCmp Dnf (Combo (Cnf, [markQuery fQuery, markDml fDml])) | 288 mapFormula (toAtomExps QueryArg) |
258 (* If one of the terms in a conjunction leads to a contradiction, which | 289 val markDml : (Sql.cmp * Sql.sqexp * Sql.sqexp) formula -> |
259 is represented by [NONE], drop the entire conjunction. *) | 290 (Sql.cmp * atomExp option * atomExp option) formula = |
260 val sequenceOption = List.foldr (fn (SOME x, SOME xs) => SOME (x :: xs) | _ => NONE) | 291 mapFormula (toAtomExps DmlRel) |
261 (SOME []) | 292 (* No eqs should have key conflicts because no variable is in two |
262 in | 293 equivalence classes, so the [#1] can be anything. *) |
263 List.mapPartial (sequenceOption o map eqsOfClass o equivClasses) dnf | 294 val mergeEqs : (atomExp IntBinaryMap.map option list |
264 end | 295 -> atomExp IntBinaryMap.map option) = |
296 List.foldr (fn (SOME eqs, SOME acc) => SOME (IM.unionWith #1 (eqs, acc)) | _ => NONE) | |
297 (SOME IM.empty) | |
298 fun dnf (fQuery, fDml) = | |
299 normalize negateCmp Dnf (Combo (Cnf, [markQuery fQuery, markDml fDml])) | |
300 (* in *) | |
301 val conflictMaps : (Sql.cmp * Sql.sqexp * Sql.sqexp) formula | |
302 * (Sql.cmp * Sql.sqexp * Sql.sqexp) formula | |
303 -> atomExp IM.map list = | |
304 List.mapPartial (mergeEqs o map eqsOfClass o equivClasses) o dnf | |
305 (* end *) | |
265 | 306 |
266 val rec sqexpToFormula = | 307 val rec sqexpToFormula = |
267 fn Sql.SqTrue => Combo (Cnf, []) | 308 fn Sql.SqTrue => Combo (Cnf, []) |
268 | Sql.SqFalse => Combo (Dnf, []) | 309 | Sql.SqFalse => Combo (Dnf, []) |
269 | Sql.SqNot e => Negate (sqexpToFormula e) | 310 | Sql.SqNot e => Negate (sqexpToFormula e) |
271 | Sql.Binop (Sql.RLop l, p1, p2) => Combo (case l of Sql.And => Cnf | Sql.Or => Dnf, | 312 | Sql.Binop (Sql.RLop l, p1, p2) => Combo (case l of Sql.And => Cnf | Sql.Or => Dnf, |
272 [sqexpToFormula p1, sqexpToFormula p2]) | 313 [sqexpToFormula p1, sqexpToFormula p2]) |
273 (* ASK: any other sqexps that can be props? *) | 314 (* ASK: any other sqexps that can be props? *) |
274 | _ => raise Match | 315 | _ => raise Match |
275 | 316 |
276 val rec queryToFormula = | 317 fun renameTables tablePairs = |
277 fn Sql.Query1 {From = tablePairs, Where = NONE, ...} => Combo (Cnf, []) | |
278 | Sql.Query1 {From = tablePairs, Where = SOME e, ...} => | |
279 let | 318 let |
280 fun renameString table = | 319 fun renameString table = |
281 case List.find (fn (_, t) => table = t) tablePairs of | 320 case List.find (fn (_, t) => table = t) tablePairs of |
282 NONE => table | 321 NONE => table |
283 | SOME (realTable, _) => realTable | 322 | SOME (realTable, _) => realTable |
284 val renameSqexp = | 323 val renameSqexp = |
285 fn Sql.Field (table, field) => Sql.Field (renameString table, field) | 324 fn Sql.Field (table, field) => Sql.Field (renameString table, field) |
286 | e => e | 325 | e => e |
287 fun renameAtom (cmp, e1, e2) = (cmp, renameSqexp e1, renameSqexp e2) | 326 fun renameAtom (cmp, e1, e2) = (cmp, renameSqexp e1, renameSqexp e2) |
288 in | 327 in |
289 mapFormula renameAtom (sqexpToFormula e) | 328 mapFormula renameAtom |
290 end | 329 end |
330 | |
331 val rec queryToFormula = | |
332 fn Sql.Query1 {Where = NONE, ...} => Combo (Cnf, []) | |
333 | Sql.Query1 {From = tablePairs, Where = SOME e, ...} => | |
334 renameTables tablePairs (sqexpToFormula e) | |
291 | Sql.Union (q1, q2) => Combo (Dnf, [queryToFormula q1, queryToFormula q2]) | 335 | Sql.Union (q1, q2) => Combo (Dnf, [queryToFormula q1, queryToFormula q2]) |
292 | 336 |
337 fun valsToFormula (table, vals) = | |
338 Combo (Cnf, map (fn (field, v) => Atom (Sql.Eq, Sql.Field (table, field), v)) vals) | |
339 | |
293 val rec dmlToFormula = | 340 val rec dmlToFormula = |
294 fn Sql.Insert (table, vals) => | 341 fn Sql.Insert tableVals => valsToFormula tableVals |
295 Combo (Cnf, map (fn (field, v) => Atom (Sql.Eq, Sql.Field (table, field), v)) vals) | 342 | Sql.Delete (table, wher) => renameTables [(table, "T")] (sqexpToFormula wher) |
296 | Sql.Delete (_, wher) => sqexpToFormula wher | |
297 (* TODO: refine formula for the vals part, which could take into account the wher part. *) | 343 (* TODO: refine formula for the vals part, which could take into account the wher part. *) |
298 | Sql.Update (table, vals, wher) => Combo (Dnf, [dmlToFormula (Sql.Insert (table, vals)), | 344 | Sql.Update (table, vals, wher) => |
299 dmlToFormula (Sql.Delete (table, wher))]) | 345 let |
346 val f = sqexpToFormula wher | |
347 fun update (positive, a) = | |
348 let | |
349 fun updateIfNecessary field = | |
350 case List.find (fn (f, _) => field = f) vals of | |
351 SOME (_, v) => (if positive then Sql.Eq else Sql.Ne, | |
352 Sql.Field (table, field), | |
353 v) | |
354 | NONE => a | |
355 in | |
356 case a of | |
357 (_, Sql.Field (_, field), _) => updateIfNecessary field | |
358 | (_, _, Sql.Field (_, field)) => updateIfNecessary field | |
359 | _ => a | |
360 end | |
361 in | |
362 renameTables [(table, "T")] | |
363 (Combo (Dnf, [f, | |
364 Combo (Cnf, [valsToFormula (table, vals), | |
365 mapFormulaSigned true update f])])) | |
366 end | |
300 | 367 |
301 val rec tablesQuery = | 368 val rec tablesQuery = |
302 fn Sql.Query1 {From = tablePairs, ...} => SS.fromList (map #1 tablePairs) | 369 fn Sql.Query1 {From = tablePairs, ...} => SS.fromList (map #1 tablePairs) |
303 | Sql.Union (q1, q2) => SS.union (tablesQuery q1, tablesQuery q2) | 370 | Sql.Union (q1, q2) => SS.union (tablesQuery q1, tablesQuery q2) |
304 | 371 |
414 | 481 |
415 fun fileMap doExp file = #1 (fileMapfold (fn x => fn _ => (doExp x, ())) file ()) | 482 fun fileMap doExp file = #1 (fileMapfold (fn x => fn _ => (doExp x, ())) file ()) |
416 | 483 |
417 fun addChecking file = | 484 fun addChecking file = |
418 let | 485 let |
419 fun doExp queryInfo = | 486 fun doExp (queryInfo as (tableToIndices, indexToQuery)) = |
420 fn e' as ELet (v, t, | 487 fn e' as ELet (v, t, |
421 queryExp' as (EQuery {query = origQueryText, | 488 queryExp' as (EQuery {query = origQueryText, |
422 initial, body, state, tables, exps}, queryLoc), | 489 initial, body, state, tables, exps}, queryLoc), |
423 letBody) => | 490 letBody) => |
424 let | 491 let |
458 state = state, | 525 state = state, |
459 tables = tables, | 526 tables = tables, |
460 exps = exps}, | 527 exps = exps}, |
461 queryLoc) | 528 queryLoc) |
462 val (EQuery {query = queryText, ...}, _) = queryExp | 529 val (EQuery {query = queryText, ...}, _) = queryExp |
463 (* val () = Print.preface ("sqlcache> ", (MonoPrint.p_exp MonoEnv.empty queryText)); *) | 530 val () = Print.preface ("sqlcache> ", (MonoPrint.p_exp MonoEnv.empty queryText)); |
464 val args = List.tabulate (numArgs, fn n => (ERel n, loc)) | 531 val args = List.tabulate (numArgs, fn n => (ERel n, loc)) |
465 fun bind x f = Option.mapPartial f x | 532 fun bind x f = Option.mapPartial f x |
466 fun guard b x = if b then x else NONE | 533 fun guard b x = if b then x else NONE |
467 (* DEBUG: set first boolean argument to true to turn on printing. *) | 534 (* DEBUG: set first boolean argument to true to turn on printing. *) |
468 fun safe bound = not o effectful true (effectfulMap file) false bound | 535 fun safe bound = not o effectful true (effectfulMap file) false bound |
469 val attempt = | 536 val attempt = |
470 (* Ziv misses Haskell's do notation.... *) | 537 (* Ziv misses Haskell's do notation.... *) |
471 guard (safe 0 queryText andalso safe 0 initial andalso safe 2 body) ( | 538 guard (safe 0 queryText andalso safe 0 initial andalso safe 2 body) ( |
472 bind (Sql.parse Sql.query queryText) (fn queryParsed => | 539 bind (Sql.parse Sql.query queryText) (fn queryParsed => |
473 bind (indexOfName v) (fn i => | 540 bind (indexOfName v) (fn index => |
474 bind (IM.find (!urlifiedRel0s, i)) (fn urlifiedRel0 => | 541 bind (IM.find (!urlifiedRel0s, index)) (fn urlifiedRel0 => |
475 SOME (wrapLets (ELet (v, t, | 542 SOME (wrapLets (ELet (v, t, |
476 cacheWrap (queryExp, i, urlifiedRel0, args), | 543 cacheWrap (queryExp, index, urlifiedRel0, args), |
477 incRelsBound 1 (length newVariables) letBody)), | 544 incRelsBound 1 (length newVariables) letBody)), |
478 SS.foldr (fn (tab, qi) => SIMM.insert (qi, tab, i)) | 545 (SS.foldr (fn (tab, qi) => SIMM.insert (qi, tab, index)) |
479 queryInfo | 546 tableToIndices |
480 (tablesQuery queryParsed)))))) | 547 (tablesQuery queryParsed), |
548 IM.insert (indexToQuery, index, (queryParsed, numArgs)))))))) | |
481 in | 549 in |
482 case attempt of | 550 case attempt of |
483 SOME pair => pair | 551 SOME pair => pair |
484 | NONE => (e', queryInfo) | 552 | NONE => (e', queryInfo) |
485 end | 553 end |
486 | ESeq ((EFfiApp ("Sqlcache", "dummy", _), _), (e', _)) => (e', queryInfo) | 554 | ESeq ((EFfiApp ("Sqlcache", "dummy", _), _), (e', _)) => (e', queryInfo) |
487 | e' => (e', queryInfo) | 555 | e' => (e', queryInfo) |
488 in | 556 in |
489 fileMapfold (fn exp => fn state => doExp state exp) file SIMM.empty | 557 fileMapfold (fn exp => fn state => doExp state exp) file (SIMM.empty, IM.empty) |
490 end | 558 end |
559 | |
560 val gunk' : (((Sql.cmp * Sql.sqexp * Sql.sqexp) formula) | |
561 * ((Sql.cmp * Sql.sqexp * Sql.sqexp) formula)) list ref = ref [] | |
491 | 562 |
492 fun invalidations (nQueryArgs, query, dml) = | 563 fun invalidations (nQueryArgs, query, dml) = |
493 let | 564 let |
494 val loc = ErrorMsg.dummySpan | 565 val loc = ErrorMsg.dummySpan |
495 val optionToExp = | 566 val optionAtomExpToExp = |
496 fn NONE => (ENone stringTyp, loc) | 567 fn NONE => (ENone stringTyp, loc) |
497 | SOME e => (ESome (stringTyp, (e, loc)), loc) | 568 | SOME e => (ESome (stringTyp, |
569 (case e of | |
570 DmlRel n => ERel n | |
571 | Prim p => EPrim p | |
572 (* TODO: make new type containing only these two. *) | |
573 | _ => raise Match, | |
574 loc)), | |
575 loc) | |
498 fun eqsToInvalidation eqs = | 576 fun eqsToInvalidation eqs = |
499 let | 577 let |
500 fun inv n = if n < 0 then [] else optionToExp (IM.find (eqs, n)) :: inv (n - 1) | 578 fun inv n = if n < 0 then [] else IM.find (eqs, n) :: inv (n - 1) |
501 in | 579 in |
502 inv (nQueryArgs - 1) | 580 inv (nQueryArgs - 1) |
503 end | 581 end |
504 in | 582 (* *) |
505 map (map eqsToInvalidation) (conflictMaps (queryToFormula query, dmlToFormula dml)) | 583 val rec madeRedundantBy : atomExp option list * atomExp option list -> bool = |
506 end | 584 fn ([], []) => true |
507 | 585 | (NONE :: xs, _ :: ys) => madeRedundantBy (xs, ys) |
508 fun addFlushing (file, queryInfo) = | 586 | (SOME x :: xs, SOME y :: ys) => equalAtomExp (x, y) andalso madeRedundantBy (xs, ys) |
509 let | 587 | _ => false |
510 val allIndices : int list = SM.foldr (fn (x, acc) => IS.listItems x @ acc) [] queryInfo | 588 fun removeRedundant' (xss, yss) = |
511 fun flushes indices = map (fn i => ffiAppCache' ("flush", i, [])) indices | 589 case xss of |
590 [] => yss | |
591 | xs :: xss' => | |
592 removeRedundant' (xss', | |
593 if List.exists (fn ys => madeRedundantBy (xs, ys)) (xss' @ yss) | |
594 then yss | |
595 else xs :: yss) | |
596 fun removeRedundant xss = removeRedundant' (xss, []) | |
597 val eqss = conflictMaps (queryToFormula query, dmlToFormula dml) | |
598 in | |
599 gunk' := (queryToFormula query, dmlToFormula dml) :: !gunk'; | |
600 (map (map optionAtomExpToExp) o removeRedundant o map eqsToInvalidation) eqss | |
601 end | |
602 | |
603 val gunk : Mono.exp list list list ref = ref [] | |
604 | |
605 fun addFlushing (file, queryInfo as (tableToIndices, indexToQuery)) = | |
606 let | |
607 val allIndices = SM.foldr (fn (x, acc) => IS.listItems x @ acc) [] tableToIndices | |
608 val flushes = map (fn i => ffiAppCache' ("flush", i, [])) | |
512 val doExp = | 609 val doExp = |
513 fn dmlExp as EDml (dmlText, _) => | 610 fn dmlExp as EDml (dmlText, _) => |
514 let | 611 let |
515 val indices = | 612 val indices = |
516 case Sql.parse Sql.dml dmlText of | 613 case Sql.parse Sql.dml dmlText of |
517 SOME dmlParsed => SIMM.findList (queryInfo, tableDml dmlParsed) | 614 SOME dmlParsed => |
615 map (fn i => ((case IM.find (indexToQuery, i) of | |
616 NONE => () | |
617 | SOME (queryParsed, numArgs) => | |
618 gunk := invalidations (numArgs, queryParsed, dmlParsed) :: !gunk); | |
619 i)) (SIMM.findList (tableToIndices, tableDml dmlParsed)) | |
518 | NONE => allIndices | 620 | NONE => allIndices |
519 in | 621 in |
520 sequence (flushes indices @ [dmlExp]) | 622 sequence (flushes indices @ [dmlExp]) |
521 end | 623 end |
522 | e' => e' | 624 | e' => e' |