diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /appl/demo/odbc/odbcmnt.b | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'appl/demo/odbc/odbcmnt.b')
| -rw-r--r-- | appl/demo/odbc/odbcmnt.b | 428 |
1 files changed, 428 insertions, 0 deletions
diff --git a/appl/demo/odbc/odbcmnt.b b/appl/demo/odbc/odbcmnt.b new file mode 100644 index 00000000..3cadc55f --- /dev/null +++ b/appl/demo/odbc/odbcmnt.b @@ -0,0 +1,428 @@ +implement Odbcmnt; + +# +# Copyright © 2003 Vita Nuova Holdings Limited. All rights reserved. +# + +include "sys.m"; + sys: Sys; + stderr: ref Sys->FD; +include "draw.m"; +include "arg.m"; +include "string.m"; + str: String; +include "daytime.m"; + daytime: Daytime; +include "convcs.m"; + convcs : Convcs; +include "styx.m"; + styx: Styx; + Tmsg, Rmsg: import styx; +include "styxservers.m"; + styxservers: Styxservers; + Styxserver, Navigator: import styxservers; + nametree: Nametree; + Tree: import nametree; + +Column: adt { + name: string; + ctype: string; + size: int; +}; + +Qroot: con iota; +WINCHARSET := "windows-1252"; # BUG: odbc.c should do the conversion! + +Odbcmnt: module +{ + init: fn(ctxt: ref Draw->Context, argv: list of string); +}; + +init(nil: ref Draw->Context, argv: list of string) +{ + sys = load Sys Sys->PATH; + stderr = sys->fildes(2); + + arg := load Arg Arg->PATH; + if(arg == nil) + notloaded(Arg->PATH); + daytime = load Daytime Daytime->PATH; + if (daytime == nil) + notloaded(Daytime->PATH); + str = load String String->PATH; + if(str == nil) + notloaded(String->PATH); + convcs = load Convcs Convcs->PATH; + if(convcs == nil) + notloaded(Convcs->PATH); + cserr := convcs->init(nil); + if (cserr != nil) + err("convcs init failed " + cserr); + styx = load Styx Styx->PATH; + if(styx == nil) + notloaded(Styx->PATH); + styx->init(); + styxservers = load Styxservers Styxservers->PATH; + if(styxservers == nil) + notloaded(Styxservers->PATH); + styxservers->init(styx); + nametree = load Nametree Nametree->PATH; + if(nametree == nil) + notloaded(Nametree->PATH); + nametree->init(); + addr := "127.0.0.1"; + arg->init(argv); + stype := "ODBC"; + while((o := arg->opt()) != 0) + case o { + 'a' => + addr = arg->earg(); + * => + usage(); + } + + argv = arg->argv(); + arg = nil; + sys->pctl(Sys->FORKNS | sys->NEWPGRP, nil); + dbdir := do_mount(netmkaddr(addr, "tcp", "6700")); + (cfd, cdir) := do_clone(dbdir); + sources := find_sources(cdir); + sys->print("Found %d sources\n", len sources); + spawn serveloop(dbdir, sources, sys->fildes(0)); +} + +netmkaddr(addr, net, svc: string): string +{ + if(net == nil) + net = "net"; + (n, l) := sys->tokenize(addr, "!"); + if(n <= 1){ + if(svc== nil) + return sys->sprint("%s!%s", net, addr); + return sys->sprint("%s!%s!%s", net, addr, svc); + } + if(svc == nil || n > 2) + return addr; + return sys->sprint("%s!%s", addr, svc); +} + +split1(s, delim: string): (string, string) +{ + (l, r) := str->splitl(s, delim); + return (l, str->drop(r, delim)); +} + +notloaded(s: string) +{ + err(sys->sprint("failed to load %s: %r", s)); +} + +usage() +{ + sys->fprint(stderr, "Usage: odbcmnt [ -a address ]\n"); + raise "fail:usage"; +} + +do_mount(addr: string): string +{ + (ok, c) := sys->dial(addr, nil); + remdir := "/n/remote"; + if (ok < 0) + err(sys->sprint("failed to dial odbc server on %s: %r", addr)); + if (sys->mount(c.dfd, nil, remdir, 0, nil) < 0) + err(sys->sprint("failed to mount odbc server on %s: %r", addr)); + dbdir := remdir + "/db"; + return dbdir; +} + + +do_clone(dbdir: string): (ref Sys->FD, string) +{ + newfile := dbdir + "/new"; + cfd := sys->open(newfile, Sys->OREAD); + if (cfd == nil) + err(sys->sprint("failed to open %s: %r", newfile)); + cname := read_fd(cfd); + if (cname == nil) + err("failed to find clone directory name"); + return(cfd, dbdir + "/" + cname); +} + +dir(name: string, perm: int, length: int, qid: int): Sys->Dir +{ + uid := read_file("/dev/user"); + d := sys->zerodir; + d.name = name; + d.uid = uid; + d.gid = uid; + d.qid.path = big qid; + if (perm & Sys->DMDIR) + d.qid.qtype = Sys->QTDIR; + else { + d.qid.qtype = Sys->QTFILE; + d.length = big length; + } + d.mode = perm; + d.atime = d.mtime = daytime->now(); + return d; +} + +newconv(dbdir, source: string): (ref Sys->FD, ref Sys->FD, ref Sys->FD, ref Sys->FD, string) +{ + err := ""; + (clonefd, cdir) := do_clone(dbdir); + ctlf := cdir + "/ctl"; + ctlfd := sys->open(ctlf, Sys->ORDWR); + if (ctlfd == nil) + err = sys->sprint("Failed to open %s: %r", ctlf); + cmdf := cdir + "/cmd"; + cmdfd := sys->open(cmdf, Sys->ORDWR); + if (cmdfd == nil) + err = sys->sprint("Failed to open %s: %r", cmdf); + dataf := cdir + "/data"; + datafd := sys->open(dataf, Sys->ORDWR); + if (datafd == nil) + err = sys->sprint("Failed to open %s: %r", dataf); + if (write_fd(ctlfd, "connect " + source) < 0) + err = sys->sprint("failed to connect to %s: %r", source); + return (clonefd, ctlfd, cmdfd, datafd, err); +} + +SRCDIR: con 1; +SQL: con 2; +TABLE: con 3; +TABLEDIR: con 4; +COLUMN: con 5; + +gettype(fid: big): int +{ + return int fid & 7; +} + +SrcFD: adt { + clonefd, ctlfd, cmdfd, datafd: ref sys->FD; +}; + +serveloop(dbdir: string, sources: list of string, confd: ref sys->FD) +{ + srcqid := 0; + sqlqid := 0; + tableqid := 0; + colqid := 0; + tabledirqid := 0; + (bs, cserr) := convcs->getbtos(WINCHARSET); + if (bs == nil) + err("getbtos error: " + cserr); + (tree, treeop) := nametree->start(); + tree.create(big Qroot, dir(".",8r555 | sys->DMDIR,0,Qroot)); + contents: list of string; + srcfds := array[len sources] of SrcFD; + i := 0; + for (sl := sources; sl!=nil; sl=tl sl) { + (srcname, srcdriver) := split1(hd sl, ":"); + # Don't do anything with 'srvdriver' - could make a driver + # file to read - but does anyone care about it? + (clonefd, ctlfd, cmdfd, datafd, e) := newconv(dbdir, srcname); + if (e != nil) + sys->fprint(sys->fildes(2), "Odbcmnt: %s\n",e); + else { + srcfds[i] = (clonefd, ctlfd, cmdfd, datafd); + sys->print("%s\n",srcname); + Qsrc := SRCDIR + (srcqid++<<3); + tree.create(big Qroot, dir(srcname,8r555 | sys->DMDIR,0,Qsrc)); + Qtabledir := TABLEDIR + (tabledirqid++<<3); + tree.create(big Qsrc, dir("tables",8r555 | sys->DMDIR,0,Qtabledir)); + Qsql := SQL + (sqlqid++<<3); + tree.create(big Qsrc, dir("sql",8r666,0, Qsql)); + + tables := find_tables(srcfds[i].cmdfd, srcfds[i].datafd); + if (tables == nil) + err(sys->sprint("failed to find tables: %r")); + if (write_fd(srcfds[i].ctlfd, "headings") < 0) + err(sys->sprint("failed to write to ctl file: %r")); + sys->print("\tBuilding tree..."); + for (tlist:=tables; tlist!=nil; tlist=tl tlist) { + table := hd tlist; + Qtable := TABLE + (tableqid++<<3); + tree.create(big Qtabledir, dir(table,8r555 | sys->DMDIR,0,Qtable)); + columns := find_columns(srcfds[i].cmdfd, srcfds[i].datafd, table); + for (clist:=columns; clist!=nil; clist=tl clist) { + column := hd clist; + Qcol := COLUMN + (colqid<<3); + tree.create(big Qtable, dir(column.name,8r555,0,Qcol)); + data := sys->sprint("%s %d\n", column.ctype, column.size); + contents = data :: contents; + colqid++; + } + } + sys->print("done\n"); + } + i++; + } + colcontent := array[colqid] of string; + for (i = colqid - 1; i >= 0; i--) { + colcontent[i] = hd contents; + contents = tl contents; + } + (tchan, srv) := Styxserver.new(confd, Navigator.new(treeop), big Qroot); + sys->pctl(Sys->FORKNS|Sys->FORKFD, nil); + gm: ref Tmsg; + buf := array[Sys->ATOMICIO] of byte; + serverloop: for (;;) { + gm = <-tchan; + if (gm == nil) + break serverloop; + pick m := gm { + Readerror => + sys->fprint(sys->fildes(2), "odbcmnt: fatal read error: %s\n", m.error); + break serverloop; + Read => + c := srv.getfid(m.fid); + if(c.qtype & Sys->QTDIR){ + srv.read(m); # does readdir + break; + } + case gettype(c.path) { + SQL => + srcno := int c.path >> 3; + sys->seek(srcfds[srcno].datafd, m.offset, Sys->SEEKSTART); + n := sys->read(srcfds[srcno].datafd, buf, len buf); + if (n >= 0) { + (state, s, err) := bs->btos(nil, buf[:n], -1); + r := ref Rmsg.Read(gm.tag, array of byte s); + srv.reply(r); + } else + srv.reply(ref Rmsg.Error(gm.tag, sys->sprint("%r"))); + break; + COLUMN => + srv.reply(styxservers->readstr(m, colcontent[int c.path>>3])); + * => + srv.default(gm); + } + Write => + c := srv.getfid(m.fid); + case gettype(c.path) { + SQL => + srcno := int c.path >> 3; + n := sys->write(srcfds[srcno].cmdfd, m.data, len m.data); + if (n == len m.data) + srv.reply(ref Rmsg.Write(m.tag, n)); + else + srv.reply(ref Rmsg.Error(gm.tag, sys->sprint("%r"))); + break; + * => + srv.default(gm); + } + + * => + srv.default(gm); + } + } + tree.quit(); +} + +find_tables(cmdfd, datafd: ref Sys->FD): list of string +{ + tlist: list of string; + if (write_fd(cmdfd, "tables") < 0) + err(sys->sprint("failed to write to cmd file: %r")); + while((rec := read_fd(datafd)) != nil) { + fields := atokenize(rec, "|"); + if (len fields < 4) + err("bad table name"); + tname := fields[2]; + tlist = tname :: tlist; + } + return tlist; +} + + +find_columns(cmdfd, datafd: ref Sys->FD, table: string): list of Column +{ + clist: list of Column; + if (write_fd(cmdfd, "columns " + table) < 0) + err(sys->sprint("failed to write to cmd file: %r")); + while((rec := read_fd(datafd)) != nil) { + fields := atokenize(rec, "|"); + if (len fields < 3) + err("bad column name"); + cname :=fields[3]; + ctype := ""; + if (len fields > 5) + ctype = fields[5]; + csize := 0; + if (len fields > 6) + csize = int fields[6]; + clist = (fields[3], ctype, csize) :: clist; + } + return clist; +} + +atokenize(s: string, delim: string): array of string +{ + if (s == nil) + return nil; + dl := len delim; + r: list of string; + l: string; + for (;;) { + (l, s) = str->splitstrl(s, delim); + r = l :: r; + if (s == nil || s == delim) + break; + s = s[dl:]; + } + a := array[len r] of string; + for (i:=len r-1; i>=0; i--) { + a[i] = hd r; + r = tl r; + } + return a; +} + +find_sources(cdir: string): list of string +{ + sfile := cdir+"/sources"; + fd := sys->open(sfile, Sys->OREAD); + if (fd == nil) + err(sys->sprint("failed to open %s: %r", sfile)); + s := read_fd(fd); + (n, lines) := sys->tokenize(s, "\n"); + return lines; +} + +err(s: string) +{ + sys->fprint(stderr, "odbcgw: %s\n", s); + raise "fail:error"; +} + +read_fd(fd: ref Sys->FD): string +{ + MAX : con Sys->ATOMICIO; + buf := array[MAX] of byte; +# sys->seek(fd, big 0, Sys->SEEKSTART); + size := sys->read(fd, buf, MAX); + if (size <= 0) { +# if (size < 0) +# sys->fprint(stderr, "read_fd error: %r\n"); + return nil; + } + return string buf[0:size]; +} + +read_file(f: string): string +{ + fd := sys->open(f, Sys->OREAD); + if (fd == nil) + return nil; + return read_fd(fd); +} + +write_fd(fd: ref Sys->FD, s: string): int +{ + a := array of byte s; + if (sys->write(fd, a, len a) != len a) + return -1; + return 0; +}
\ No newline at end of file |
