/********************************************************************************* * * Processing of ODMG ODL 2.0 * Copyright (c) 1999-2003 by Leonidas Fegaras, the University of Texas at * Arlington. All rights reserved. * Programmer: Leonidas Fegaras * Date: 9/28/98 * ********************************************************************************/ #ifdef LDB_SERVER #include #else #include # endif #include #include #include "odl.h" extern ofstream fout; extern char* schema_include_file; // the pathname of the current module static Path current_module_path; static bool in_method = false; // list of current ODL declarations static list* current_declarations = Nil; static Pool user_catalog; static sm_index user_catalog_index; static Pool user_database; static sm_index user_database_index; void fatal_odmg_error ( const char* s, Expr x ) { if (x->eq(#)) eout << "*** LDB error: " << s << endl; else eout << "*** LDB error: " << s << ": " << x << endl; throw odmg_error_class(eout.str()); }; void odmg_error ( const char* s ) { fatal_odmg_error(s,#); }; void odmg_error ( const char* s, Expr e) { fatal_odmg_error(s,e); }; void odmg_error ( const char* s, String e) { fatal_odmg_error(s,variable(e)); }; Path::Path () { context = new list; }; void Path::new_context ( String name ) { context = Cons(name,context); }; void Path::exit_context () { if (context->consp()) context = context->tl; }; String Path::local ( String name ) { String res = name; for(list* r = context; r->consp(); r=r->tl) res = new string(*r->hd + "::" + *res); return res; }; String Path::clocal ( String name ) { String res = name; for(list* r = context; r->consp(); r=r->tl) res = new string(*r->hd + "_" + *res); return res; }; list* Path::local_in_each_module ( String name ) { list* res = new list; String nm = new string(""); for(list* r = context->reverse(); r->consp(); r=r->tl) { nm = new string(*nm + *r->hd + "::"); res = Cons(new string(*nm + *name),res); }; return res; }; void initialize_current_module () { current_module_path = Path(); }; void set_current_module ( String name ) { current_module_path.new_context(name); }; String get_local_in_path ( String name ) { return current_module_path.local(name); }; Ref create_user ( sm_string username, sm_string password ) { Pool user_pool; sm_index user_index; sm_string user_index_ref; sm_string user_pool_ref; if (!ldb_sm->find_declaration(sm_string("user_pool"),user_pool_ref) || !ldb_sm->find_declaration(sm_string("user_index"),user_index_ref)) { cout << "Creating the User Database.\n"; user_pool = Pool(false); user_index = sm_index(false,true,sm_string("b*100")); oid_t up_id = user_pool.oid(); oid_t ui_id = user_index.oid(); ldb_sm->add_declaration(sm_string("user_pool"),sm_string((char*) &up_id,sizeof(oid_t))); ldb_sm->add_declaration(sm_string("user_index"),sm_string((char*) &ui_id,sizeof(oid_t))); } else { user_pool = Pool(*(oid_t*) user_pool_ref.content()); user_index = sm_index(*(oid_t*) user_index_ref.content(),false); }; raw_ref uu; if (user_index.find(username,uu)) odmg_error(fform("User %s already exists",username.scontent())); cout << "Creating user '" << username << "'.\n"; Ref u = user_pool.new_record(); user_index.add(username,u.oid()); u->name = username; u->password = password; user_catalog = Pool(false); user_catalog_index = sm_index(false,false,sm_string("b*100")); user_database = Pool(false); user_database_index = sm_index(false,true,sm_string("b*100")); u->catalog = user_catalog.oid(); u->catalog_index = user_catalog_index.oid(); u->user_database = user_database.oid(); u->user_database_index = user_database_index.oid(); return u; }; Ref login ( sm_string username, sm_string password ) { Pool user_pool; sm_index user_index; sm_string user_index_ref; sm_string user_pool_ref; if (!ldb_sm->find_declaration(sm_string("user_pool"),user_pool_ref) || !ldb_sm->find_declaration(sm_string("user_index"),user_index_ref)) odmg_error("The User Database does not exist"); user_pool = Pool(*(oid_t*) user_pool_ref.content()); user_index = sm_index(*(oid_t*) user_index_ref.content(),false); raw_ref uu; if (!user_index.find(username,uu)) odmg_error(fform("User %s does not exist",username.scontent())); Ref u(uu); if (sm_string(u->password) != password) odmg_error("Wrong password"); user_catalog = Pool(u->catalog); user_catalog_index = sm_index(u->catalog_index,false); user_database = Pool(u->user_database); user_database_index = sm_index(u->user_database_index,false); return u; }; void print_all_declarations () { Ref< Catalog > decl; PoolScan scan(user_catalog); while ( scan.next(decl) ) { cout << decl.oid() << " " << sm_string(decl->name); cout << " " << decl->tag << " " << get_declaration_binding(decl) << endl; }; scan.close(); }; list< Ref >* get_declarations ( String dname ) { list< Ref >* dcls = new list< Ref >; sm_string name = sm_string(dname->content()); sm_string key; raw_ref decl; sm_index_scan scan(user_catalog_index,name,name); while(scan.next(key,decl)) dcls = dcls->cons(Ref(decl)); scan.close(); return dcls; }; Ref get_declaration ( String dname ) { list< Ref >* dcls = get_declarations(dname); if (dcls->nullp() || dcls->tl->consp()) return sm_ref(); return dcls->hd; }; Expr get_declaration_binding ( Ref dcl ) { if (dcl.valid()) return read_expr(sm_string(dcl->binding).scontent()); else return #; }; Expr get_path_binding ( String path ) { for(list* r = current_declarations; r->consp(); r=r->tl) #case r->hd | declaration(`nm,`binding) : nm->name()->eq(path) => return binding; #end; Ref dcl = get_declaration(path); Expr binding = (dcl.valid()) ? read_expr(sm_string(dcl->binding).scontent()) : #; current_declarations = current_declarations->cons(#); return binding; }; Expr get_scoped_binding ( String name ) { #case get_path_binding(name) | none => ; | `e => return e; #end; for(list* r = current_module_path.local_in_each_module(name); r->consp(); r=r->tl) #case get_path_binding(r->hd) | none => ; | `e => return e; #end; return #; }; Expr get_declaration_binding ( String dname ) { return get_scoped_binding(dname); }; Expr get_declaration_binding ( String dname, String cname ) { return get_scoped_binding(new string(*cname+"::"+*dname)); }; String expr_to_string ( Expr e ) { eout.reset(); e->write(eout); eout.flush(); return new string(eout.str()); }; Ref store_declaration ( String name, const type_tag tag, Expr binding, bool duplicate_error ) { list< Ref >* dcls = get_declarations(name); Ref ref; if (dcls->consp() && duplicate_error && !(dcls->tl->nullp() && dcls->hd->tag == forward_dcl)) odmg_error("duplicate declaration",name); else if (dcls->consp()) if (dcls->tl->nullp()) { user_catalog_index.remove(sm_string(name->content()),dcls->hd.oid()); user_catalog.remove(dcls->hd); } else odmg_error("ambiguous declaration",name); ref = user_catalog.new_record(); user_catalog_index.add(sm_string(name->content()),ref.oid()); ref->name = name->content(); ref->tag = tag; ref->binding = sm_string(expr_to_string(binding)->content()); ref->module = sm_string(current_module_path.local(new string(""))->content()); sm_string bs = sm_string(expr_to_string(binding)->content()); if (sm_string(ref->binding) != bs) ref->binding = bs; current_declarations = current_declarations->cons(#); ldb_sm->commit_transaction(); ldb_sm->begin_transaction(); return ref; }; Ref store_local_declaration ( String name, const type_tag tag, Expr binding, bool duplicate_error = true ) { return store_declaration(current_module_path.local(name),tag,binding,duplicate_error); }; Ref get_data_entry ( String pathname ) { raw_ref ref; if (user_database_index.find(sm_string(pathname->content()),ref)) return Ref(ref); else return sm_ref(); }; Ref new_extent ( String pathname, String classname ) { sm_file pool(false); Ref ref = user_database.new_record(); ref->tag = extent_entry; ref->name = sm_string(pathname->content()); ref->class_name = sm_string(classname->content()); ref->module = sm_string(current_module_path.local(new string(""))->content()); ref->cardinality = 0; ref->size = 0; ref->oid = pool.oid(); user_database_index.add(sm_string(ref->name),ref.oid()); return ref; }; Ref new_index ( String pathname, String classname, bool uniquep ) { sm_index ind(false,uniquep,sm_string("b*100")); Ref ref = user_database.new_record(); ref->tag = index_entry; ref->name = sm_string(pathname->content()); ref->class_name = sm_string(classname->content()); ref->module = sm_string(current_module_path.local(new string(""))->content()); ref->cardinality = 0; ref->size = 0; ref->oid = ind.oid(); ref->uniquep = uniquep; user_database_index.add(sm_string(ref->name),ref.oid()); return ref; }; list* class_keys ( Expr e ) { #case e | class(`cname,scope(...es),inherits(...inhr),extent(...ext),keys(...keys),...body) => if (es->nullp()) return keys; else return keys->append(class_keys(get_scoped_binding(es->hd->name()))); | _ => return Nil; #end; }; void import_module ( String module_name ) { cout << "Importing module " << module_name << endl; sm_string key; raw_ref ref; sm_string low = sm_string(module_name->content()); sm_string high = low + ":_"; sm_index_scan scan(user_catalog_index,low,high); while(scan.next(key,ref)) { Ref cref(ref); String name = new string(sm_string(cref->name).scontent()); user_catalog_index.add(sm_string(name->content()),ref); Expr decl = get_declaration_binding(cref); #case decl | class(`cname,scope(...es),inherits(...inhr),extent(...ext),keys(...keys),...body) => { sm_file f(false); int i = 0; for(list* r = class_keys(decl); r->consp(); r=r->tl, i++) { sm_index(true,true,sm_string("i4")); }; }; #end; current_declarations = current_declarations->cons(#); }; scan.close(); }; String scoped_name ( Expr e ) { #case e | scope(...r,`x) => return x->name(); | _ => odmg_error("Illegal scope",e); #end; }; void print_scoped_name ( Expr e ) { #case e | scope(...ns) => { fout << ns->hd; for(list* r = ns->tl; r->consp(); r=r->tl) fout << "::" << r->hd; }; | _ => fout << e; #end; }; void print_inherits ( list* inhs ) { if (inhs->consp()) { fout << ": "; for(list* r = inhs; r->consp(); r=r->tl) { fout << "public "; print_scoped_name(r->hd); if (r->tl->consp()) fout << ", "; }; }; }; void print_expr (Expr e); void print_declarators ( list* dcls ) { for(list* r = dcls; r->consp(); r=r->tl) { #case r->hd | array(`v,`n) => { fout << v << "["; print_expr(n); fout << "]"; }; | array(`v,...s) => odmg_error("can't handle arrays of multiple dimensions",r->hd); | `e => fout << e; #end; if (r->tl->consp()) fout << ", "; }; }; bool classp ( String name ) { for(list* r = Cons(name,current_module_path.local_in_each_module(name)); r->consp(); r=r->tl) for(list< Ref >* dcls = get_declarations(r->hd); dcls->consp(); dcls=dcls->tl) if (dcls->hd->tag == class_dcl || dcls->hd->tag == forward_dcl) return true; return false; }; bool member ( String s, list* r ) { if (r->consp()) return s->eq(r->hd) || member(s,r->tl); else return false; }; bool needs_alloc ( Expr tp ) { #case tp | set(_) => return true; | bag(_) => return true; | list(_) => return true; | struct(...r) => return true; | scope(`nm) : nm->variablep() => #case get_scoped_binding(nm->name()) | typedef(`type,_) => return needs_alloc(type); | _ => return false; #end; | _ => return false; #end; }; void print_type ( Expr e ); void print_alloc ( Expr name, Expr type ) { #case type | scope(`nm) : nm->variablep() => #case get_scoped_binding(nm->name()) | typedef(`tp,_) => print_alloc(name,tp); | _ => fout << name << "._alloc(); "; #end; | `f(`etp) => { fout << name << ".element_size = sizeof("; print_type(etp); fout << "); "; }; | _ => fout << name << "._alloc(); "; #end; }; void create_alloc ( list* decls ) { return; fout << "void _alloc () { "; for(list* r=decls; r->consp(); r=r->tl) #case r->hd | attribute(`tp,none,...vars) : needs_alloc(tp) => print_alloc(vars->hd,tp); | attribute(`tp,...vars) : needs_alloc(tp) => print_alloc(vars->hd,tp); | relationship(`tp,`rname,...r) : needs_alloc(tp) => print_alloc(rname,tp); #end; fout << "}; "; }; void print_type ( Expr e ) { #case e | struct(`name,...decls) => { fout << "struct " << name << " { "; for(list* r=decls; r->consp(); r=r->tl) #case r->hd | attribute(`tp,...dcls) => { print_type(tp); fout << " "; print_declarators(dcls); fout << "; "; }; #end; create_alloc(decls->reverse()); fout << "}"; }; | enum(`name,...vars) => { fout << "enum " << name << " { " << vars->hd; for(list* r = vars->tl; r->consp(); r=r->tl) fout << ", " << r->hd; fout << " }"; }; | union(`name,`tp,...cases) => { fout << "struct " << name << " { "; print_type(tp); fout << " tag; struct { "; for(list* r = cases; r->consp(); r=r->tl) #case r->hd | case(`tp,`dcl,...cs) => { print_type(tp); fout << " "; print_declarators(Cons(dcl,Nil)); fout << "; "; }; #end; fout << "} value; }"; }; | scope(`x) => { if (classp(x->name())) if (in_method) { fout << "Ref<"; print_scoped_name(e); fout << ">"; } else fout << "raw_ref"; else print_scoped_name(e); }; | `f(`tp) => if (in_method) { fout << "Sequence<"; print_type(tp); fout << " >"; } else fout << "raw_sequence"; | array(`tp,none) => { fout << "Sequence< "; print_type(tp); fout << " >"; }; | array(`tp,`n) => { fout << "Vector< "; print_type(tp); fout << "," << n << " >"; }; | set(`e) => { fout << "Set< "; print_type(e); fout << " >"; }; | bag(`e) => { fout << "Bag< "; print_type(e); fout << " >"; }; | list(`e) => { fout << "Sequence< "; print_type(e); fout << " >"; }; | unsigned_long => fout << "unsigned long"; | unsigned_short => fout << "unsigned short"; | integer => fout << "int"; | string => if (in_method) fout << "sm_string"; else fout << "raw_string"; | _ : e->variablep() => if (classp(e->name())) if (in_method) { fout << "Ref<"; print_scoped_name(e); fout << ">"; } else fout << "raw_ref"; else fout << e; | _ => odmg_error("I don't know how to handle the type",e); #end; }; list* get_union_tags ( Expr type ) { #case type | `e : (e->eq(#) || e->eq(#) || e->eq(#) || e->eq(#) || e->eq(#) || e->eq(#) || e->eq(#)) => return Nil; | scope(`tp) => return get_union_tags(tp); | enum(`ename,...tags) => return tags; | _ : type->variablep() => #case get_scoped_binding(type->name()) | typedef(`tp,`nm) => return get_union_tags(tp); | enum(`ename,...tags) => return tags; | _ => odmg_error("invalid union tag type",type); #end; | _ => odmg_error("invalid union tag type",type); #end; }; void check_type ( Expr e ) { #case e | struct(`name,...r) => { list* ns = Nil; for(; r->consp(); r=r->tl) #case r->hd | attribute(`tp,...vars) => { check_type(tp); for(; vars->consp(); vars=vars->tl) if (member(vars->hd,ns)) odmg_error("duplicate attribute name",vars->hd); else ns = ns->cons(vars->hd); }; #end; }; | enum(`name,...vars) => { list* ns = Nil; for(; vars->consp(); vars=vars->tl) if (member(vars->hd,ns)) odmg_error("duplicate enumeration tag",vars->hd); else ns = ns->cons(vars->hd); }; | union(`name,`tp,...cases) => { list* ns = Nil; list* ts = Nil; check_type(tp); list* utags = get_union_tags(tp); for(list* r = cases; r->consp(); r=r->tl) #case r->hd | case(`ctp,`decl,...tags) => { check_type(ctp); if (member(decl,ns)) odmg_error("duplicate union case name",decl); else ns = ns->cons(decl); for(; tags->consp(); tags=tags->tl) { Expr tag = tags->hd; #case tag | scope(`v) => tag = v; #end; if (utags->nullp() && !tag->eq(#) && !tag->integerp()) odmg_error("expected an integer case tag",tag); else if (utags->consp() && !tag->eq(#) && !member(tag,utags)) odmg_error("invalid case tag",tag); else if (member(tag,ts)) odmg_error("duplicate union case tag",tag); else ts = ts->cons(tag); }; }; #end; }; | scope(`tp) => check_type(tp); | array(`tp,_) => check_type(tp); | `f(`tp) => check_type(tp); | _ : e->variablep() => if (e->eq(#) || e->eq(#) || e->eq(#) || e->eq(#) || e->eq(#) || e->eq(#) || e->eq(#) || e->eq(#)) ; else if (e->eq(#) || e->eq(#