comparison src/sql.sml @ 2202:606af2c9b828

Identifies tables read or touched by queries.
author Ziv Scully <ziv@mit.edu>
date Sat, 08 Mar 2014 05:06:22 -0500
parents cb0f05bdc183
children 39faa4a037f4
comparison
equal deleted inserted replaced
1994:94529780bbcf 2202:606af2c9b828
1 structure Sql = struct 1 structure Sql = struct
2 2
3 open Mono 3 open Mono
4 4
5 val debug = ref false 5 val debug = ref true (*false*)
6 6
7 type lvar = int 7 type lvar = int
8 8
9 datatype func = 9 datatype func =
10 DtCon0 of string 10 DtCon0 of string
236 | SOME (s, []) => SOME (s, chs) 236 | SOME (s, []) => SOME (s, chs)
237 | SOME (s, cs) => SOME (s, String (String.implode cs) :: chs) 237 | SOME (s, cs) => SOME (s, String (String.implode cs) :: chs)
238 end 238 end
239 else 239 else
240 NONE 240 NONE
241 | _ => NONE 241 | _ => NONE
242 242
243 val prim = 243 val prim =
244 altL [wrap (follow (wrapP (follow (keep Char.isDigit) (follow (const ".") (keep Char.isDigit))) 244 altL [wrap (follow (wrapP (follow (keep Char.isDigit) (follow (const ".") (keep Char.isDigit)))
245 (fn (x, ((), y)) => Option.map Prim.Float (Real64.fromString (x ^ "." ^ y)))) 245 (fn (x, ((), y)) => Option.map Prim.Float (Real64.fromString (x ^ "." ^ y))))
246 (opt (const "::float8"))) #1, 246 (opt (const "::float8"))) #1,
265 | Exp (ECase (e, [((PCon (_, PConFfi {mod = "Basis", con = "True", ...}, NONE), _), 265 | Exp (ECase (e, [((PCon (_, PConFfi {mod = "Basis", con = "True", ...}, NONE), _),
266 (EPrim (Prim.String "TRUE"), _)), 266 (EPrim (Prim.String "TRUE"), _)),
267 ((PCon (_, PConFfi {mod = "Basis", con = "False", ...}, NONE), _), 267 ((PCon (_, PConFfi {mod = "Basis", con = "False", ...}, NONE), _),
268 (EPrim (Prim.String "FALSE"), _))], _), _) :: chs => 268 (EPrim (Prim.String "FALSE"), _))], _), _) :: chs =>
269 SOME (e, chs) 269 SOME (e, chs)
270 270
271 | _ => NONE 271 | _ => NONE
272 272
273 fun constK s = wrap (const s) (fn () => s) 273 fun constK s = wrap (const s) (fn () => s)
274 274
275 val funcName = altL [constK "COUNT", 275 val funcName = altL [constK "COUNT",
315 (fn ((), (e, ())) => e)]) 315 (fn ((), (e, ())) => e)])
316 chs 316 chs
317 317
318 and known chs = wrap (follow known' (follow (const "(") (follow sqexp (const ")")))) 318 and known chs = wrap (follow known' (follow (const "(") (follow sqexp (const ")"))))
319 (fn ((), ((), (e, ()))) => e) chs 319 (fn ((), ((), (e, ()))) => e) chs
320 320
321 and func chs = wrap (follow funcName (follow (const "(") (follow sqexp (const ")")))) 321 and func chs = wrap (follow funcName (follow (const "(") (follow sqexp (const ")"))))
322 (fn (f, ((), (e, ()))) => (f, e)) chs 322 (fn (f, ((), (e, ()))) => (f, e)) chs
323 323
324 datatype sitem = 324 datatype sitem =
325 SqField of string * string 325 SqField of string * string
423 Query of query 423 Query of query
424 | Dml of dml 424 | Dml of dml
425 425
426 val querydml = log "querydml" (altL [wrap dml Dml, wrap query Query]) 426 val querydml = log "querydml" (altL [wrap dml Dml, wrap query Query])
427 427
428 (* New stuff. *)
429
430 fun subExps' (exp' : Mono.exp') =
431 case exp' of
432 ECon (_,_,SOME exp) => [exp]
433 | ESome (_,exp) => [exp]
434 | EFfiApp (_,_,xs) => map #1 xs
435 | EApp (exp1,exp2) => [exp1, exp2]
436 | EAbs (_,_,_,exp) => [exp]
437 | EUnop (_,exp) => [exp]
438 | EBinop (_,_,exp1,exp2) => [exp1, exp2]
439 | ERecord xs => map #2 xs
440 | EField (exp,_) => [exp]
441 | ECase (exp,xs,_) => exp :: map #2 xs
442 | EStrcat (exp1,exp2) => [exp1,exp2]
443 | EError (exp,_) => [exp]
444 | EReturnBlob {blob=NONE, mimeType, ...} => [mimeType]
445 | EReturnBlob {blob=SOME exp, mimeType, ...} => [exp, mimeType]
446 | ERedirect (exp,_) => [exp]
447 | EWrite exp => [exp]
448 | ESeq (exp1,exp2) => [exp1, exp2]
449 | ELet (_,_,exp1,exp2) => [exp1, exp2]
450 | EClosure (_,xs) => xs
451 | EQuery {query, body, initial, ...} => [query, body, initial]
452 | EDml (exp,_) => [exp]
453 | ENextval exp => [exp]
454 | ESetval (exp1,exp2) => [exp1, exp2]
455 | EUnurlify (exp,_,_) => [exp]
456 | EJavaScript (_,exp) => [exp]
457 | ESignalReturn exp => [exp]
458 | ESignalBind (exp1,exp2) => [exp1, exp2]
459 | ESignalSource exp => [exp]
460 | EServerCall (exp,_,_,_) => [exp]
461 | ERecv (exp,_) => [exp]
462 | ESleep exp => [exp]
463 | ESpawn exp => [exp]
464 | _ => []
465
466 val subExps : Mono.exp -> Mono.exp list = subExps' o #1
467
468 fun println str = print (str ^ "\n")
469 fun printlnExp exp = (Print.print (MonoPrint.p_exp MonoEnv.empty exp); println "")
470
471 fun tablesRead (Query1 {From=tablePairs, ...}) = map #1 tablePairs
472 | tablesRead (Union (q1,q2)) = tablesRead q1 @ tablesRead q2
473
474 fun tableTouched (Insert (tab,_)) = tab
475 | tableTouched (Delete (tab,_)) = tab
476 | tableTouched (Update (tab,_,_)) = tab
477
478 fun goExp (exp : Mono.exp) =
479 case #1 exp of
480 EQuery {query=e, ...} => (
481 case parse query e of
482 SOME q => println ("Query reads from " ^ String.concatWith ", " (tablesRead q))
483 | NONE => println "Couldn't parse query";
484 printlnExp exp; println "")
485 | EDml (e,_) => (
486 case parse dml e of
487 SOME d => println ("DML touches " ^ tableTouched d)
488 | NONE => println "Couldn't parse DML";
489 printlnExp exp; println "")
490 | ENextval _ => (printlnExp exp; println "")
491 | ESetval _ => (printlnExp exp; println "")
492 (* Recurse down the syntax tree. *)
493 | _ => app goExp (subExps exp)
494
495 fun goDecl (decl : decl) =
496 case #1 decl of
497 DVal (_,_,_,exp,_) => goExp exp
498 | DValRec xs => app (goExp o #4) xs
499 | _ => ()
500
501 fun goFile (file : file) = app goDecl (#1 file)
502
503 fun go file = (println "Doing SQL analysis.\n"; goFile file; ())
504
428 end 505 end