implement PgCatalogue; include "sys.m"; sys: Sys; include "bufio.m"; bufio: Bufio; Iobuf: import bufio; include "daytime.m"; daytime : Daytime; include "pgbase.m"; pgbase :PgBase; Connection : import pgbase; include "pg_catalogue.m"; disconnect(c : ref Connection) { c.disconnect(); } new_connection(ip, port, user, password, database, options, parameters: string) : ref Connection { pgbase = load PgBase "pgbase.dis"; c := ref Connection; c.user = user; c.password = password; c.database = database; if(c.connect(ip, port, options, parameters)) return c; raise "connection failed"; } new_catalogue(conn : ref Connection) : ref Catalogue { c := ref Catalogue; c.conn = conn; return c; } Catalogue.sync(c : self ref Catalogue) : int { if(daytime == nil) daytime = load Daytime Daytime->PATH; c.err_chan <- = "sync"; c.fill_procs(); c.fill_types(); c.fill_users(); c.last_sync = daytime->now(); return c.last_sync; } Catalogue.drop_proc(c : self ref Catalogue, id : int) : int { c.err_chan <- = "drop_proc"; return (c != nil && id != -1); } Catalogue.user_sysid(c : self ref Catalogue, username : string) : (string,int) { if(c.conn.parse("", "SELECT usesysid FROM pg_user WHERE usename=$1;", nil)) { recordset := c.conn.execute("", "", nil, array[1] of {array of byte username}, array[1] of {0}, 0); if(recordset == nil) return ("Not Found", 0); return (nil, int string recordset.rows[0][0]); } return ("Database choked in user_sysid", 0); } Catalogue.print_procs_full(c : self ref Catalogue, user_sysid: int) { if(sys == nil) sys = load Sys Sys->PATH; if(c.procs == nil && c.fill_procs() == 0) { sys->print("No Procs found\n"); return; } for(r := 0; r < len c.procs; r++) { if(c.procs[r].owner != user_sysid) continue; sys->print("P: oid %bd\n", c.procs[r].oid); sys->print("name %s\n", c.procs[r].name); sys->print("namespace %bd\n", c.procs[r].namespace); sys->print("owner %d\n", c.procs[r].owner); sys->print("lang %bd\n", c.procs[r].lang); sys->print("isagg %d\n", c.procs[r].isagg); sys->print("secdef %d\n", c.procs[r].secdef); sys->print("isstrict %d\n", c.procs[r].isstrict); sys->print("retset %d\n", c.procs[r].retset); sys->print("volatile %d\n", c.procs[r].volatile); sys->print("nargs %d\n", c.procs[r].nargs); sys->print("rettype %bd\n", c.procs[r].rettype); sys->print("argtypes :\n"); for(i := 0; i < len c.procs[r].argtypes; i++) sys->print(" type : %bd %s\n", c.procs[r].argtypes[i], c.type_name(c.procs[r].argtypes[i])); sys->print("argnames :\n"); for(i = 0; i < len c.procs[r].argnames; i++) sys->print(" names : %s\n", c.procs[r].argnames[i]); } } Catalogue.proc_sql(c : self ref Catalogue, r : int) : string { c.err_chan <- = "proc_sql"; p := c.procs[r]; sql := "CREATE OR REPLACE FUNCTION " + p.name + "("; for(k := 0; k < p.nargs; k++) { if(p.argnames != nil) sql += p.argnames[k] + " "; sql += c.type_name(p.argtypes[k]); if(k < p.nargs -1) sql += ", "; } sql += ") RETURNS " + c.type_name(p.rettype) + " AS $_$" + p.src + "$_$ LANGUAGE " + c.language_name(p.lang) + ";\n"; return sql; } Catalogue.print_procs(c : self ref Catalogue, user_sysid: int) { if(sys == nil) sys = load Sys Sys->PATH; if(c.procs == nil && c.fill_procs() == 0) { sys->print("No Procs found\n"); return; } nl := ""; for(r := 0; r < len c.procs; r++) { if(c.procs[r].owner != user_sysid) continue; sys->print("%s%s", nl, c.proc_sql(r)); nl = "\n"; } } Catalogue.fill_procs(c : self ref Catalogue) : int { c.err_chan <- = "fill_procs"; if(sys == nil) sys = load Sys Sys->PATH; stderr := sys->fildes(2); if(c.conn == nil) { sys->fprint(stderr, "conn is nil, fool\n"); return 0; } if(!c.conn.parse("", "SELECT oid, proname, pronamespace, proowner, prolang, proisagg, prosecdef, proisstrict, proretset, provolatile, pronargs, prorettype, proargtypes, proargnames, prosrc FROM pg_proc;", nil)) { sys->fprint(stderr, "proc parse failed\n"); return 0; } recordset := c.conn.execute("", "", nil, nil, nil, 0); if(recordset == nil) return 0; s : int; c.procs = array[len recordset.rows] of Proc; for(r := 0; r < len recordset.rows; r++) { s = 0; c.procs[r].rows = recordset.rows[r]; c.procs[r].oid = big string recordset.rows[r][s++]; c.procs[r].name = string recordset.rows[r][s++]; c.procs[r].namespace = big string recordset.rows[r][s++]; c.procs[r].owner = int string recordset.rows[r][s++]; c.procs[r].lang = big string recordset.rows[r][s++]; c.procs[r].isagg = int string recordset.rows[r][s++]; c.procs[r].secdef = int string recordset.rows[r][s++]; c.procs[r].isstrict = int string recordset.rows[r][s++]; c.procs[r].retset = int string recordset.rows[r][s++]; c.procs[r].volatile = int string recordset.rows[r][s++]; c.procs[r].nargs = int string recordset.rows[r][s++]; c.procs[r].rettype = big string recordset.rows[r][s++]; i : int; (errs, types) := sys->tokenize(string recordset.rows[r][s++], " "); if(len types > 0) { c.procs[r].argtypes = array[c.procs[r].nargs] of big; for(i = 0; i < c.procs[r].nargs; i++) { c.procs[r].argtypes[i] = big hd types; types = tl types; } } c.procs[r].argnames = nil; names := string recordset.rows[r][s++]; if(len names > 0) { (errs, types) = sys->tokenize(names[1:len names -1], ","); if(len types > 0) { c.procs[r].argnames = array[c.procs[r].nargs] of string; for(i = 0; i < c.procs[r].nargs; i++) { c.procs[r].argnames[i] = hd types; types = tl types; } } } c.procs[r].src = string recordset.rows[r][s++]; } return len c.procs; } Catalogue.print_types(c : self ref Catalogue) { if(sys == nil) sys = load Sys Sys->PATH; if(c.types == nil && c.fill_types() == 0) { sys->print("No Types found\n"); return; } sys->print("%d Type(s)\n", len c.types); for(r := 0; r < len c.types; r++) { sys->print("T: oid %bd\n", c.types[r].oid); sys->print("name %s\n", c.types[r].name); sys->print("namespace %bd\n", c.types[r].namespace); sys->print("owner %bd\n", c.types[r].owner); sys->print("length %d\n", c.types[r].length); sys->print("byval %d\n", c.types[r].byval); sys->print("typ %s\n", c.types[r].typ); sys->print("isdefined %d\n", c.types[r].isdefined); sys->print("delim %s\n", c.types[r].delim); sys->print("relid %bd\n", c.types[r].relid); sys->print("elem %bd\n", c.types[r].elem); sys->print("input %d\n", c.types[r].input); sys->print("output %d\n", c.types[r].output); sys->print("receive %d\n", c.types[r].receive); sys->print("send %d\n", c.types[r].send); sys->print("analyze %d\n", c.types[r].analyze); sys->print("align %s\n", c.types[r].align); sys->print("storage %s\n", c.types[r].storage); sys->print("notnull %d\n", c.types[r].notnull); sys->print("basetype %bd\n", c.types[r].basetype); sys->print("typmod %d\n", c.types[r].typmod); sys->print("ndims %d\n", c.types[r].ndims); sys->print("defaultbin %s\n", string c.types[r].defaultbin); sys->print("default %s\n", c.types[r].default); } } Catalogue.fill_types(c : self ref Catalogue) : int { c.err_chan <- = "fill_types"; if(!c.conn.parse("", "SELECT oid, typname, typnamespace, typowner, typlen, typbyval, typtype, typisdefined, typdelim, typrelid, typelem, typinput, typoutput, typreceive, typsend, typanalyze, typalign, typstorage, typnotnull, typbasetype, typtypmod, typndims, typdefaultbin, typdefault FROM pg_type;", nil)) raise "Database choked in types"; recordset := c.conn.execute("", "", nil, nil, nil, 0); if(recordset == nil) raise "No Types found"; s : int; c.types = array[len recordset.rows] of Type; for(r := 0; r < len recordset.rows; r++) { s = 0; c.types[r].oid = big string recordset.rows[r][s++]; c.types[r].name = string recordset.rows[r][s++]; c.types[r].namespace = big string recordset.rows[r][s++]; c.types[r].owner = big string recordset.rows[r][s++]; c.types[r].length = int string recordset.rows[r][s++]; c.types[r].byval = int string recordset.rows[r][s++]; c.types[r].typ = string recordset.rows[r][s++]; c.types[r].isdefined = int string recordset.rows[r][s++]; c.types[r].delim = string recordset.rows[r][s++]; c.types[r].relid = big string recordset.rows[r][s++]; c.types[r].elem = big string recordset.rows[r][s++]; c.types[r].input = int string recordset.rows[r][s++]; c.types[r].output = int string recordset.rows[r][s++]; c.types[r].receive = int string recordset.rows[r][s++]; c.types[r].send = int string recordset.rows[r][s++]; c.types[r].analyze = int string recordset.rows[r][s++]; c.types[r].align = string recordset.rows[r][s++]; c.types[r].storage = string recordset.rows[r][s++]; c.types[r].notnull = int string recordset.rows[r][s++]; c.types[r].basetype = big string recordset.rows[r][s++]; c.types[r].typmod = int string recordset.rows[r][s++]; c.types[r].ndims = int string recordset.rows[r][s++]; c.types[r].defaultbin = recordset.rows[r][s++]; c.types[r].default = string recordset.rows[r][s++]; } return len c.types; } Catalogue.type_name(c : self ref Catalogue, oid : big) : string { if(c.types == nil) c.fill_types(); for(i := 0; i < len c.types; i++) { if(c.types[i].oid == oid) return c.types[i].name; } return nil; } Catalogue.fill_languages(c : self ref Catalogue) : int { c.err_chan <- = "fill_languages"; if(!c.conn.parse("", "SELECT oid, lanname, lanispl, lanpltrusted, lanplcallfoid, lanvalidator, lanacl FROM pg_language;", nil)) raise "Database choked in languages"; recordset := c.conn.execute("", "", nil, nil, nil, 0); if(recordset == nil) raise "No Languages found"; s : int; c.languages = array[len recordset.rows] of Language; for(r := 0; r < len recordset.rows; r++) { s = 0; c.languages[r].oid = big string recordset.rows[r][s++]; c.languages[r].name = string recordset.rows[r][s++]; c.languages[r].ispl = int string recordset.rows[r][s++]; c.languages[r].pltrusted = int string recordset.rows[r][s++]; c.languages[r].plcallfoid = big string recordset.rows[r][s++]; c.languages[r].validator = big string recordset.rows[r][s++]; c.languages[r].acl = string recordset.rows[r][s++]; } return len c.languages; } Catalogue.language_name(c : self ref Catalogue, oid : big) : string { if(c.languages == nil) c.fill_languages(); for(i := 0; i < len c.languages; i++) { if(c.languages[i].oid == oid) return c.languages[i].name; } return nil; } Catalogue.fill_users(c : self ref Catalogue) : int { if(!c.conn.parse("", "SELECT usename, usesysid, usecreatedb, usesuper, usecatupd, valuntil, useconfig FROM pg_user;", nil)) raise "Database choked in users"; recordset := c.conn.execute("", "", nil, nil, nil, 0); if(recordset == nil) raise "No Users found"; s : int; c.users = array[len recordset.rows] of User; for(r := 0; r < len recordset.rows; r++) { s = 0; c.users[r].name = string recordset.rows[r][s++]; c.users[r].sysid = int string recordset.rows[r][s++]; c.users[r].createdb = int string recordset.rows[r][s++]; c.users[r].super = int string recordset.rows[r][s++]; c.users[r].catupd = int string recordset.rows[r][s++]; c.users[r].valuntil = string recordset.rows[r][s++]; c.users[r].config = string recordset.rows[r][s++]; } c.err_chan <- = "filled_users"; return len c.users; } Catalogue.user_name(c : self ref Catalogue, sysid : int) : string { if(c.users == nil) c.fill_users(); for(i := 0; i < len c.users; i++) { if(c.users[i].sysid == sysid) return c.users[i].name; } return nil; }