Mercurial > urweb
comparison src/sqlcache.sml @ 2274:0730e217fc9c
First draft of more specific formulas for queries.
author | Ziv Scully <ziv@mit.edu> |
---|---|
date | Thu, 05 Nov 2015 01:48:42 -0500 |
parents | a3cac6cea625 |
children | ce96e166d938 |
comparison
equal
deleted
inserted
replaced
2273:a3cac6cea625 | 2274:0730e217fc9c |
---|---|
6 structure IM = IntBinaryMap | 6 structure IM = IntBinaryMap |
7 structure SK = struct type ord_key = string val compare = String.compare end | 7 structure SK = struct type ord_key = string val compare = String.compare end |
8 structure SS = BinarySetFn(SK) | 8 structure SS = BinarySetFn(SK) |
9 structure SM = BinaryMapFn(SK) | 9 structure SM = BinaryMapFn(SK) |
10 structure SIMM = MultimapFn(structure KeyMap = SM structure ValSet = IS) | 10 structure SIMM = MultimapFn(structure KeyMap = SM structure ValSet = IS) |
11 | |
12 (* ASK: how do we deal with heap reallocation? *) | |
13 | |
14 fun id x = x | |
11 | 15 |
12 fun iterate f n x = if n < 0 | 16 fun iterate f n x = if n < 0 |
13 then raise Fail "Can't iterate function negative number of times." | 17 then raise Fail "Can't iterate function negative number of times." |
14 else if n = 0 | 18 else if n = 0 |
15 then x | 19 then x |
225 fun mapFormula mf = | 229 fun mapFormula mf = |
226 fn Atom x => Atom (mf x) | 230 fn Atom x => Atom (mf x) |
227 | Negate f => Negate (mapFormula mf f) | 231 | Negate f => Negate (mapFormula mf f) |
228 | Combo (j, fs) => Combo (j, map (mapFormula mf) fs) | 232 | Combo (j, fs) => Combo (j, map (mapFormula mf) fs) |
229 | 233 |
234 fun mapFormulaExps mf = mapFormula (fn (cmp, e1, e2) => (cmp, mf e1, mf e2)) | |
235 | |
230 | 236 |
231 (****************) | 237 (****************) |
232 (* SQL Analysis *) | 238 (* SQL Analysis *) |
233 (****************) | 239 (****************) |
234 | 240 |
580 NONE => table | 586 NONE => table |
581 | SOME (realTable, _) => realTable | 587 | SOME (realTable, _) => realTable |
582 val renameSqexp = | 588 val renameSqexp = |
583 fn Sql.Field (table, field) => Sql.Field (renameString table, field) | 589 fn Sql.Field (table, field) => Sql.Field (renameString table, field) |
584 | e => e | 590 | e => e |
585 fun renameAtom (cmp, e1, e2) = (cmp, renameSqexp e1, renameSqexp e2) | 591 (* fun renameAtom (cmp, e1, e2) = (cmp, renameSqexp e1, renameSqexp e2) *) |
586 in | 592 in |
587 mapFormula renameAtom | 593 mapFormulaExps renameSqexp |
588 end | 594 end |
589 | 595 |
590 val rec queryToFormula = | 596 fun queryToFormula marker = |
591 fn Sql.Query1 {Where = NONE, ...} => Combo (Conj, []) | 597 fn Sql.Query1 {Select = sitems, From = tablePairs, Where = wher} => |
592 | Sql.Query1 {From = tablePairs, Where = SOME e, ...} => | 598 let |
593 renameTables tablePairs (sqexpToFormula e) | 599 val fWhere = case wher of |
594 | Sql.Union (q1, q2) => Combo (Disj, [queryToFormula q1, queryToFormula q2]) | 600 NONE => Combo (Conj, []) |
595 | 601 | SOME e => sqexpToFormula e |
596 fun valsToFormula (table, vals) = | 602 in |
597 Combo (Conj, map (fn (field, v) => Atom (Sql.Eq, Sql.Field (table, field), v)) vals) | 603 renameTables tablePairs |
598 | 604 (case marker of |
599 val rec dmlToFormula = | 605 NONE => fWhere |
600 fn Sql.Insert (table, vals) => valsToFormula (table, vals) | 606 | SOME markFields => |
601 | Sql.Delete (table, wher) => renameTables [(table, "T")] (sqexpToFormula wher) | 607 let |
608 val fWhereMarked = mapFormulaExps markFields fWhere | |
609 val toSqexp = | |
610 fn Sql.SqField tf => Sql.Field tf | |
611 | Sql.SqExp (se, _) => se | |
612 fun ineq se = Atom (Sql.Ne, se, markFields se) | |
613 val fIneqs = Combo (Disj, map (ineq o toSqexp) sitems) | |
614 in | |
615 (Combo (Conj, | |
616 [fWhere, | |
617 Combo (Disj, | |
618 [Negate fWhereMarked, | |
619 Combo (Conj, [fWhereMarked, fIneqs])])])) | |
620 end) | |
621 end | |
622 | Sql.Union (q1, q2) => Combo (Disj, [queryToFormula marker q1, queryToFormula marker q2]) | |
623 | |
624 fun valsToFormula (markLeft, markRight) (table, vals) = | |
625 Combo (Conj, | |
626 map (fn (field, v) => Atom (Sql.Eq, markLeft (Sql.Field (table, field)), markRight v)) | |
627 vals) | |
628 | |
629 (* TODO: verify logic for insertion and deletion. *) | |
630 val rec dmlToFormulaMarker = | |
631 fn Sql.Insert (table, vals) => (valsToFormula (id, id) (table, vals), NONE) | |
632 | Sql.Delete (table, wher) => (renameTables [(table, "T")] (sqexpToFormula wher), NONE) | |
602 | Sql.Update (table, vals, wher) => | 633 | Sql.Update (table, vals, wher) => |
603 let | 634 let |
604 val fWhere = sqexpToFormula wher | 635 val fWhere = sqexpToFormula wher |
605 val fVals = valsToFormula (table, vals) | 636 fun fVals marks = valsToFormula marks (table, vals) |
606 val modifiedFields = SS.addList (SS.empty, map #1 vals) | 637 val modifiedFields = SS.addList (SS.empty, map #1 vals) |
607 (* TODO: don't use field name hack. *) | 638 (* TODO: don't use field name hack. *) |
608 val markField = | 639 fun markFields table = |
609 fn e as Sql.Field (t, v) => if SS.member (modifiedFields, v) | 640 fn e as Sql.Field (t, v) => if t = table andalso SS.member (modifiedFields, v) |
610 then Sql.Field (t, v ^ "'") | 641 then Sql.Field (t, v ^ "'") |
611 else e | 642 else e |
643 | Sql.SqNot e => Sql.SqNot (markFields table e) | |
644 | Sql.Binop (r, e1, e2) => Sql.Binop (r, markFields table e1, markFields table e2) | |
645 | Sql.SqKnown e => Sql.SqKnown (markFields table e) | |
646 | Sql.SqFunc (s, e) => Sql.SqFunc (s, markFields table e) | |
612 | e => e | 647 | e => e |
613 val mark = mapFormula (fn (cmp, e1, e2) => (cmp, markField e1, markField e2)) | 648 val mark = mapFormulaExps (markFields "T") |
614 in | 649 in |
615 renameTables [(table, "T")] | 650 (* Inside renameTables, we mark with table "T". Outside, we use the real table name. *) |
616 (Combo (Disj, [Combo (Conj, [fVals, mark fWhere]), | 651 (renameTables [(table, "T")] |
617 Combo (Conj, [mark fVals, fWhere])])) | 652 (Combo (Disj, [Combo (Conj, [fVals (id, markFields "T"), mark fWhere]), |
618 end | 653 Combo (Conj, [fVals (markFields "T", id), fWhere])])), |
619 | 654 SOME (markFields table)) |
620 (* val rec toFormula = *) | 655 end |
621 (* fn (Sql.Union (q1, q2), d) => Combo (Disj, [toFormula (q1, d), toFormula (q2, d)]) *) | 656 |
622 (* | (q as Sql.Query1 {Select = items, ...}, d) => *) | 657 fun pairToFormulas (query, dml) = |
623 (* let *) | 658 let |
624 (* val selected = osequence (map (fn )) *) | 659 val (fDml, marker) = dmlToFormulaMarker dml |
625 (* in *) | 660 in |
626 (* case selected of *) | 661 (queryToFormula marker query, fDml) |
627 (* NONE => (Combo (Conj, [markQuery (), markDml fDml])) *) | 662 end |
628 (* end *) | 663 |
664 (* structure ToFormula = struct *) | |
665 | |
666 (* val testOfQuery : Sql.query1 -> (Sql.cmp * Sql.sqexp * Sql.sqexp) formula = *) | |
667 (* fn {From = tablePairs, Where = SOME e, ...} => renameTables tablePairs (sqexpToFormula e) *) | |
668 (* | {Where = NONE, ...} => Combo (Conj, []) *) | |
669 | |
670 (* (* If selecting some parsable subset of fields, says which ones. [NONE] *) | |
671 (* means anything could be selected. *) *) | |
672 (* fun fieldsOfQuery (q : Sql.query1) = *) | |
673 (* osequence (map (fn Sql.SqField tf => SOME tf *) | |
674 (* | Sql.SqExp (Sql.Field tf) => SOME tf *) | |
675 (* | _ => NONE) (#Select q)) *) | |
676 | |
677 (* fun fieldsOfVals (table, vals, wher) = *) | |
678 (* let *) | |
679 (* val fWhere = renameTables [(table, "T")] (sqexpToFormula wher) *) | |
680 (* val fVals = valsToFormula (table, vals) *) | |
681 (* val modifiedFields = SS.addList (SS.empty, map #1 vals) *) | |
682 (* (* TODO: don't use field name hack. *) *) | |
683 (* val markField = *) | |
684 (* fn e as Sql.Field (t, v) => if SS.member (modifiedFields, v) *) | |
685 (* then Sql.Field (t, v ^ "'") *) | |
686 (* else e *) | |
687 (* | e => e *) | |
688 (* val mark = mapFormula (fn (cmp, e1, e2) => (cmp, markField e1, markField e2)) *) | |
689 (* in *) | |
690 (* renameTables [(table, "T")] *) | |
691 (* (Combo (Disj, [Combo (Conj, [fVals, mark fWhere]), *) | |
692 (* Combo (Conj, [mark fVals, fWhere])])) *) | |
693 (* end *) | |
694 (* end *) | |
629 | 695 |
630 structure ConflictMaps = struct | 696 structure ConflictMaps = struct |
631 | 697 |
632 structure TK = TripleKeyFn(structure I = CmpKey | 698 structure TK = TripleKeyFn(structure I = CmpKey |
633 structure J = AtomOptionKey | 699 structure J = AtomOptionKey |
634 structure K = AtomOptionKey) | 700 structure K = AtomOptionKey) |
701 | |
635 structure TS : ORD_SET = BinarySetFn(TK) | 702 structure TS : ORD_SET = BinarySetFn(TK) |
636 | 703 |
637 val toKnownEquality = | 704 val toKnownEquality = |
638 (* [NONE] here means unkown. Anything that isn't a comparison between two | 705 (* [NONE] here means unkown. Anything that isn't a comparison between two |
639 knowns shouldn't be used, and simply dropping unused terms is okay in | 706 knowns shouldn't be used, and simply dropping unused terms is okay in |
640 disjunctive normal form. *) | 707 disjunctive normal form. *) |
641 fn (Sql.Eq, SOME e1, SOME e2) => SOME (e1, e2) | 708 fn (Sql.Eq, SOME e1, SOME e2) => SOME (e1, e2) |
642 | _ => NONE | 709 | _ => NONE |
643 | 710 |
644 val equivClasses : (Sql.cmp * atomExp option * atomExp option) list -> atomExp list list = | 711 fun equivClasses atoms : atomExp list list option = |
645 UF.classes | 712 let |
646 o List.foldl UF.union' UF.empty | 713 val uf = List.foldl UF.union' UF.empty (List.mapPartial toKnownEquality atoms) |
647 o List.mapPartial toKnownEquality | 714 val ineqs = List.filter (fn (cmp, _, _) => |
715 cmp = Sql.Ne orelse cmp = Sql.Lt orelse cmp = Sql.Gt) | |
716 atoms | |
717 val contradiction = | |
718 fn (cmp, SOME ae1, SOME ae2) => (cmp = Sql.Ne orelse cmp = Sql.Lt orelse cmp = Sql.Gt) | |
719 andalso not (UF.together (uf, ae1, ae2)) | |
720 (* If we don't know one side of the comparision, not a contradiction. *) | |
721 | _ => false | |
722 in | |
723 not (List.exists contradiction atoms) <\oguard\> SOME (UF.classes uf) | |
724 end | |
648 | 725 |
649 fun addToEqs (eqs, n, e) = | 726 fun addToEqs (eqs, n, e) = |
650 case IM.find (eqs, n) of | 727 case IM.find (eqs, n) of |
651 (* Comparing to a constant is probably better than comparing to a | 728 (* Comparing to a constant is probably better than comparing to a |
652 variable? Checking that existing constants match a new ones is | 729 variable? Checking that existing constants match a new ones is |
732 o map (fn xs => TS.addList (TS.empty, xs)) | 809 o map (fn xs => TS.addList (TS.empty, xs)) |
733 | 810 |
734 fun dnf (fQuery, fDml) = | 811 fun dnf (fQuery, fDml) = |
735 normalize simplify normalizeAtom Disj (Combo (Conj, [markQuery fQuery, markDml fDml])) | 812 normalize simplify normalizeAtom Disj (Combo (Conj, [markQuery fQuery, markDml fDml])) |
736 | 813 |
737 val conflictMaps = List.mapPartial (mergeEqs o map eqsOfClass o equivClasses) o dnf | 814 val conflictMaps = |
815 List.mapPartial (mergeEqs o map eqsOfClass) | |
816 o List.mapPartial equivClasses | |
817 o dnf | |
738 | 818 |
739 end | 819 end |
740 | 820 |
741 val conflictMaps = ConflictMaps.conflictMaps | 821 val conflictMaps = ConflictMaps.conflictMaps |
742 | 822 |
1228 in | 1308 in |
1229 (map (map optionAtomExpToExp) | 1309 (map (map optionAtomExpToExp) |
1230 o removeRedundant madeRedundantBy | 1310 o removeRedundant madeRedundantBy |
1231 o map (eqsToInvalidation numArgs) | 1311 o map (eqsToInvalidation numArgs) |
1232 o conflictMaps) | 1312 o conflictMaps) |
1233 (queryToFormula query, dmlToFormula dml) | 1313 (pairToFormulas (query, dml)) |
1234 end | 1314 end |
1235 | 1315 |
1236 end | 1316 end |
1237 | 1317 |
1238 val invalidations = Invalidations.invalidations | 1318 val invalidations = Invalidations.invalidations |
1267 (* TODO: fail more gracefully. *) | 1347 (* TODO: fail more gracefully. *) |
1268 NONE => raise Match | 1348 NONE => raise Match |
1269 | SOME invs => sequence (flushes invs @ [dmlExp]) | 1349 | SOME invs => sequence (flushes invs @ [dmlExp]) |
1270 end | 1350 end |
1271 | e' => e' | 1351 | e' => e' |
1352 val file = fileMap doExp file | |
1353 | |
1272 in | 1354 in |
1273 (* DEBUG *) | 1355 (* DEBUG *) |
1274 (* gunk := []; *) | 1356 (* gunk := []; *) |
1275 ffiInfoRef := ffiInfo; | 1357 ffiInfoRef := ffiInfo; |
1276 fileMap doExp file | 1358 file |
1277 end | 1359 end |
1278 | 1360 |
1279 | 1361 |
1280 (************************) | 1362 (************************) |
1281 (* Compiler Entry Point *) | 1363 (* Compiler Entry Point *) |