/******************************************************************************** * * The code generator for evaluating physical plans produced by the OQL optimizer. * The generated code contains calls to the evaluator functions (evaluator/eval.h) * * Copyright (c) 1999-2003 by Leonidas Fegaras, the University of Texas at * Arlington. All rights reserved. * Programmer: Leonidas Fegaras, UTA * Date: 10/20/98 * *********************************************************************************/ #include "odl.h" #include "typecheck.h" #include "constant.h" #include /* flag to indicate whether we are compiling or interpreting queries */ bool interpreterp = false; /* initial_offset is the offset of the first attribute in an ODL class */ class test_for_size { public: int x; }; static test_for_size test_for_size_var; const int initial_offset = ((char*) &test_for_size_var.x) - ((char*) &test_for_size_var); /* return the variables of a pattern */ list* pattern_variables ( Expr pattern ); extern binding* global_lvars; extern String current_module_name; extern ofstream fout; /* global environment for group-by vars */ GEnv gvars = new list*>; Schema gbinds = new binding; /* a type_of function that uses the global environment for variable binding */ Expr type ( Expr &e, Schema sch ) { Schema cvars = sch; Expr tp = typecheck(e,cvars,global_lvars,gvars); e = eliminate_type_vars(e,global_lvars,false,true); return eliminate_type_vars(tp,global_lvars,false,true); }; /* finds an evaluation function stored in the function table (defined in eval.cc) */ int find_function ( const char* function_name ); typedef struct { char* name; void* address; short args; short fncs; } function_table_element; const int function_table_size = 1000; extern int function_table_top; extern function_table_element function_table[function_table_size]; /* find an internal function */ Expr internal ( const char* fname, list* args ) { int loc = find_function(fname); if (loc<0) { Schema sch = new binding; String s = new string(fname); for(list*>* n = internal_methods->env; n->consp(); n=n->tl) if (n->hd->first->eq(s)) return #hd->second->name)),`(integer(n->hd->second->location)),boolean,...args)>; odmg_error("couldn't find the internal function",function(variable(new string(fname)),args)); }; return #; }; /* A stack of environments; each environment binds names to values or streams * that are active in the current plan */ list*>* active_environment = Cons(new binding,new list*>); void new_active_stream () { active_environment = Cons(new binding,active_environment); }; Expr new_environment_stream ( Expr stream ) { if (active_environment->nullp()) odmg_error("Wrong nested active streams",#); Expr v = new_variable(); active_environment->hd = active_environment->hd->extend(v->name(),stream); return #; }; Expr new_stream ( Expr e, bool materializep ) { Expr s = new_environment_stream(e); if (materializep) s = new_environment_stream(internal("materialize_stream",Cons(s,Nil))); return s; }; Expr close_active_stream ( Expr return_value ) { list* res = Nil; if (active_environment->nullp()) odmg_error("Wrong nested active streams",#); binding* last_env = active_environment->hd; for(Names nms = last_env->names(); nms->consp(); nms=nms->tl) { #case last_env->find(nms->hd) | bind(...r) => res = Cons(#,res); | `v => res = Cons(#hd)),`v,stream)>,res); #end; }; active_environment = active_environment->tl; if (res->nullp()) return return_value; #case return_value | xassign(...bs,`v) => return #; | _ => return #; #end; }; /* does e generate a collection? */ bool bulk_operation ( Expr e ) { #case e | `f(`m,...r) : member(f,Nil->cons(#)->cons(#)->cons(#)->cons(#) ->cons(#)->cons(#)) => return collectionp(m); | `f(...r) => return member(f,Nil->cons(#)->cons(#)->cons(#)->cons(#) ->cons(#)->cons(#)->cons(#)); | _ => return false; #end; }; /* if e is module:...:class, retrieve the class name */ Expr class_name ( Expr e ) { char* r = (char*) GC_malloc(strlen(e->name()->content())+1); int j = 0; for(int i = 0; iname()->length(); i++, j++) if (e->name()->content()[i] == ':') j = -1; else r[j] = e->name()->content()[i]; return variable(new string(r)); }; Expr find_binary_function ( const char* name, Expr type, Expr x, Expr y ) { Schema sch = new binding; if (type->eq(#)) type = #; int loc = find_internal_method(new string(name),Cons(type,Cons(type,Nil)),sch)->second; if (loc<0) odmg_error("Incompatible types for primitive operation",#<`(variable(new string(name)))(`type,`type)>); for(list*>* n = internal_methods->env; n->consp(); n=n->tl) { method_info* m = n->hd->second; if (m->location == loc) return #name)),`(integer(loc)),`(m->parameters->hd),`x,`y)>; }; }; list* expr_variables ( Expr e ) { for(Names s = gbinds->names(); s->consp(); s=s->tl) if (gbinds->find(s->hd)->eq(e)) return Cons(variable(s->hd),Nil); #case e | project(`x,`a,_) => return expr_variables(x); | `f(...r) => { list* s = Nil; for(; r->consp(); r=r->tl) s = s->append(expr_variables(r->hd)); return s; }; | true => return Nil; | false => return Nil; | `v => if (v->variablep()) return Cons(v,Nil); #end; return Nil; }; /* defined below */ Expr translate_expr ( Expr e, Schema sch, Schema stuple, int size ); Expr translate_opr ( Expr e, Schema &sch, Schema &stuple, Expr stream_prefix, bool materializep = false, bool streamp = true ); Expr translate_tuple ( Expr e, Schema sch, Schema stuple, int size ); int size_in_bytes ( Expr tp, bool is_raw_data = false ); Expr make_element ( Expr e, Schema sch, Schema stuple ) { Expr tp = type(e,sch); Expr ne = translate_expr(e,sch,stuple,stuple->length()); if (is_class(tp)) return #; else return #; }; /* translate a '%for each' loop (in stream-based fashion); sch is the typechecking schema, stuple is the schema of the input stream variables */ Expr translate_stream_opr ( Expr x, Schema &sch, Schema &stuple, bool materializep = false, bool streamp = true ) { new_active_stream(); Expr stream_prefix = #; if (stuple->length() > 0) { Names n = stuple->names(); stream_prefix = make_element(variable(n->hd),sch,stuple); for(n=n->tl; n->consp(); n=n->tl) stream_prefix = internal("concat_tuples",Cons(stream_prefix,Cons(make_element(variable(n->hd),sch,stuple),Nil))); }; return close_active_stream(translate_opr(x,sch,stuple,stream_prefix,materializep,streamp)); }; /* large values (>4B) are alligned at the beginning of words */ int round_size ( int n ) { return ((n-1) | 3) + 1; }; int add_sizes ( int n, int m ) { return (m >= 4) ? (((n-1) | 3) + 1)+m : n+m; }; /* generate an equality test between x and y (of type tp) */ Expr generate_equality ( Expr tp1, Expr tp2, Expr x, Expr y ) { #case tp1 | scope(`etp) => return generate_equality(get_declaration_binding(etp->name()),tp2,x,y); | void(`etp) => if (is_class(etp)) return generate_equality(etp,tp2,x,y); else return generate_equality(etp,tp2,#,#); | struct(...r) => { list* s = Nil; for(int i = 0; r->consp(); r=r->tl, i++) #case r->hd | bind(`v,`etp) => s = s->cons(generate_equality(etp,etp, #, #)); #end; if (s->nullp()) return #; Expr res = s->hd; for(list* n = s->tl; n->consp(); n=n->tl) res = find_binary_function("and",#,res,n->hd); return res; }; | enum(`nm,...r) => return internal("enum_equality",Cons(x,Cons(y,Nil))); | union(`nm,`tp,...cases) => { Expr res = #; int n = sizeof(type_tag); for(list* r=cases; r->consp(); r=r->tl) #case r->hd | case(`ctp,`decl,...tags) => { Expr cond = generate_equality(tp,tp,#, translate_expr(tags->hd,new binding,new binding,0)); for(list* s=tags->tl; s->consp(); s=s->tl) cond = find_binary_function("or",#,cond, generate_equality(tp,tp,#, translate_expr(s->hd,new binding,new binding,0))); Expr eq = generate_equality(ctp,ctp,#, #); n = add_sizes(n,size_in_bytes(ctp,true)); res = #; }; #end; return #,#)),`res,false)>; }; | class(...r) => return #; | `f(`etp) : collectionp(f) => { Expr eq = generate_equality(etp,etp,#,#); Expr eqf = #; #case f | set => return internal("set_equality",Cons(x,Cons(y,Cons(eqf,Nil)))); | bag => return internal("bag_equality",Cons(x,Cons(y,Cons(eqf,Nil)))); | list => return internal("list_equality",Cons(x,Cons(y,Cons(eqf,Nil)))); | _ => return #; #end; }; | _ : is_class(tp1) => return #; | `v : v->variablep() && !get_declaration_binding(v->name())->eq(#) && !get_scoped_type(v)->eq(v) => return generate_equality(get_scoped_type(v),tp2,x,y); | _ => return find_binary_function("eq",tp1,x,y); #end; }; int size_in_bytes_1 ( Expr tp, bool is_raw_data ) { #case tp | scope(`nm) => return size_in_bytes_1(nm,is_raw_data); | void(`tp) => return size_in_bytes_1(tp,is_raw_data); | struct(...r) => { int i = 0; for(; r->consp(); r=r->tl) #case r->hd | bind(_,`etp) => i = add_sizes(i,size_in_bytes_1(etp,is_raw_data)); #end; return i; }; | set(`etp) => if (is_raw_data) return sizeof(raw_sequence); else return sizeof(sm_sequence); | bag(`etp) => if (is_raw_data) return sizeof(raw_sequence); else return sizeof(sm_sequence); | list(`etp) => if (is_raw_data) return sizeof(raw_sequence); else return sizeof(sm_sequence); | union(`nm,`tp,...cases) => { int size = sizeof(type_tag); int i = size; for(list* r=cases; r->consp(); r=r->tl) #case r->hd | case(`ctp,`decl,...tags) => i = add_sizes(i,size_in_bytes_1(ctp,is_raw_data)); #end; return i; }; | enum(...r) => return sizeof(type_tag); | string => if (is_raw_data) return sizeof(raw_string); else return sizeof(sm_string); | integer => return sizeof(long); | long => return sizeof(long); | short => return sizeof(long); | unsigned_long => return sizeof(unsigned long); | unsigned_short => return sizeof(unsigned short); | real => return sizeof(float); | float => return sizeof(float); | double => return sizeof(double); | boolean => return sizeof(bool); | `v : v->variablep() => #case get_declaration_binding(v->name()) | none => return 4; | class(...r) => if (is_raw_data) return sizeof(raw_ref); else return sizeof(sm_ref); | typedef(`tp,_) => return size_in_bytes_1(tp,is_raw_data); | union(...r) => return size_in_bytes_1(#,is_raw_data); | `etp => return 4; #end; | _ => return 4; #end; }; int size_in_bytes ( Expr tp, bool is_raw_data ) { return size_in_bytes_1(tp,is_raw_data); }; Expr expand_type ( Expr tp ) { #case tp | scope(`nm) => return expand_type(nm); | void(`nm) => return expand_type(nm); | _ => return get_scoped_type(tp); | `v : v->variablep() => #case get_declaration_binding(v->name()) | typedef(`tp,_) => return expand_type(tp); | union(...r) => return #; | struct(...r) => return #; | _ => return tp; #end; #end; }; Expr import_value ( Expr e, Expr tp ) { return e; /* #case tp | string => return internal("import_string",Cons(e,Nil)); | scope(`nm) => return import_value(e,expand_type(nm)); | struct(...binds) => { list* nbinds = Nil; Expr nv = new_variable(); for(list* r=binds->reverse(); r->consp(); r=r->tl) #case r->hd | bind(`v,`etp) => nbinds = Cons(#,nbinds); #end; Expr res = translate_expr(#, new binding(nv->name(),tp),new binding(),0); return #; }; | `f(`etp) : collectionp(f) => return internal("import_sequence",Cons(e,Cons(integer(round_size(size_in_bytes(etp))), Cons(#,etp)))>,Nil)))); | `v : v->variablep() && is_class(v) => return internal("import_ref",Cons(e,Nil)); | _ => return e; #end; */ }; Expr get_scoped_binding ( String name ); String scoped_name ( Expr e ); list* get_class_components ( String cname ) { #case get_scoped_binding(cname) | class(`name,scope(...exc),inherits(...inhr),extent(...ext),keys(...keys),...body) => { list* res = Nil; for(; body->consp(); body=body->tl) #case body->hd | attribute(`type,`copies,...vars) => for(; vars->consp(); vars=vars->tl) res = res->cons(#hd),`type)>); | relationship(`tp,`name,...r) => res = res->cons(#); #end; res = res->reverse(); if (exc->consp()) res = get_class_components(scoped_name(#))->append(res); return res; }; | _ => return Nil; #end; }; Expr simple_type_to_key ( Expr e, Expr tp ); Expr translate_key ( Expr relation, list* attributes, Schema sch, Schema stuple, int len ); Expr make_projection ( Expr e, Expr A, Expr tp ) { #case e | struct(...r) => for(; r->consp(); r=r->tl) #case r->hd | bind(`v,`u) : v->eq(A) => return u; #end; return #; | null => return #; | _ => return #; #end; }; /* Make a simple assignment and enforce relationships (update the inverse part of the relationship */ list* make_complete_assignment ( Expr dest, Expr source, Expr tp, Schema sch, Schema stuple, int size ) { Expr x = translate_expr(dest,sch,stuple,size); Expr y = translate_expr(source,sch,stuple,size); if (x->eq(#) || y->eq(#)) return Nil; list* res = Cons(#,Nil); #case x | project(`e,`A,_,_,`C) : C->variablep() && classp(C->name()) => #case get_declaration_binding(A->name(),C->name()) | relationship(set(_),_,inverse(`D,`B)) => #case get_declaration_binding(B->name(),D->name()) | relationship(set(_),_,inverse(_,_)) => { Expr zb = translate_expr(#,sch->extend(#->name(),D),stuple,size); zb = import_value(zb,#); return Cons(#,res); }; | relationship(_,_,inverse(_,_)) => { Expr zb = translate_expr(#,sch->extend(#->name(),D),stuple,size); return Cons(#,res); }; #end; | relationship(_,_,inverse(`D,`B)) => #case get_declaration_binding(B->name(),D->name()) | relationship(set(_),_,inverse(_,_)) => { Expr yb = translate_expr(#,sch,stuple,size); yb = import_value(yb,#); return Cons(#,res); }; | relationship(_,_,inverse(_,_)) => { Expr yb = translate_expr(#,sch,stuple,size); return Cons(#,res); }; #end; | _ => return res; #end; | _ => return res; #end; }; /* Make a composite assignment */ list* make_assignment ( Expr dest, Expr source, Expr tp, Schema sch, Schema stuple, int size ) { #case expand_type(tp) | struct(...comps) => { list* s = Nil; for(list* r=comps; r->consp(); r=r->tl) #case r->hd | bind(`v,`etp) => s = s->append(make_assignment(make_projection(dest,v,etp),make_projection(source,v,etp), etp,sch,stuple,size)); #end; return s; }; | union(_,`ttp,...comps) => { Expr ts = translate_expr(source,sch,stuple,size); Expr res = #; for(list* r=comps; r->consp(); r=r->tl) #case r->hd | case(`etp,`v,...n) => { Expr cond = generate_equality(ttp,ttp,#, translate_expr(n->hd->arguments()->hd,sch,stuple,size)); for(list* s=n->tl; s->consp(); s=s->tl) cond = find_binary_function("or",#,cond, generate_equality(ttp,ttp,#, translate_expr(s->hd->arguments()->hd,sch,stuple,size))); list* k = make_assignment(make_projection(dest,v,etp),make_projection(source,v,etp), etp,sch,stuple,size); if (res->eq(#)) res = #; else res = #; }; #end; return Cons(#,Cons(res,Nil)); }; | _ => return make_complete_assignment(dest,source,tp,sch,stuple,size); #end; }; /* Make an insertion and enforce relationships (update the inverse part of the relationship */ list* make_insertion ( Expr dest, Expr source, Expr tp, Schema sch, Schema stuple, int size ) { Expr x = translate_expr(dest,sch,stuple,size); Expr y = translate_expr(source,sch,stuple,size); if (x->eq(#) || y->eq(#)) return Nil; list* res = Cons(#,Nil); #case x | project(`e,`A,_,_,`C) : C->variablep() && classp(C->name()) => #case get_declaration_binding(A->name(),C->name()) | relationship(set(_),_,inverse(`D,`B)) => #case get_declaration_binding(B->name(),D->name()) | relationship(set(_),_,inverse(_,_)) => { Expr yb = translate_expr(#,sch,stuple,size); yb = import_value(yb,#); return Cons(#,res); }; | relationship(_,_,inverse(_,_)) => { Expr yb = translate_expr(#,sch,stuple,size); return Cons(#,res); }; #end; | _ => return res; #end; | _ => return res; #end; }; /* Make a deletion and enforce relationships (update the inverse part of the relationship */ list* make_deletion ( Expr dest, Expr source, Expr tp, Schema sch, Schema stuple, int size ) { Expr x = translate_expr(dest,sch,stuple,size); Expr y = translate_expr(source,sch,stuple,size); if (x->eq(#) || y->eq(#)) return Nil; list* res = Cons(#,Nil); #case x | project(`e,`A,_,_,`C) : C->variablep() && classp(C->name()) => #case get_declaration_binding(A->name(),C->name()) | relationship(set(_),_,inverse(`D,`B)) => #case get_declaration_binding(B->name(),D->name()) | relationship(set(_),_,inverse(_,_)) => { Expr yb = translate_expr(#,sch,stuple,size); yb = import_value(yb,#); return Cons(#,res); }; | relationship(_,_,inverse(_,_)) => { Expr yb = translate_expr(#,sch,stuple,size); return Cons(#,res); }; #end; | _ => return res; #end; | _ => return res; #end; }; /* Translate an OQL non-bulk operation e into intermediate code; sch is the typechecking schema, stuple is the schema of the input stream variables, size is used in binary operators to index either the left (positive size) or right (negative size) input stream variables */ Expr translate_expr ( Expr e, Schema sch, Schema stuple, int size ) { for(Names s = gbinds->names(); s->consp(); s=s->tl) if (gbinds->find(s->hd)->eq(e)) return translate_expr(variable(s->hd),sch,stuple,size); #case e | struct(...r) : interpreterp => { list* s = Nil; for(; r->consp(); r=r->tl) #case r->hd | bind(`v,`u) => s = s->cons(#); #end; s = s->reverse(); Expr tp = type(e,sch); return #names()->nullp())),...s)>; }; | struct(...r) => { list* s = Nil; Expr nd = new_variable(); Expr tp = type(e,sch); Schema new_sch = sch->extend(nd->name(),tp); Schema tsch = type_to_schema(tp); for(; r->consp(); r=r->tl) #case r->hd | bind(`v,`u) => { Expr etp = expand_type(tsch->find(v->name())); if (true || etp->variablep()) s = s->append(make_assignment(make_projection(nd,v,etp),u,etp,new_sch,stuple,size)); else { Expr nu = translate_expr(u,sch,stuple,size); Expr ns = new_variable(); s = s->append(Cons(#, make_assignment(make_projection(nd,v,etp),ns,etp, new_sch->extend(ns->name(),etp),stuple,size))); }; }; #end; return #; }; | union_construction(`nm,`tag,`attr,`value,`etp,`tp) => { Expr nv = new_variable(); #case expand_type(tp) | union(_,_,...cs) => for(list* r=cs; r->consp(); r=r->tl) #case r->hd | case(`ctp,`a,...s) : a->eq(attr) => { list* s = make_assignment(make_projection(nv,attr,etp),value, ctp,sch->extend(nv->name(),tp),stuple,size); return #; }; #end; #end; return #; }; | `c(`cname,...attributes) : (c->eq(#) || c->eq(#)) => { bool persistentp = c->eq(#); list* body = Nil; Expr ext = estring(get_class_extent(cname)->name()); Expr sz = integer(round_size(initial_offset+size_in_bytes(class_type(cname->name()),true))); Expr obj = (persistentp) ? internal("new_persistent_object",Cons(ext,Cons(sz,Nil))) : internal("new_transient_object",Cons(sz,Nil)); String name = new_name(); Expr vname = variable(name); Schema as = type_to_schema(#); Schema new_sch = sch->extend(vname->name(),cname); int n = initial_offset; for(list* r=get_class_components(cname->name()); r->consp(); r=r->tl) #case r->hd | `f(`nm,`tp,...s) => { if (as->in(nm->name())) { Expr nu = translate_expr(as->find(nm->name()),sch,stuple,size); Expr ns = new_variable(); body = body->append(Cons(#, make_assignment(make_projection(vname,nm,tp),ns, tp,new_sch->extend(ns->name(),tp),stuple,size))); } else #case tp | `g(`etp) : collectionp(g) => body = Cons(#, body); #end; n = add_sizes(n,size_in_bytes(tp,true)); }; #end; /* if persistent object, update indexes ... */ if (persistentp) #case get_declaration_binding(new string("_class_indexes"),cname->name()) | index(...r) => for(; r->consp(); r=r->tl) #case get_declaration_binding(r->hd->name()) | index(_,`unique,...attrs) => { for(list* s=attrs; s->consp(); s=s->tl) if (!member(s->hd,as->names())) odmg_error("indexed attributes must have a value in construction",e); Expr key = translate_key(vname,attrs,new binding(name,cname), new binding(name,cname),-1); body = body->append(Cons(internal("insert_into_index",Cons(estring(r->hd->name()), Cons(key,Cons(vname,Nil)))),Nil)); }; #end; | _ => odmg_error("No class indexes"); #end; return #; }; | project(`x,`a,`rtp) => #case expand_type(type(x,sch)) | `v : v->variablep() && is_class(v) => #case class_type(v->name()) | struct(...r) => { for(int n = initial_offset; r->consp(); r=r->tl) #case r->hd | bind(`w,_) : w->eq(a) => return import_value(#,rtp); | bind(_,`etp) => n = add_sizes(n,size_in_bytes(etp,true)); #end; odmg_error("No such attribute in class",e); }; | _ => odmg_error("Ill-formed class",e); #end; | struct(...args) => { int n = 0; int i = 0; for(list* r=args; r->consp(); r=r->tl, i++) #case r->hd | bind(`v,_) : v->eq(a) => return import_value(#,rtp); | bind(_,`etp) => n = add_sizes(n,size_in_bytes(etp,true)); #end; return #; }; | union(`nm,`etp,...cs) => { int n = sizeof(type_tag); for(list* r=cs; r->consp(); r=r->tl) #case r->hd | case(`tp,`dcl,...cs) : dcl->eq(a) => return import_value(#,rtp); | case(`tp,`dcl,...cs) => n = add_sizes(n,size_in_bytes(tp,true)); #end; odmg_error("No such attribute in union",e); }; | `tp => return import_value(#,rtp); #end; | cases(`e,...cs) => { Expr res = #; #case cs->hd | case(`action,default) => { res = translate_expr(action,sch,stuple,size); cs = cs->tl; }; #end; Expr tp; #case expand_type(type(e,sch)) | union(_,`etp,...r) => tp = etp; | `etp => odmg_error("expected a union value in case statement",e); #end; Expr x = translate_expr(e,sch,stuple,size); for(list* r=cs; r->consp(); r=r->tl) #case r->hd | case(`action,...tags) => { Expr cond = generate_equality(tp,tp,#, translate_expr(tags->hd,new binding,new binding,0)); for(list* s=tags->tl; s->consp(); s=s->tl) cond = find_binary_function("or",#,cond, generate_equality(tp,tp,#, translate_expr(s->hd,new binding,new binding,0))); Expr a = translate_expr(action,sch,stuple,size); if (res->eq(#)) res = a; else res = #; }; #end; return res; }; | and() => return #; | and(`e) => return translate_expr(e,sch,stuple,size); | and(`e,...r) => return find_binary_function("and",#, translate_expr(e,sch,stuple,size), translate_expr(#,sch,stuple,size)); | or() => return #; | or(`e) => return translate_expr(e,sch,stuple,size); | or(`e,...r) => return find_binary_function("or",#, translate_expr(e,sch,stuple,size), translate_expr(#,sch,stuple,size)); | OID(`e) => return translate_expr(e,sch,stuple,size); | like(`e,`pat) => { String npat = pat->info.Estring; char* nc = new (GC) char[npat->length()+1]; strcpy(nc,npat->content()); for(int i = npat->length()-1; i>=0; i--) if (nc[i] == (char) 37) nc[i] = '*'; else if (nc[i] == '_') nc[i] = '?'; return internal("string_match",Cons(estring(new (GC) string(nc)), Cons(translate_expr(e,sch,stuple,size),Nil))); }; | method(`o,`name,...r) : interpreterp => #case expand_type(type(o,sch)) | `tp : tp->variablep() && is_class(tp) => { int loc = find_function(fform("_F_%s_%s_%s",current_module_name->content(), tp->name()->content(),name->name()->content())); list* s = Nil; for(; r->consp(); r=r->tl) s = s->cons(translate_expr(r->hd,sch,stuple,size)); s = Cons(translate_expr(o,sch,stuple,size),s->reverse()); if (loc>0) return #length()+1)),`(integer(loc)),...s)>; else { String nm = new string(*tp->name()+"::_"+*name->name()); return #; #case get_declaration_binding(nm); | none => odmg_error("There is no implementation for method",e); | `body => return #; #end; }; }; #end; | method(`o,`name,...r) => { list* s = Nil; for(; r->consp(); r=r->tl) s = s->cons(translate_expr(r->hd,sch,stuple,size)); s = s->reverse(); return #; }; | call(reduce,`merge,`zero,`x) => #case type(x,sch) | list(`atp) => { Expr btp = type(e,sch); Expr ex = translate_expr(x,sch,stuple,size); return #; }; | _ => return #; #end; | call(`name,...r) => { list* s = Nil; for(; r->consp(); r=r->tl) s = s->cons(translate_expr(r->hd,sch,stuple,size)); s = s->reverse(); return #; }; | pair(`x,`y) => return internal("concat",Cons(translate_expr(x,sch,stuple,size), Cons(translate_expr(y,sch,stuple,size),Nil))); | eq(`x,`y) => return generate_equality(type(x,sch),type(y,sch), translate_expr(x,sch,stuple,size), translate_expr(y,sch,stuple,size)); | neq(`x,`y) => return internal("not",Cons(generate_equality(type(x,sch),type(y,sch), translate_expr(x,sch,stuple,size), translate_expr(y,sch,stuple,size)), Nil)); | if(`pred,`x,`y) => return #; | scope(`e) => return translate_expr(e,sch,stuple,size); | simple_type_to_key(`e,`tp) => return simple_type_to_key(translate_expr(e,sch,stuple,size),tp); | simple_type_to_cmp(`x,`y,`tp) => return internal(fform("%s_cmp",tp->name()->content()), Cons(translate_expr(x,sch,stuple,size),Cons(translate_expr(y,sch,stuple,size),Nil))); | concat_keys(`x,`y) => return internal("concat_keys",Cons(translate_expr(x,sch,stuple,size),Cons(translate_expr(y,sch,stuple,size),Nil))); | merge_cmp(`x,`y) => internal("merge_cmp",Cons(translate_expr(x,sch,stuple,size),Cons(translate_expr(y,sch,stuple,size),Nil))); | vector_access(`u,`n) => { Expr tp = type(e,sch); Expr ret; #case translate_stream_opr(u,sch,stuple) | assign(...r,`x) => ret = #; | `x => ret = import_value(internal("nth_element",Cons(x,Cons(translate_expr(n,sch,stuple,size),Nil))),tp); #end; if (is_class(tp)) return #; else return #; }; | referencep(`x) => #case translate_expr(x,sch,stuple,size) | tuple_reference(`v,`n,_) => return internal("referencep",Cons(v,Cons(n,Nil))); | _ => odmg_error("wrong reference testing",e); #end; | valuep(`x) => #case translate_expr(x,sch,stuple,size) | tuple_value(`v,`n,_) => return internal("valuep",Cons(v,Cons(n,Nil))); | _ => odmg_error("wrong value testing",e); #end; | element(`u) => { Expr tp = type(e,sch); Expr ret; #case translate_stream_opr(u,sch,stuple) | assign(...r,`x) => ret = import_value(#,tp); | `x => ret = import_value(internal("single_element",Cons(x,Nil)),tp); #end; if (is_class(tp)) return #; else return #; }; | first(`u) => { Expr tp = type(e,sch); Expr ret; #case translate_stream_opr(u,sch,stuple) | assign(...r,`x) => ret = import_value(#,tp); | `x => ret = import_value(internal("first_element",Cons(x,Nil)),tp); #end; if (is_class(tp)) return #; else return #; }; | last(`u) => { Expr tp = type(e,sch); Expr ret; #case translate_stream_opr(u,sch,stuple) | assign(...r,`x) => ret = import_value(#,tp); | `x => ret = import_value(internal("last_element",Cons(x,Nil)),tp); #end; if (is_class(tp)) return #; else return #; }; | assign(...binds,`e) => { new_active_stream(); for(list* r = binds; r->consp(); r=r->tl) #case r->hd | bind(`v,`u,`tp) => { sch = sch->extend(v->name(),tp); active_environment->hd = active_environment->hd->extend(v->name(), #length())),`tp)>); }; | bind(`v,`u) => { Expr tp = type(u,sch); sch = sch->extend(v->name(),tp); active_environment->hd = active_environment->hd->extend(v->name(), #length())),`tp)>); }; #end; return close_active_stream(translate_expr(e,sch,stuple,stuple->length())); }; | update(project(`x,`a,`rtp),`source) => { Expr dest = translate_expr(x,sch,stuple,size); Expr sour = translate_expr(source,sch,stuple,size); Expr tp = type(x,sch); Expr nd = new_variable(); Expr ns = new_variable(); Schema nenv = sch->extend(nd->name(),tp)->extend(ns->name(),rtp); list* al = make_assignment(#,ns,rtp,nenv,stuple,size); return #; }; | insert(project(`x,`a,`f(`rtp)),`source) => { Expr sour = translate_expr(source,sch,stuple,size); Expr tp = type(x,sch); Expr ns = new_variable(); Schema nenv = sch->extend(ns->name(),rtp); list* al = make_insertion(#,ns,#<`f(`rtp)>,nenv,stuple,size); return #; }; | delete(project(`x,`a,`f(`rtp)),`source) => { Expr sour = translate_expr(source,sch,stuple,size); Expr tp = type(x,sch); Expr ns = new_variable(); Schema nenv = sch->extend(ns->name(),rtp); list* al = make_deletion(#,ns,#<`f(`rtp)>,nenv,stuple,size); return #; }; | `f(...r) : internal_methods->in(f->name()) => { list* types = Nil; for(list* ar = r; ar->consp(); ar=ar->tl) types = types->cons(type(ar->hd,sch)); types = types->reverse(); int loc = find_internal_method(f->name(),types,sch)->second; if (loc<0) odmg_error("Incompatible types for internal operation",#<`f(...types)>); Expr name = f; Expr tp = #; for(list*>* n = internal_methods->env; n->consp(); n=n->tl) { method_info* m = n->hd->second; if (m->location == loc) { name = variable(m->name); tp = m->parameters->hd; }; }; list* s = Nil; for(; r->consp(); r=r->tl) s = s->cons(translate_expr(r->hd,sch,stuple,size)); s = s->reverse(); return #; }; | `f(...r) : member(f,Nil->cons(#)->cons(#)->cons(#)->cons(#)->cons(#)) => { Expr se = translate_stream_opr(e,sch,stuple,false,false); Expr ne = se; bool streamp = false; #case se | stream(_) => streamp = true; ne = se; | assign(...r,stream(`s)) => streamp = true; ne = #; #end; if (!streamp) return ne; Expr tp = type(e,sch); #case tp | `f(scope(`etp)) => tp = #<`f(`etp)>; #end; Expr res; #case tp | `f(`etp) : collectionp(f) => { Expr size = integer(round_size(size_in_bytes(etp))); Expr eq = generate_equality(etp,etp,#,#); Expr eqf = #; Expr up = (f->eq(#)) ? # : #; if (is_class(etp)) res = internal("collect_references",Cons(ne,Cons(up,Cons(eqf,Nil)))); else res = internal("collect_values",Cons(ne,Cons(size,Cons(up,Cons(eqf,Nil))))); }; #end; #case se | assign(...r,stream(_)) => return #; | _ => return res; #end; }; | `f(...r) => { list* s = Nil; for(; r->consp(); r=r->tl) s = s->cons(translate_expr(r->hd,sch,stuple,size)); s = s->reverse(); return #<`f(...s)>; }; | _ : (e->variablep() && constantp(e)) => { #case get_declaration_binding(e->name()) | constant(scope(`type),`cname,`value) => return translate_expr(value,sch,stuple,size); | constant(`type,`cname,`value) => return translate_expr(value,sch,stuple,size); #end; }; | _ => if (e->variablep()) { if (size < 0) #case type(e,sch) | void(`etp) => return #; | _ => return e; #end; int i = 0; for(Names n = stuple->names(); n->consp(); n=n->tl, i++) if (n->hd->eq(e->name())) { Expr index = integer((i : #; Expr tp = type(e,sch); if (is_class(tp)) return #; else return #; }; #case find_scoped_variable(e->name()) | none => return e; | `tp => return #name()))),`tp)>; #end; } else return e; #end; }; Expr generate_predicate ( Expr pred, Schema sch, Schema stuple, int size ) { Expr pred_code = translate_expr(pred,sch,stuple,size); list* fv = expr_variables(pred); Expr test = #; int i = 0; for(list* s = stuple->names(); s->consp(); s=s->tl, i++) if (member(variable(s->hd),fv)) { Expr vtype = stuple->find(s->hd); Expr v = variable(s->hd); if (is_class(vtype)) if (test->eq(#)) test = #; else test = find_binary_function("and",#,test,#); else if (test->eq(#)) test = #; else test = find_binary_function("and",#,test,#); }; if (test->eq(#)) return pred_code; else return #; }; Expr transl_tuple ( Expr e, Schema sch, Schema stuple, int size ) { Expr nt = internal("null_tuple",Nil); #case e | pair(`x,`y) => return internal("concat_tuples", Cons(transl_tuple(x,sch,stuple,size), Cons(transl_tuple(y,sch,stuple,size),Nil))); | _ : (e->variablep() && stuple->in(e->name())) => { Expr ne = translate_expr(e,sch,stuple,size); Expr at = (is_class(type(e,sch))) ? # : #; #case ne | tuple_reference(`x,`n,...r) => return #; | tuple_value(`x,`n,...r) => return #; | `e => odmg_error("invalid tuple",e); #end; }; | project(`x,...r) : (x->variablep() && stuple->in(x->name())) => { Expr ne = translate_expr(e,sch,stuple,size); Expr at = (is_class(type(e,sch))) ? # : #; #case ne | `f(...m,tuple_reference(`x,`n,...s),...r) => return #; | `f(...m,tuple_value(`x,`n,...s),...r) => return #; | `e => return at; #end; }; | _ => { Expr tp = type(e,sch); Expr ne = translate_expr(e,sch,stuple,size); if (is_class(tp)) return #; else return #; }; #end; }; Expr translate_tuple ( Expr e, Schema sch, Schema stuple, int size ) { return transl_tuple(e,sch,stuple,size); }; Expr type_key ( Expr tp, Expr e, Schema sch, Schema stuple, int len ) { #case tp | integer => return #; | short => return #; | long => return #; | real => return #; | float => return #; | boolean => return #; | string => return #; | scope(`tp) : is_class(tp) => return #; | scope(`v) : v->variablep() => return type_key(get_declaration_binding(v->name()),e,sch,stuple,len); | `f(`etp) : collectionp(f) => { Expr nv = new_variable(); Expr nw = new_variable(); Expr head = type_key(etp,nv,sch->extend(nv->name(),etp),(new binding)->extend(nv->name(),etp),1); return #; }; | struct(...r) => { Expr res = NULL; for(; r->consp(); r=r->tl) #case r->hd | bind(`v,`etp) => { Expr ns = type_key(etp,#,sch,stuple,len); if (res) res = #; else res = ns; }; #end; return res; }; | union(`nm,`etp,...r) => { list* ns = Nil; for(; r->consp(); r=r->tl) #case r->hd | case(`etp,`dcl,...cs) => { list* tags = Nil; for(; cs->consp(); cs=cs->tl) tags = tags->cons(cs->hd->arguments()->hd); Expr ne = type_key(etp,#,sch,stuple,len); ns = Cons(#,ns); }; #end; return #; }; | none => odmg_error("Sorry, I don't know how to handle this type as a key",tp); | `v : is_class(v) => return #; | `v : v->variablep() => return type_key(get_declaration_binding(v->name()),e,sch,stuple,len); | _ => odmg_error("Sorry, I don't know how to handle this type as a key",tp); #end; }; Expr simple_type_to_key ( Expr e, Expr tp ) { #case tp | integer => return internal("int_to_key",Cons(e,Nil)); | short => return internal("int_to_key",Cons(e,Nil)); | long => return internal("int_to_key",Cons(e,Nil)); | real => return internal("real_to_key",Cons(e,Nil)); | float => return internal("real_to_key",Cons(e,Nil)); | boolean => return internal("bool_to_key",Cons(e,Nil)); | string => return internal("string_to_key",Cons(e,Nil)); | scope(`tp) : is_class(tp) => return internal("oid_to_key",Cons(e,Nil)); | `v : is_class(v) => return internal("oid_to_key",Cons(e,Nil)); | _ => odmg_error("Sorry, I don't know how to handle this type as a key",tp); #end; }; Expr map_to_key ( Expr e, Schema sch, Schema stuple, int len ) { #case e | pair(`x,`y) => return internal("concat_keys",Cons(map_to_key(x,sch,stuple,len),Cons(map_to_key(y,sch,stuple,len),Nil))); | _ => return translate_expr(type_key(type(e,sch),e,sch,stuple,len),sch,stuple,len); #end; }; Expr map_to_key_desc ( Expr e, Schema sch, Schema stuple, int len ) { return internal("inverse_string",Cons(map_to_key(e,sch,stuple,len),Nil)); }; /* create a search key */ Expr translate_key ( Expr order, Schema sch, Schema stuple, int len ) { #case order | order(...r) => { Expr res; #case r->hd | desc(`e) => res = map_to_key_desc(e,sch,stuple,len); | `e => res = map_to_key(e,sch,stuple,len); #end; for(r=r->tl; r->consp(); r=r->tl) #case r->hd | desc(`e) => res = internal("concat_keys",Cons(res,Cons(map_to_key_desc(e,sch,stuple,len),Nil))); | `e => res = internal("concat_keys",Cons(res,Cons(map_to_key(e,sch,stuple,len),Nil))); #end; return res; }; | _ => odmg_error("no such order",order); #end; }; Expr type_cmp ( Expr tp, Expr x, Expr y, Schema sch, Schema stuple, int len ) { #case tp | integer => return #; | short => return #; | long => return #; | real => return #; | float => return #; | boolean => return #; | string => return #; | scope(`tp) : is_class(tp) => return #; | scope(`v) : v->variablep() => return type_cmp(get_declaration_binding(v->name()),x,y,sch,stuple,len); | `f(`etp) : collectionp(f) => { Expr nv = new_variable(); Expr nw = new_variable(); return #; }; | struct(...r) => { Expr res = NULL; for(; r->consp(); r=r->tl) #case r->hd | bind(`v,`etp) => { Expr ns = type_cmp(etp,#,#,sch,stuple,len); if (res) res = #; else res = ns; }; #end; return res; }; | union(`nm,`etp,...r) => { list* ns = Nil; for(; r->consp(); r=r->tl) #case r->hd | case(`etp,`dcl,...cs) => { list* tags = Nil; for(; cs->consp(); cs=cs->tl) tags = tags->cons(cs->hd->arguments()->hd); Expr ne = type_cmp(etp,#,#,sch,stuple,len); ns = Cons(#,ns); }; #end; return #; }; | none => odmg_error("Sorry, I don't know how to handle this type as a key",tp); | `v : is_class(v) => return #; | `v : (v->variablep() && !v->eq(get_declaration_binding(v->name()))) => return type_cmp(get_declaration_binding(v->name()),x,y,sch,stuple,len); | _ => odmg_error("Sorry, I don't know how to handle this type as a key",tp); #end; }; /* create a sort comparison */ Expr translate_compare ( Expr xorder, Expr yorder, Schema sch, Schema stuple, int len ) { #case xorder | order(...r) => #case yorder | order(...s) => { Expr res = NULL; for(; r->consp() && s->consp(); r=r->tl, s=s->tl) { Expr nx = r->hd; Expr ny = s->hd; #case r->hd | desc(`e) => nx = e; #end; #case s->hd | desc(`e) => ny = e; #end; Expr tp = type(nx,sch); Expr xx = translate_expr(nx,sch,stuple,stuple->length()); Expr yy = translate_expr(ny,sch,stuple,0); Expr vx = new_variable(); Expr vy = new_variable(); Schema nsch = sch->extend(vx->name(),tp)->extend(vy->name(),tp); Expr ne = type_cmp(tp,vx,vy,nsch,stuple,len); if (!nx->eq(r->hd)) ne = #; Expr nres = subst_expr(vy,yy,subst_expr(vx,xx,translate_expr(ne,nsch,stuple,len))); if (res) res = internal("merge_cmp",Cons(res,Cons(nres,Nil))); else res = nres; }; return res; }; | _ => odmg_error("no such order",yorder); #end; | _ => odmg_error("no such order",xorder); #end; }; Expr translate_geq ( Expr xorder, Expr yorder, Schema sch, Schema stuple, int len ) { Expr cmp = translate_compare(xorder,yorder,sch,stuple,len); return find_binary_function("geq",#,cmp,#<0>); }; Expr translate_key ( Expr relation, list* attributes, Schema sch, Schema stuple, int len ) { list* s = Nil; int i = 0; for(list* r = attributes; r->consp(); r=r->tl, i++) { Expr e = #hd))>; Expr tp = type(e,sch); s = s->cons(#hd),`tp)>); }; s = s->reverse(); return translate_key(#,sch,stuple,len); }; Expr generate_groupby_var_equality ( Expr pat, Schema sch, Schema stuple ) { #case pat | pair(`x,`y) => return find_binary_function("and",#, generate_groupby_var_equality(x,sch,stuple), generate_groupby_var_equality(y,sch,stuple)); | _ => { Expr tp = type(pat,sch); if (is_class(tp)) return #length())), `(translate_expr(pat,sch,stuple,0)))>; return generate_equality(tp,tp, translate_expr(pat,sch,stuple,stuple->length()), translate_expr(pat,sch,stuple,0)); }; #end; }; Expr translate_head_function ( list* groups, Schema sch, Schema stuple ) { Expr res, s; Expr nt = internal("null_tuple",Nil); short i = 0; Schema aggrs = new binding; for(list* r = groups; r->consp(); r=r->tl, i++) #case r->hd | groupby(`m,`w,`hd) => { Expr tp = type(hd,sch); s = translate_expr(hd,sch,stuple,stuple->length()); if (is_class(tp)) s = #; else s = #; list* fv = expr_variables(hd); Expr test = #; int i = 0; for(list* k = stuple->names(); k->consp(); k=k->tl, i++) if (member(variable(k->hd),fv)) { Expr vtype = stuple->find(k->hd); Expr v = variable(k->hd); if (is_class(vtype)) if (test->eq(#)) test = #; else test = find_binary_function("and",#,test,#); else if (test->eq(#)) test = #; else test = find_binary_function("and",#,test,#); }; if (!test->eq(#)) s = #length())),`s,`nt)>; res = (r==groups) ? s : internal("concat_tuples",Cons(res,Cons(s,Nil))); }; #end; return res; }; Expr translate_merge_function ( list* groups, Schema sch, Schema stuple ) { Expr res, s; short i = 0; Expr test = #; Schema aggrs = new binding; for(list* r = groups; r->consp(); r=r->tl, i++) #case r->hd | groupby(`m,`w,`hd) => { Expr tp = type(hd,sch); list* args = Cons(#,Cons(integer(i),Nil)); tp = collectionp(m) ? #<`m(`tp)> : tp; list* d; #case tp | `f(`et) : is_class(et) && collectionp(f) => { d = Cons(#, Cons(#,Nil)); if (test->eq(#)) test = internal("referencep",args); else test = find_binary_function("and",#,test,internal("referencep",args)); }; | `f(`et) : collectionp(f) => { d = Cons(#, Cons(#,Nil)); if (test->eq(#)) test = internal("valuep",args); else test = find_binary_function("and",#,test,internal("valuep",args)); }; | _ => { d = Cons(#, Cons(#,Nil)); if (test->eq(#)) test = internal("valuep",args); else test = find_binary_function("and",#,test,internal("valuep",args)); }; #end; if (!collectionp(m)) s = internal(fform("%s_merge", (tp->eq(#)) ? fform("f%s",m->name()->content()) : m->name()->content()),d); else #case tp | set(`etp) => { Expr eq = generate_equality(etp,etp,#,#); s = internal(fform("%s_merge",m->name()->content()), d->append(Cons(#,Nil))); }; | _ => s = internal(fform("%s_merge",m->name()->content()),d); #end; s = #; res = (r==groups) ? s : internal("concat_tuples",Cons(res,Cons(s,Nil))); }; #end; return #; }; /* group-by uses this zero function to group records */ Expr translate_zero_function ( list* groups, Schema sch ) { Expr res, s; Schema aggrs = new binding; for(list* r = groups; r->consp(); r=r->tl) #case r->hd | groupby(`m,`w,`hd) => { Expr tp = type(hd,sch); if (collectionp(m)) s = #; else s = internal(fform("%s_zero",m->name()->content()),Nil); s = #; res = (r==groups) ? s : internal("concat_tuples",Cons(res,Cons(s,Nil))); }; #end; return res; }; Expr project_var ( Expr e ) { #case e | project(`x,...r) => return project_var(x); | _ => return e; #end; }; Schema merge ( Schema x, Schema y ) { return x->extend(y); }; /* translate a scoped collection variable */ Expr scan_collection_variable ( Expr e, Expr tp, Expr prefix ) { Expr nt; Expr etp; #case tp | `f(scope(`tp)) : is_class(tp) => { nt = #; etp = tp; }; | `f(scope(`tp)) => { nt = #; etp = tp; }; | `f(`tp) : is_class(tp) => { nt = #; etp = tp; }; | `f(`tp) => { nt = #; etp = tp; }; #end; Expr nv = variable(new_name()); Expr fn = (is_class(etp)) ? internal("access_collection_ref",Cons(#,Cons(#,Nil))) : internal("access_collection_value",Cons(nv,Cons(#,Nil))); Expr res = internal((interpreterp ? "nested_collection_stream_with_closure" : "nested_collection_stream"), Cons(#,Cons(prefix,Nil))); return #; }; Expr translate_opr ( Expr e, Schema &sch, Schema &stuple, Expr stream_prefix, bool materializep, bool streamp ) { Expr res; #case e | ZERO(`m,...r) => res = #; | UNIT(_,`x) => { Expr ne = translate_expr(x,sch,stuple,stuple->length()); #case type(x,sch) | `v : v->variablep() && classp(v->name()) => return new_stream(internal("residual_ref_stream",Cons(ne,Nil)),materializep); | _ => return new_stream(internal("residual_value_stream",Cons(ne,Nil)),materializep); #end; }; | MERGE(_,`x,`y) => { Schema sx = stuple; Expr nx = translate_opr(x,sch,stuple,stream_prefix); Expr ny = translate_opr(y,sch,sx,stream_prefix); res = #; }; | TABLE_SCAN( `M, `table, `v, `pred ) => { Expr tp = type(table,sch); #case tp | `f(`Aclass) : Aclass->variablep() && collectionp(f) => stuple = stuple->extend(new binding(v->name(),class_name(Aclass))); | `f(`etp) : collectionp(f) => stuple = stuple->extend(new binding(v->name(),etp)); #end; sch = sch->extend(stuple); int len = stuple->length(); if (table->variablep() && extentp(table)) { Expr tbl = estring(find_in_module(table)->name()); Expr strn = new_stream(internal("materialized_stream",Cons(tbl,Cons(stream_prefix,Nil))),false); Expr fpred = translate_expr(pred,sch,stuple,len); res = #; } else { Expr ne = translate_opr(table,sch,stuple,stream_prefix); #case ne | stream(_) => res = ne; | _ => Expr prefix = subst_expr(#,#,stream_prefix); res = new_stream(internal("suspended_stream", Cons(scan_collection_variable(ne,tp,prefix),Nil)), materializep); #end; #case pred | and() => return res; | _ => { Expr fpred = translate_expr(pred,sch,stuple,len); res = #; }; #end; }; }; | INDEX_SCAN( `M, `table, `v, `pred, `index, `low, `high ) => { #case type(table,sch) | `f(`Aclass) : Aclass->variablep() && collectionp(f) => stuple = stuple->extend(new binding(v->name(),class_name(Aclass))); | `f(`tp) : collectionp(f) => stuple = stuple->extend(new binding(v->name(),tp)); #end; sch = sch->extend(stuple); int len = stuple->length(); Expr vlow = (low->eq(#)) ? # : map_to_key(low,sch,stuple,len); Expr vhigh = (high->eq(#)) ? # : map_to_key(high,sch,stuple,len); Expr strn = new_stream(internal("indexed_stream", Cons(internal("find_index", Cons(estring(index->name()),Nil)), Cons(#, Cons(vlow,Cons(vhigh,Cons(stream_prefix,Nil)))))), false); Expr fpred = translate_expr(pred,sch,stuple,len); res = #; }; | NESTED_LOOP( `M, `x, `y, `pred, `outer ) => { Schema sx = stuple; Schema sy = stuple; Expr nx = translate_opr(x,sch,sx,stream_prefix); Expr ny = translate_opr(y,sch,sy,stream_prefix,true); stuple = merge(sx,sy); sch = sch->extend(stuple); Expr fpred = generate_predicate(pred,sch,stuple,sx->length()); Expr outers = (outer->eq(#)) ? # : #; Expr fkeep = #; if (!outer->eq(#)) fkeep = generate_groupby_var_equality(outer,sch,stuple); res = #; }; | BLOCK_NESTED_LOOP( `M, `x, `y, `pred, `outer ) => { Schema sx = stuple; Schema sy = stuple; Expr nx = translate_opr(x,sch,sx,stream_prefix); Expr ny = translate_opr(y,sch,sy,stream_prefix,true); stuple = merge(sx,sy); Expr rx = new_stream(internal("residual_buffer",Cons(#<1000>,Cons(stream_prefix,Nil))),false); sch = sch->extend(stuple); Expr fpred = generate_predicate(pred,sch,stuple,sx->length()); Expr outers = (outer->eq(#)) ? # : #; Expr fkeep = #; if (!outer->eq(#)) fkeep = generate_groupby_var_equality(outer,sch,stuple); res = #; }; | MAP( `M, `x, `var, `pred, `outer, `path ) => { Expr nx = translate_opr(x,sch,stuple,stream_prefix); Expr fmap = translate_tuple(path,sch,stuple,stuple->length()); stuple = stuple->extend(new binding(var->name(),type(path,sch))); sch = sch->extend(stuple); Expr fpred = generate_predicate(pred,sch,stuple,stuple->length()); Expr outers = (outer->eq(#)) ? # : #; Expr fkeep = #; if (!outer->eq(#)) fkeep = generate_groupby_var_equality(outer,sch,stuple); res = #; }; | INDEXED_LOOP( `M, `x, INDEX_SCAN( _, `table, `v, ...r ), `pred, `outer, `index, `key ) => { Expr nx = translate_opr(x,sch,stuple,stream_prefix); int len = stuple->length(); Expr strn = new_stream(internal("indexed_stream", Cons(internal("find_index", Cons(estring(index->name()),Nil)), Cons(#,Cons(#,Cons(#, Cons(stream_prefix,Nil)))))), false); #case type(table,sch) | `f(`Aclass) : Aclass->variablep() && collectionp(f) => stuple = stuple->extend(new binding(v->name(),class_name(Aclass))); | `f(`tp) : collectionp(f) => stuple = stuple->extend(new binding(v->name(),tp)); #end; sch = sch->extend(stuple); Expr fpred = generate_predicate(pred,sch,stuple,len); Expr outers = (outer->eq(#)) ? # : #; Expr fkeep = #; if (!outer->eq(#)) fkeep = generate_groupby_var_equality(outer,sch,stuple); Expr fkey = translate_key(key,sch,stuple,stuple->length()); res = #; }; | MERGE_JOIN( `M, `x, `y, `pred, `left_key, `xorder, `yorder ) => { Schema sx = stuple; Schema sy = stuple; Expr nx = translate_opr(x,sch,sx,stream_prefix); Expr ny = translate_opr(y,sch,sy,stream_prefix); stuple = merge(sx,sy); sch = sch->extend(stuple); Expr fpred = generate_predicate(pred,sch,stuple,sx->length()); Expr geq = translate_geq(xorder,yorder,sch,stuple,sx->length()); res = #; }; | UNNEST( `M, `x, `v, `path, `pred, `outer ) => { Expr nx = translate_opr(x,sch,stuple,stream_prefix); Expr outers = (outer->eq(#)) ? # : #; Expr fkeep = #; if (!outer->eq(#)) fkeep = generate_groupby_var_equality(outer,sch,stuple); Expr pv = project_var(path); Expr fnullp = (pv->variablep()) ? internal("null_element", Cons(translate_expr(pv,sch,stuple,stuple->length()),Nil)) : #; Expr ctp = type(path,sch); Expr tp = ctp->arguments()->hd; #case tp | scope(`etp) => tp = etp; #end; Expr fpath = (is_class(tp)) ? translate_tuple(path,sch,stuple,stuple->length()) : translate_expr(path,sch,stuple,stuple->length()); stuple = stuple->extend((new binding)->extend(v->name(),tp)); sch = sch->extend(stuple); Expr fpred = generate_predicate(pred,sch,stuple,stuple->length()); Expr vpath = new_variable(); Expr fn = (is_class(tp)) ? internal("access_collection_ref",Cons(vpath,Cons(#,Nil))) : internal("access_collection_value",Cons(vpath,Cons(#,Nil))); Expr ftest = find_binary_function("eq",#,#,#<0>); Expr btp = (is_class(tp)) ? # : ctp; res = #; }; | NEST( `M, `x, `v, `head, `vars, `bpred, `apred ) => { Expr ne = e; list* s = Nil; list* bpreds = Nil; list* apreds = Nil; list* fnullps = Nil; bool stop = false; do { #case ne | NEST( `m, `u, `w, `hd, `vars2, and(...r), and(...l) ) : vars->eq(vars2) => { s = s->cons(#); bpreds = bpreds->append(r); apreds = apreds->append(l); ne = u; }; | _ => stop = true; #end; } while (!stop); Expr nx = translate_opr(ne,sch,stuple,stream_prefix); gbinds = new binding; Expr fkey = translate_tuple(vars,sch,stuple,stuple->length()); Expr fhead = translate_head_function(s,sch,stuple); Schema new_stuple = new binding; list* pvars = pattern_variables(vars); for(list* r = pvars->reverse(); r->consp(); r=r->tl) if (r->hd->variablep()) { if (!new_stuple->in(r->hd->name())) new_stuple = new_stuple->extend(r->hd->name(),sch->find(r->hd->name())); } else { Expr tp = type(r->hd,sch); String nv = new_name(); new_stuple = new_stuple->extend(nv,tp); gvars = Cons(Pair(r->hd,tp),gvars); gbinds = gbinds->extend(nv,r->hd); }; #case type(x,sch) | `f(`tp) : collectionp(f) => for(Names r = type_to_schema(tp)->names(); r->consp(); r=r->tl) { Expr v = variable(r->hd); if (!member(v,pvars) && sch->in(r->hd)) { if (is_class(sch->find(r->hd))) fnullps = fnullps->cons(#); else fnullps = fnullps->cons(#); }; }; #end; Expr fnullp = translate_expr(#,sch,stuple,stuple->length()); sch = sch->extend(new_stuple); Expr feq = generate_groupby_var_equality(vars,sch,new_stuple); for(list* r = s; r->consp(); r=r->tl) #case r->hd | groupby(`m,`w,`hd) => { Expr tp = type(hd,sch); tp = collectionp(m) ? #<`m(`tp)> : tp; new_stuple = new_stuple->extend(new binding(w->name(),tp)); } #end; Expr fmerge = translate_merge_function(s,sch,stuple); Expr fzero = translate_zero_function(s,sch); Expr fbpred = generate_predicate(#,sch,stuple,stuple->length()); stuple = new_stuple; sch = sch->extend(stuple); Expr fapred = generate_predicate(#,sch,stuple,stuple->length()); res = #; }; | REDUCE( `M, `x, `v, `head, `pred ) : collectionp(M) => { Expr nx = translate_opr(x,sch,stuple,stream_prefix); int size = stuple->length(); Expr fpred = generate_predicate(pred,sch,stuple,size); Expr fhead = translate_tuple(head,sch,stuple,size); stuple = stuple->extend(new binding(v->name(),type(head,sch))); sch = sch->extend(stuple); res = #; }; | REDUCE( `M, ...r ) : !collectionp(M) => { Expr nx = translate_opr(#,sch,stuple,stream_prefix); Expr tp = type(e,sch); const char* m = (tp->eq(#)) ? fform("f%s",M->name()->content()) : M->name()->content(); list* d = Cons(nx,Cons(internal(fform("%s_zero",m),Nil), Cons(#,Cons(#,Nil)))))>,Nil))); return internal("aggregate",d); }; | SORT( `x, `order ) => { Expr nx = translate_opr(x,sch,stuple,stream_prefix); Expr fcmp = translate_compare(order,order,sch,stuple,stuple->length()); Expr strn = new_stream(internal("sort_stream",Cons(nx,Cons(#,Nil))),false); res = #; }; | if(`pred,`x,`y) : streamp => { sch = new binding; Expr npred = translate_expr(pred,sch,stuple,stuple->length()); Expr nx = translate_opr(x,sch,stuple,stream_prefix); Expr ny = translate_opr(y,sch,stuple,stream_prefix); return #; }; | assign(...binds,`e) => { new_active_stream(); for(list* r = binds; r->consp(); r=r->tl) #case r->hd | bind(`v,`u,`tp) => { sch = sch->extend(v->name(),tp); active_environment->hd = active_environment->hd->extend(v->name(), #length())),`tp)>); }; | bind(`v,`u) => { Expr tp = type(u,sch); sch = sch->extend(v->name(),tp); active_environment->hd = active_environment->hd->extend(v->name(), #length())),`tp)>); }; #end; return close_active_stream(translate_opr(e,sch,stuple,stream_prefix)); }; | _ : streamp => { Expr ne = translate_expr(e,sch,stuple,stuple->length()); #case ne | stream(_) => return ne; | _ => { Expr tp = type(e,sch); res = scan_collection_variable(ne,tp,stream_prefix); return new_stream(res,false); }; #end; }; | _ => { //sch = new binding; Expr ne = translate_expr(e,sch,stuple,stuple->length()); return ne; }; #end; #case res | `f(...r) => res = internal(f->name()->content(),r); #end; return new_stream(internal("suspended_stream",Cons(#,Nil)),materializep); }; Expr translate_query ( Expr e, Schema &sch, Schema &stuple, bool streamp = true ) { Expr se = translate_stream_opr(e,sch,stuple,false,streamp); Expr ne = se; streamp = false; #case se | stream(_) => streamp = true; ne = se; | assign(...r,stream(`s)) => streamp = true; ne = #; #end; if (!streamp) return ne; Expr res; Expr tp = type(e,stuple); #case tp | `f(`etp) : collectionp(f) => { Expr size = integer(round_size(size_in_bytes(etp))); Expr eq = generate_equality(etp,etp,#,#); Expr eqf = #; Expr up = (f->eq(#)) ? # : #; if (is_class(etp)) res = internal("collect_references",Cons(ne,Cons(up,Cons(eqf,Nil)))); else res = internal("collect_values",Cons(ne,Cons(size,Cons(up,Cons(eqf,Nil))))); }; | bag(_) => if (bulk_operation(e)) res = internal("materialize_bag",Cons(ne,Nil)); else res = ne; | list(_) => if (bulk_operation(e)) res = internal("materialize_list",Cons(ne,Nil)); else res = ne; | set(void(`etp)) => if (bulk_operation(e)) res = internal("materialize_set",Cons(ne, Cons(#,#)))>,Nil))); else res = ne; | set(`etp) => if (bulk_operation(e)) res = internal("materialize_set",Cons(ne, Cons(#,#)))>,Nil))); else res = ne; | _ => res = ne; #end; #case se | assign(...r,stream(_)) => return #; | _ => return res; #end; };