/********************************************************************************* * * Translating ODMG OQL into monoid comprehensions * Copyright (c) 1999-2003 by Leonidas Fegaras, the University of Texas at * Arlington. All rights reserved. * Programmer: Leonidas Fegaras * Date: 10/8/98 * ********************************************************************************/ #include "odl.h" #include "typecheck.h" list* comparison_operators = Nil->cons(#)->cons(#)->cons(#)->cons(#)->cons(#)->cons(#); list* aggregate_operators = Nil->cons(#)->cons(#)->cons(#)->cons(#)->cons(#); /* alpha coersion (renaming variables to avoid name conflicts) */ Expr rename_vars ( Expr term, binding* binds ); /* given a pattern, return a new pattern of the same shape but with fresh variables */ Expr new_patterns ( Expr pattern ); /* bind pattern variables to values; eg. pattern_binding of pair(pair(a,b),c) * to pair(pair(1,2),3) will bind a to 1, b to 2, and c to 3 */ binding* pattern_bindings ( Expr pattern, Expr value ); /* translates the projection part of a select-from-where OQL clause */ Expr translate_projection ( list* project_list, list* from_list, list* group_by_list ) { if (project_list->consp() && project_list->tl->nullp() && project_list->hd->eq(#)) { if (group_by_list->consp()) { list* r = Cons(#,Nil); for(list* by = group_by_list; by->consp(); by=by->tl) #case by->hd | bind(`v,_) => r = r->cons(#); | _ => r = r->cons(#hd))>); #end; return #; }; list* s = Nil; for(list* fl = from_list; fl->consp(); fl=fl->tl) #case fl->hd | iterate(`x,_) => s = s->cons(#name())),`x)>); #end; if (s->tl->nullp()) return s->hd->arguments()->hd; s = s->reverse(); return #; }; if (project_list->consp() && project_list->tl->nullp()) #case project_list->hd | bind(`x,`e) => return #; | _ => return project_list->hd; #end; list* s = Nil; for(list* pl = project_list; pl->consp(); pl=pl->tl) #case pl->hd | bind(`x,`e) => s = s->cons(pl->hd); | project(`e,`v) => s = s->cons(#hd))>); | `e => if (e->variablep()) s = s->cons(#name())),`e)>); else s = s->cons(#); #end; s = s->reverse(); return #; }; Expr fix_projection ( Expr e, Expr v ) { #case e | project(`x,`a) => return #; | _ => if (e->variablep()) return #; else return e; #end; }; bool is_projection ( Expr e ) { #case e | project(`x,`a,...r) => return is_projection(x); | _ => return e->variablep(); #end; }; Expr projection_variable ( Expr e ) { #case e | project(`x,`a,...r) => return projection_variable(x); | _ => return e; #end; }; /* fix SQL-like aggregations */ Expr fix_ugly_aggregations ( Expr e, list* binds ) { #case e | `h[`f(`v)] : member(f,aggregate_operators) && v->variablep() && member(v,binds) => { Expr nv = new_variable(); Expr nx = fix_projection(v,nv); if (f->eq(#)) return fix_ugly_aggregations(#<`h[compr(sum,1,iterate(`nv,partition))]>,binds); return fix_ugly_aggregations(#<`h[compr(`f,`nx,iterate(`nv,partition))]>,binds); }; | `h[project(`x,`a,...r)] : is_projection(x) && member(projection_variable(x),binds) => { Expr nv = new_variable(); Expr nx = fix_projection(x,nv); return fix_ugly_aggregations(#<`h[compr(set,project(`nx,`a,...r),iterate(`nv,partition))]>,binds); }; | _ => return e; #end; }; /* handle the group-by part of an OQL query */ list* make_partition ( list* qualifiers, list* group_by, Expr where ) { list* q = Nil; list* h = Nil; list* bl = Nil; binding* binds = new binding; for(list* s = qualifiers; s->consp(); s=s->tl) #case s->hd | iterate(`v,`e) => { Expr nv = new_patterns(v); binds = pattern_bindings(v,nv)->extend(binds); q = q->cons(#); h = h->cons(#); }; | bind(`v,`e) => { Expr nv = new_patterns(v); binds = pattern_bindings(v,nv)->extend(binds); q = q->cons(#); }; | _ => q = q->cons(rename_vars(s->hd,binds)); #end; Expr w = rename_vars(where,binds); list* eqs = Nil; for(list* b = group_by; b->consp(); b=b->tl) #case b->hd | bind(`v,`e) => { eqs = eqs->cons(#); bl = bl->cons(b->hd); }; | `e => eqs = eqs->cons(#); #end; Expr lv = fresh_type_variable(); q = q->reverse(); return bl->cons(#); }; /* convert an OQL term into a comprehension form */ Expr translate_term ( Expr e ) { #case e | struct(...r) => return #; | construct(`x,...r) => return #; | call(`x,...r) => return #; | member(`x,`s) => { Expr nv = new_variable(); return #; }; | listtoset(`x) => { Expr nx = new_variable(); return #; }; | intersect(`x,`y) => { Expr nx = new_variable(); Expr ny = new_variable(); Expr lv = fresh_type_variable(); return #; }; | except(`x,`y) => { Expr nx = new_variable(); Expr ny = new_variable(); Expr lv = fresh_type_variable(); return #; }; | union(`x,`y) => Expr lv = fresh_type_variable(); return #; | exists(`x,`s,`e) => return #; | exists(`s) => return #; | unique(`s) => return #; | forall(`x,`s,`e) => return #; | `f(`x,some,`y) : member(f,comparison_operators) => { Expr nv = new_variable(); return #; }; | `f(`x,any,`y) : member(f,comparison_operators) => { Expr nv = new_variable(); return #; }; | `f(`x,all,`y) : member(f,comparison_operators) => { Expr nv = new_variable(); return #; }; | group(`x,`s,NONE,...by) => { Expr nv = new_variable(); list* eqs = Nil; for(list* r = by; r->consp(); r=r->tl) #case r->hd | bind(_,`e) => eqs = eqs->cons(#); #end; eqs = eqs->reverse(); Expr lv = fresh_type_variable(); Expr tv = fresh_type_variable(); return #; }; | group(`x,`s,struct(...with),...by) => { Expr nv = new_variable(); list* eqs = Nil; for(list* r = by; r->consp(); r=r->tl) #case r->hd | bind(_,`e) => eqs = eqs->cons(#); #end; eqs = eqs->reverse(); Expr lv = fresh_type_variable(); Expr tv = fresh_type_variable(); Expr uv = fresh_type_variable(); return #; }; | flatten(`e) => { Expr nx = new_variable(); Expr ns = new_variable(); return #; }; | min(`e) => { Expr nx = new_variable(); return #; }; | max(`e) => { Expr nx = new_variable(); return #; }; | sum(`e) => { Expr nx = new_variable(); return #; }; | avg(`e) => { Expr nx = new_variable(); Expr ny = new_variable(); return #; }; | count(all) => { Expr nx = new_variable(); return #; }; | count(`e) => { Expr nx = new_variable(); return #; }; | `f(...r) => if (member(f,Nil->cons(#)->cons(#)->cons(#)->cons(#))) { if (r->nullp()) return #; r = r->reverse(); Expr res = #hd))>; for(list* s = r->tl; s->consp(); s=s->tl) res = #hd)),`res)>; return res; }; #end; return e; }; bool macrop ( Expr fname ) { #case get_declaration_binding(fname->name()) | define(`name,params(...ps),`body) => return true; | _ => return false; #end; }; /* convert an OQL term into a comprehension form */ Expr translate ( Expr e ) { Expr u; #case e | select(`m,project(...r),from(...s),`where,groupby(...by),`having,order(...ord)) => { if (ord->consp()) m = #; list* partition = Nil; Expr p = translate_projection(r,s,by); if (by->consp()) { partition = make_partition(s,by,where); list* range_vars = Nil; for(list* c = s; c->consp(); c=c->tl) #case c->hd | iterate(`v,`e) => range_vars = range_vars->cons(v); | bind(`v,`e) => range_vars = range_vars->cons(v); #end; p = fix_ugly_aggregations(p,range_vars); having = fix_ugly_aggregations(having,range_vars); }; Expr res = #; return translate(res); }; | call(`f,...args) /* macro definition */ : macrop(f) => #case get_declaration_binding(f->name()) | define(`name,params(...ps),`body) => { Expr new_exp = body; list* r = args; for(; r->consp() && ps->consp(); r=r->tl, ps=ps->tl) new_exp = subst_expr(ps->hd,r->hd,new_exp); if (r->consp() || ps->consp()) type_error("Wrong number of arguments in macro call",e); return translate(new_exp); }; #end; | `f(...r) => { list* nr = Nil; for(list* s = r; s->consp(); s=s->tl) nr = nr->cons(translate(s->hd)); nr = nr->reverse(); u = #<`f(...nr)>; }; | _ => u = e; #end; return translate_term(u); };