* http://cs.unibo.it/helm/.
*)
-open Dbconn;;
-open Union;;
-open Intersect;;
-open Meet;;
-open Property;;
-open Sub;;
-open Context;;
-open Diff;;
-open Relation;;
-open Func;;
-open Pattern;;
-
-exception SVarUnbound of string;;
-exception RVarUnbound of string;;
-exception VVarUnbound of string;;
-exception PathUnbound of (string * string list);;
-
-exception InvalidConnection
-exception ConnectionFailed of string
-
-exception BooleExpTrue
-
-(* valuta una MathQL.set_exp e ritorna un MathQL.resource_set *)
-
-let galax_char = 'G'
-let stat_char = 'S'
-
-let execute_aux log m x =
- let module M = MathQL in
- let module X = MQueryMisc in
-let rec exec_set_exp c = function
- M.SVar svar ->
- (try
- List.assoc svar c.svars
- with Not_found ->
- raise (SVarUnbound svar))
- | M.RVar rvar ->
- (try
- [List.assoc rvar c.rvars]
- with Not_found ->
- raise (RVarUnbound rvar))
- | M.Ref vexp -> List.map (fun s -> (s,[])) (exec_val_exp c vexp)
- | M.Pattern vexp -> pattern_ex (exec_val_exp c vexp)
- | M.Intersect (sexp1, sexp2) ->
- let before = X.start_time() in
- let rs1 = exec_set_exp c sexp1 in
- let rs2 = exec_set_exp c sexp2 in
- let res = intersect_ex rs1 rs2 in
- let diff = X.stop_time before in
- let ll1 = string_of_int (List.length rs1) in
- let ll2 = string_of_int (List.length rs2) in
- if String.contains m stat_char then
- log ("INTERSECT(" ^ ll1 ^ "," ^ ll2 ^ ") = " ^ string_of_int (List.length res) ^
- ": " ^ diff ^ "\n");
- res
- | M.Union (sexp1, sexp2) ->
- let before = X.start_time () in
- let res = union_ex (exec_set_exp c sexp1) (exec_set_exp c sexp2) in
- let diff = X.stop_time before in
- if String.contains m stat_char then log ("UNION: " ^ diff ^ "\n");
- res
- | M.LetSVar (svar, sexp1, sexp2) ->
- let before = X.start_time() in
- let c1 = upd_svars c ((svar, exec_set_exp c sexp1) :: c.svars) in
- let res = exec_set_exp c1 sexp2 in
- if String.contains m stat_char then begin
- log ("LETIN " ^ svar ^ " = " ^ string_of_int (List.length res) ^ ": ");
- log (X.stop_time before ^ "\n");
- end;
- res
- | M.LetVVar (vvar, vexp, sexp) ->
- let before = X.start_time() in
- let c1 = upd_vvars c ((vvar, exec_val_exp c vexp) :: c.vvars) in
- let res = exec_set_exp c1 sexp in
- if String.contains m stat_char then begin
- log ("LETIN " ^ vvar ^ " = " ^ string_of_int (List.length res) ^ ": ");
- log (X.stop_time before ^ "\n");
- end;
- res
- | M.Relation (inv, rop, path, sexp, assl) ->
- let before = X.start_time() in
- if String.contains m galax_char then begin
- let res = relation_galax_ex inv rop path (exec_set_exp c sexp) assl in
- if String.contains m stat_char then begin
- log ("RELATION-GALAX " ^ (fst path) ^ " = " ^ string_of_int(List.length res) ^ ": ");
- log (X.stop_time before ^ "\n")
- end;
- res
- end else begin
- let res = relation_ex inv rop path (exec_set_exp c sexp) assl in
- if String.contains m stat_char then begin
- log ("RELATION " ^ (fst path) ^ " = " ^ string_of_int(List.length res) ^ ": ");
- log (X.stop_time before ^ "\n")
- end;
- res
- end
- | M.Select (rvar, sexp, bexp) ->
- let before = X.start_time() in
- let rset = (exec_set_exp c sexp) in
- let rec select_ex =
- function
- [] -> []
- | r::tl ->
- let c1 = upd_rvars c ((rvar,r)::c.rvars) in
- if (exec_boole_exp c1 bexp) then
- r::(select_ex tl)
- else
- select_ex tl
- in
- let res = select_ex rset in
- if String.contains m stat_char then begin
- log ("SELECT " ^ rvar ^ " = " ^ string_of_int (List.length res) ^ ": ");
- log (X.stop_time before ^ "\n");
- end;
- res
- | M.Diff (sexp1, sexp2) -> diff_ex (exec_set_exp c sexp1) (exec_set_exp c sexp2)
-
-(* valuta una MathQL.boole_exp e ritorna un boole *)
+(* AUTOR: Ferruccio Guidi <fguidi@cs.unibo.it>
+ *)
-and exec_boole_exp c =
- function
- M.False -> false
- | M.True -> true
- | M.Not x -> not (exec_boole_exp c x)
- | M.And (x, y) -> (exec_boole_exp c x) && (exec_boole_exp c y)
- | M.Or (x, y) -> (exec_boole_exp c x) || (exec_boole_exp c y)
- | M.Sub (vexp1, vexp2) ->
- sub_ex (exec_val_exp c vexp1) (exec_val_exp c vexp2)
- | M.Meet (vexp1, vexp2) ->
- meet_ex (exec_val_exp c vexp1) (exec_val_exp c vexp2)
- | M.Eq (vexp1, vexp2) -> (exec_val_exp c vexp1) = (exec_val_exp c vexp2)
- | M.Ex l bexp ->
- if l = [] then
- (exec_boole_exp c bexp)
- else
- let latt =
- List.map
- (fun uri ->
- let (r,attl) =
- (try
- List.assoc uri c.rvars
- with Not_found -> assert false)
- in
- (uri,attl)
- ) l (*latt = l + attributi*)
- in
- try
- let rec prod c =
- function
- [] -> if (exec_boole_exp c bexp) then raise BooleExpTrue
- | (uri,attl)::tail1 ->
- (*per ogni el. di attl devo andare in ric. su tail1*)
- let rec sub_prod attl =
- match attl with
- [] -> ()
- | att::tail2 ->
- let c1 = upd_groups c ((uri,att)::c.groups) in
- prod c1 tail1; sub_prod tail2
- in
- sub_prod attl
- in
- prod c latt;
- false
- with BooleExpTrue -> true
+(* contexts *****************************************************************)
-(* valuta una MathQL.val_exp e ritorna un MathQL.value *)
+type svar_context = (MathQL.svar * MathQL.resource_set) list
-and exec_val_exp c = function
- M.Const x -> let
- ol = List.sort compare x in
- let rec edup = function
-
- [] -> []
- | s::tl -> if tl <> [] then
- if s = (List.hd tl) then edup tl
- else s::(edup tl)
- else s::[]
- in
- edup ol
- | M.Record (rvar, path) ->
- (try
- List.assoc path
- (try
- List.assoc rvar c.groups
- with Not_found ->
- raise (RVarUnbound rvar))
- with Not_found ->
- raise (PathUnbound path))
- | M.VVar s ->
- (try
- List.assoc s c.vvars
- with Not_found ->
- raise (VVarUnbound s))
- | M.RefOf sexp -> List.map (fun (s,_) -> s) (exec_set_exp c sexp)
- | M.Fun (s, vexp) -> fun_ex s (exec_val_exp c vexp)
- | M.Property (inv, rop, path, vexp) -> property_ex rop path inv (exec_val_exp c vexp)
+type avar_context = (MathQL.avar * MathQL.resource) list
-(* valuta una MathQL.set_exp nel contesto vuoto e ritorna un MathQL.resource_set *)
-in
- exec_set_exp {svars = []; rvars = []; groups = []; vvars = []} x
+type group_context = (MathQL.avar * MathQL.attribute_group) list
-(* new interface ***********************************************************)
+type vvar_context = (MathQL.vvar * MathQL.value) list
-module type Callbacks =
- sig
- val log : string -> unit (* logging function *)
- end
+type context = {svars: svar_context;
+ avars: avar_context;
+ groups: group_context; (* auxiliary context *)
+ vvars: vvar_context
+ }
-module Make (C: Callbacks) =
- struct
-
- let postgres = "P"
- let galax = "G"
- let stat = "S"
- let quiet = "Q"
- let warn = "W"
+(* execute *****************************************************************)
- let execute m x = execute_aux C.log m x
+exception Found
- let init m =
- let default_connection_string =
- "host=mowgli.cs.unibo.it dbname=helm_mowgli_new_schema user=helm"
- in
- let connection_string =
- try Sys.getenv "POSTGRESQL_CONNECTION_STRING"
- with Not_found -> default_connection_string
- in
- if String.contains m galax_char then true else
- try Dbconn.init connection_string; true
- with ConnectionFailed s -> false
+module M = MathQL
+module P = MQueryUtil
+module C = MQIConn
+module U = MQIUtil
- let close m =
- if String.contains m galax_char then () else Dbconn.close ()
-
- let check m =
- if String.contains m galax_char then false else
- try ignore (Dbconn.pgc ()); true with InvalidConnection -> false
-
- end
+let execute h x =
+ let warn q =
+ if C.set h C.Warn then
+ begin
+ C.log h "MQIExecute: waring: reference to undefined variables: ";
+ P.text_of_query (C.log h) "\n" q
+ end
+ in
+ let rec eval_val c = function
+ | M.False -> U.mql_false
+ | M.True -> U.mql_true
+ | M.Const s -> [s]
+ | M.Set l -> U.iter (eval_val c) l
+ | M.Test (k,y1,y2) ->
+ let cand y1 y2 =
+ if eval_val c y1 = U.mql_false then U.mql_false else eval_val c y2
+ in
+ let cor y1 y2 =
+ let v1 = eval_val c y1 in
+ if v1 = U.mql_false then eval_val c y2 else v1
+ in
+ let h f y1 y2 = f (eval_val c y1) (eval_val c y2) in
+ let f = match k with
+ | M.And -> cand
+ | M.Or -> cor
+ | M.Xor -> h U.xor
+ | M.Sub -> h U.set_sub
+ | M.Meet -> h U.set_meet
+ | M.Eq -> h U.set_eq
+ | M.Le -> h U.le
+ | M.Lt -> h U.lt
+ in
+ f y1 y2
+ | M.Not y ->
+ if eval_val c y = U.mql_false then U.mql_true else U.mql_false
+ | M.VVar i -> begin
+ try List.assoc i c.vvars
+ with Not_found -> warn (M.Subj (M.VVar i)); [] end
+ | M.Dot (i,p) -> begin
+ try List.assoc p (List.assoc i c.groups)
+ with Not_found -> warn (M.Subj (M.Dot (i,p))); [] end
+ | M.Proj (None,x) -> List.map (fun (r, _) -> r) (eval_query c x)
+ | M.Proj ((Some p),x) ->
+ let proj_group_aux (q, v) = if q = p then v else [] in
+ let proj_group a = U.iter proj_group_aux a in
+ let proj_set (_, g) = U.iter proj_group g in
+ U.iter proj_set (eval_query c x)
+ | M.Ex (l,y) ->
+ let rec ex_aux h = function
+ | [] ->
+ let d = {c with groups = h} in
+ if eval_val d y = U.mql_false then () else raise Found
+ | i :: tail ->
+ begin
+ try
+ let (_, a) = List.assoc i c.avars in
+ let rec add_group = function
+ | [] -> ()
+ | g :: t -> ex_aux ((i, g) :: h) tail; add_group t
+ in
+ add_group a
+ with Not_found -> ()
+ end
+ in
+ (try ex_aux [] l; U.mql_false with Found -> U.mql_true)
+ | M.StatVal y ->
+ let t = P.start_time () in
+ let r = (eval_val c y) in
+ let s = P.stop_time t in
+ C.log h (Printf.sprintf "Stat: %s,%i\n" s (List.length r));
+ r
+ | M.Count y -> [string_of_int (List.length (eval_val c y))]
+ | M.Align (s,y) -> U.iter (U.align s) (eval_val c y)
+ and eval_query c = function
+ | M.Empty -> []
+ | M.Subj x ->
+ List.map (fun s -> (s, [])) (eval_val c x)
+ | M.Log (_,b,x) ->
+ if b then begin
+ let t = P.start_time () in
+ P.text_of_query (C.log h) "\n" x;
+ let s = P.stop_time t in
+ if C.set h C.Times then
+ C.log h (Printf.sprintf "Log source: %s\n" s);
+ eval_query c x
+ end else begin
+ let s = (eval_query c x) in
+ let t = P.start_time () in
+ P.text_of_result (C.log h) "\n" s;
+ let r = P.stop_time t in
+ if C.set h C.Times then
+ C.log h (Printf.sprintf "Log: %s\n" r);
+ s
+ end
+ | M.If (y,x1,x2) ->
+ if (eval_val c y) = U.mql_false
+ then (eval_query c x2) else (eval_query c x1)
+ | M.Bin (k,x1,x2) ->
+ let f = match k with
+ | M.BinFJoin -> U.mql_union
+ | M.BinFMeet -> U.mql_intersect
+ | M.BinFDiff -> U.mql_diff
+ in
+ f (eval_query c x1) (eval_query c x2)
+ | M.SVar i -> begin
+ try List.assoc i c.svars
+ with Not_found -> warn (M.SVar i); [] end
+ | M.AVar i -> begin
+ try [List.assoc i c.avars]
+ with Not_found -> warn (M.AVar i); [] end
+ | M.LetSVar (i,x1,x2) ->
+ let d = {c with svars = U.set (i, eval_query c x1) c.svars} in
+ eval_query d x2
+ | M.LetVVar (i,y,x) ->
+ let d = {c with vvars = U.set (i, eval_val c y) c.vvars} in
+ eval_query d x
+ | M.For (k,i,x1,x2) ->
+ let f = match k with
+ | M.GenFJoin -> U.mql_union
+ | M.GenFMeet -> U.mql_intersect
+ in
+ let rec for_aux = function
+ | [] -> []
+ | h :: t ->
+ let d = {c with avars = U.set (i, h) c.avars} in
+ f (eval_query d x2) (for_aux t)
+ in
+ for_aux (eval_query c x1)
+ | M.Add (b,z,x) ->
+ let f = if b then U.mql_prod else U.set_union in
+ let g a s = (fst a, f (snd a) (eval_grp c z)) :: s in
+ List.fold_right g (eval_query c x) []
+ | M.Property (q0,q1,q2,mc,ct,cfl,el,pat,y) ->
+ let subj, mct =
+ if q0 then [], (pat, q2 @ mc, eval_val c y)
+ else (q2 @ mc), (pat, [], eval_val c y)
+ in
+ let eval_cons (pat, p, y) = (pat, q2 @ p, eval_val c y) in
+ let cons_true = mct :: List.map eval_cons ct in
+ let cons_false = List.map (List.map eval_cons) cfl in
+ let eval_exp (p, po) = (q2 @ p, po) in
+ let exp = List.map eval_exp el in
+ let t = P.start_time () in
+ let r = MQIProperty.exec h q1 subj cons_true cons_false exp in
+ let s = P.stop_time t in
+ if C.set h C.Times then
+ C.log h (Printf.sprintf "Property: %s,%i\n" s (List.length r));
+ r
+ | M.StatQuery x ->
+ let t = P.start_time () in
+ let r = (eval_query c x) in
+ let s = P.stop_time t in
+ C.log h (Printf.sprintf "Stat: %s,%i\n" s (List.length r));
+ r
+ | M.Select (i,x,y) ->
+ let rec select_aux = function
+ | [] -> []
+ | h :: t ->
+ let d = {c with avars = U.set (i, h) c.avars} in
+ if eval_val d y = U.mql_false
+ then select_aux t else h :: select_aux t
+ in
+ select_aux (eval_query c x)
+ | M.Keep (b,l,x) ->
+ let keep_path (p, v) t =
+ if List.mem p l = b then t else (p, v) :: t in
+ let keep_grp a = List.fold_right keep_path a [] in
+ let keep_set a g =
+ let kg = keep_grp a in
+ if kg = [] then g else kg :: g
+ in
+ let keep_av (s, g) = (s, List.fold_right keep_set g []) in
+ List.map keep_av (eval_query c x)
+ and eval_grp c = function
+ | M.Attr gs ->
+ let attr_aux g (p, y) = U.mql_union g [(p, eval_val c y)] in
+ let attr_auxs s l = U.set_union s [List.fold_left attr_aux [] l] in
+ List.fold_left attr_auxs [] gs
+ | M.From i ->
+ try snd (List.assoc i c.avars)
+ with Not_found -> warn (M.AVar i); []
+ in
+ let c = {svars = []; avars = []; groups = []; vvars = []} in
+ let t = P.start_time () in
+ if C.set h C.Source then P.text_of_query (C.log h) "\n" x;
+ let r = eval_query c x in
+ if C.set h C.Result then P.text_of_result (C.log h) "\n" r;
+ let s = P.stop_time t in
+ if C.set h C.Times then
+ C.log h (Printf.sprintf "MQIExecute: %s,%s\n" s
+ (C.string_of_flags (C.flags h)));
+ r