146439007SCharles.Forsyth #ifdef WINDOWSNT
246439007SCharles.Forsyth #include <windows.h>
346439007SCharles.Forsyth #endif
446439007SCharles.Forsyth #include <lib9.h>
546439007SCharles.Forsyth #include <styx.h>
646439007SCharles.Forsyth #include "styxserver.h"
746439007SCharles.Forsyth /* #include <winsock.h> */
846439007SCharles.Forsyth
946439007SCharles.Forsyth #define DEFCOLSIZE 10000
1046439007SCharles.Forsyth
1146439007SCharles.Forsyth static int ODebug;
1246439007SCharles.Forsyth
1346439007SCharles.Forsyth char Eodbcalloc[] = "no free ODBC handles";
1446439007SCharles.Forsyth char Enoconnect[] = "no ODBC connection";
1546439007SCharles.Forsyth
1646439007SCharles.Forsyth static char *netport = "6700";
1746439007SCharles.Forsyth static char *inferno = "inferno";
1846439007SCharles.Forsyth
1946439007SCharles.Forsyth Styxserver *iserver;
2046439007SCharles.Forsyth
2146439007SCharles.Forsyth /* ----- */
2246439007SCharles.Forsyth #include <sql.h>
2346439007SCharles.Forsyth #include <sqlext.h>
2446439007SCharles.Forsyth
2546439007SCharles.Forsyth int nclients = 0;
2646439007SCharles.Forsyth
2746439007SCharles.Forsyth typedef struct Env Env;
2846439007SCharles.Forsyth struct Env
2946439007SCharles.Forsyth {
3046439007SCharles.Forsyth SQLHENV h; /* ODBC environment handle */
3146439007SCharles.Forsyth };
3246439007SCharles.Forsyth
3346439007SCharles.Forsyth typedef struct Conn Conn;
3446439007SCharles.Forsyth struct Conn
3546439007SCharles.Forsyth {
3646439007SCharles.Forsyth SQLHDBC h; /* ODBC connection handle */
3746439007SCharles.Forsyth int connected;
3846439007SCharles.Forsyth };
3946439007SCharles.Forsyth
4046439007SCharles.Forsyth typedef struct Coltype Coltype;
4146439007SCharles.Forsyth struct Coltype
4246439007SCharles.Forsyth {
4346439007SCharles.Forsyth char name[255];
4446439007SCharles.Forsyth ushort type;
4546439007SCharles.Forsyth SQLUINTEGER size;
4646439007SCharles.Forsyth ushort digits;
4746439007SCharles.Forsyth ushort nulls;
4846439007SCharles.Forsyth };
4946439007SCharles.Forsyth
5046439007SCharles.Forsyth typedef struct Column Column;
5146439007SCharles.Forsyth struct Column
5246439007SCharles.Forsyth {
5346439007SCharles.Forsyth char *data;
5446439007SCharles.Forsyth SQLINTEGER len;
5546439007SCharles.Forsyth };
5646439007SCharles.Forsyth
5746439007SCharles.Forsyth typedef struct Stmt Stmt;
5846439007SCharles.Forsyth struct Stmt
5946439007SCharles.Forsyth {
6046439007SCharles.Forsyth SQLHSTMT h; /* ODBC statement handle */
6146439007SCharles.Forsyth ushort ncols; /* number of columns in result */
6246439007SCharles.Forsyth ulong nrows; /* number of rows affected by update, insert, delete */
6346439007SCharles.Forsyth Coltype *cols; /* column descriptions */
6446439007SCharles.Forsyth Column *rec; /* data record */
6546439007SCharles.Forsyth char *headstr; /* column headings if requested */
6646439007SCharles.Forsyth };
6746439007SCharles.Forsyth
6846439007SCharles.Forsyth /* ----- */
6946439007SCharles.Forsyth enum
7046439007SCharles.Forsyth {
7146439007SCharles.Forsyth Qtopdir = 0, /* top level directory */
7246439007SCharles.Forsyth Qnclients,
7346439007SCharles.Forsyth Qprotodir,
7446439007SCharles.Forsyth Qclonus,
7546439007SCharles.Forsyth Qconvdir,
7646439007SCharles.Forsyth Qdata,
7746439007SCharles.Forsyth Qcmd,
7846439007SCharles.Forsyth Qctl,
7946439007SCharles.Forsyth Qstatus,
8046439007SCharles.Forsyth Qformat,
8146439007SCharles.Forsyth Qsources,
8246439007SCharles.Forsyth Qerror,
8346439007SCharles.Forsyth
8446439007SCharles.Forsyth MAXPROTO = 1
8546439007SCharles.Forsyth };
8646439007SCharles.Forsyth #define TYPE(x) ((x).path & 0xf)
8746439007SCharles.Forsyth #define CONV(x) (((x).path >> 4)&0xfff)
8846439007SCharles.Forsyth #define PROTO(x) (((x).path >> 16)&0xff)
8946439007SCharles.Forsyth #define QID(p, c, y) (((p)<<16) | ((c)<<4) | (y))
9046439007SCharles.Forsyth
9146439007SCharles.Forsyth typedef struct Proto Proto;
9246439007SCharles.Forsyth typedef struct Conv Conv;
9346439007SCharles.Forsyth typedef struct Output Output;
9446439007SCharles.Forsyth
9546439007SCharles.Forsyth struct Output {
9646439007SCharles.Forsyth enum {Fixed, Float} style; /* output style */
9746439007SCharles.Forsyth uchar fs; /* float: field separator */
9846439007SCharles.Forsyth uchar rs; /* float: record separator */
9946439007SCharles.Forsyth };
10046439007SCharles.Forsyth Output defoutput = {Float, '|', '\n'};
10146439007SCharles.Forsyth
10246439007SCharles.Forsyth struct Conv
10346439007SCharles.Forsyth {
10446439007SCharles.Forsyth int x;
10546439007SCharles.Forsyth int ref;
10646439007SCharles.Forsyth int perm;
10746439007SCharles.Forsyth char *owner;
10846439007SCharles.Forsyth char* state;
10946439007SCharles.Forsyth Proto* p;
11046439007SCharles.Forsyth
11146439007SCharles.Forsyth /*-----*/
11246439007SCharles.Forsyth Conn c;
11346439007SCharles.Forsyth Stmt s;
11446439007SCharles.Forsyth Output out;
11546439007SCharles.Forsyth int headings;
11646439007SCharles.Forsyth char errmsg[400]; /* odbc error messages can be big */
11746439007SCharles.Forsyth };
11846439007SCharles.Forsyth
11946439007SCharles.Forsyth struct Proto
12046439007SCharles.Forsyth {
12146439007SCharles.Forsyth int x;
12246439007SCharles.Forsyth char *name;
12346439007SCharles.Forsyth uint nc;
12446439007SCharles.Forsyth int maxconv;
12546439007SCharles.Forsyth Conv** conv;
12646439007SCharles.Forsyth Qid qid;
12746439007SCharles.Forsyth };
12846439007SCharles.Forsyth
12946439007SCharles.Forsyth typedef struct Dirtab Dirtab;
13046439007SCharles.Forsyth struct Dirtab
13146439007SCharles.Forsyth {
13246439007SCharles.Forsyth char name[255];
13346439007SCharles.Forsyth Qid qid;
13446439007SCharles.Forsyth long length;
13546439007SCharles.Forsyth long perm;
13646439007SCharles.Forsyth };
13746439007SCharles.Forsyth
13846439007SCharles.Forsyth static int np;
13946439007SCharles.Forsyth static Proto proto[MAXPROTO];
14046439007SCharles.Forsyth static Conv* protoclone(Proto*, char*);
14146439007SCharles.Forsyth
14246439007SCharles.Forsyth typedef int Devgen(Fid*, char *, Dirtab*, int, int, Dir*);
14346439007SCharles.Forsyth
14446439007SCharles.Forsyth struct xClient {
14546439007SCharles.Forsyth /* ---- */
14646439007SCharles.Forsyth Env e;
14746439007SCharles.Forsyth };
14846439007SCharles.Forsyth
14946439007SCharles.Forsyth #define H(c) ((Env*)(c->u))->h
15046439007SCharles.Forsyth
15146439007SCharles.Forsyth void
fatal(char * fmt,...)15246439007SCharles.Forsyth fatal(char *fmt, ...)
15346439007SCharles.Forsyth {
15446439007SCharles.Forsyth char buf[1024], *out;
15546439007SCharles.Forsyth va_list arg;
15646439007SCharles.Forsyth out = vseprint(buf, buf+sizeof(buf), "Fatal error: ", 0);
15746439007SCharles.Forsyth va_start(arg, fmt);
15846439007SCharles.Forsyth out = vseprint(out, buf+sizeof(buf), fmt, arg);
15946439007SCharles.Forsyth va_end(arg);
16046439007SCharles.Forsyth write(2, buf, out-buf);
16146439007SCharles.Forsyth exit(1);
16246439007SCharles.Forsyth }
16346439007SCharles.Forsyth
16446439007SCharles.Forsyth #define ASSERT(A,B) xassert((int)A,B)
16546439007SCharles.Forsyth
16646439007SCharles.Forsyth void
xassert(int true,char * reason)16746439007SCharles.Forsyth xassert(int true, char *reason)
16846439007SCharles.Forsyth {
16946439007SCharles.Forsyth if(!true)
17046439007SCharles.Forsyth fatal("assertion failed: %s\n", reason);
17146439007SCharles.Forsyth }
17246439007SCharles.Forsyth
17346439007SCharles.Forsyth void *
xmalloc(int bytes)17446439007SCharles.Forsyth xmalloc(int bytes)
17546439007SCharles.Forsyth {
17646439007SCharles.Forsyth char *m = malloc(bytes);
17746439007SCharles.Forsyth if(m)
17846439007SCharles.Forsyth memset(m, 0, bytes);
17946439007SCharles.Forsyth // print("xmalloc: %lux (%d)\n", m, bytes);
18046439007SCharles.Forsyth return m;
18146439007SCharles.Forsyth }
18246439007SCharles.Forsyth
18346439007SCharles.Forsyth void
xfree(void * p,char * from)18446439007SCharles.Forsyth xfree(void *p, char *from)
18546439007SCharles.Forsyth {
18646439007SCharles.Forsyth // print("xfree: %lux [%s]\n", p, from);
18746439007SCharles.Forsyth free(p);
18846439007SCharles.Forsyth }
18946439007SCharles.Forsyth
19046439007SCharles.Forsyth char *
odbcerror(Conv * cv,int lasterr)19146439007SCharles.Forsyth odbcerror(Conv *cv, int lasterr)
19246439007SCharles.Forsyth {
19346439007SCharles.Forsyth char sqlstate[6];
19446439007SCharles.Forsyth long native;
19546439007SCharles.Forsyth char *mp;
19646439007SCharles.Forsyth short msglen;
19746439007SCharles.Forsyth
19846439007SCharles.Forsyth if(cv == 0)
19946439007SCharles.Forsyth return "";
20046439007SCharles.Forsyth if(lasterr)
20146439007SCharles.Forsyth return cv->errmsg;
20246439007SCharles.Forsyth if(cv->c.connected)
20346439007SCharles.Forsyth SQLGetDiagRec(SQL_HANDLE_STMT, cv->s.h, 1, sqlstate, &native, cv->errmsg, sizeof(cv->errmsg), &msglen);
20446439007SCharles.Forsyth else
20546439007SCharles.Forsyth SQLGetDiagRec(SQL_HANDLE_DBC, cv->c.h, 1, sqlstate, &native, cv->errmsg, sizeof(cv->errmsg), &msglen);
20646439007SCharles.Forsyth cv->errmsg[msglen]=0;
20746439007SCharles.Forsyth /* fprint(2, "c: sqlstate: %s, msg %s\n", sqlstate, cv->errmsg); */
20846439007SCharles.Forsyth if((mp=strrchr(cv->errmsg, ']')) != 0)
20946439007SCharles.Forsyth return mp+1;
21046439007SCharles.Forsyth return cv->errmsg;
21146439007SCharles.Forsyth }
21246439007SCharles.Forsyth
213*ea0789e7SCharles.Forsyth char*
odbcsources(Client * c)214*ea0789e7SCharles.Forsyth odbcsources(Client *c)
21546439007SCharles.Forsyth {
21646439007SCharles.Forsyth int ss, i;
21746439007SCharles.Forsyth char server[SQL_MAX_DSN_LENGTH+1];
21846439007SCharles.Forsyth char source[1024];
21946439007SCharles.Forsyth char buff[1024+SQL_MAX_DSN_LENGTH+1];
22046439007SCharles.Forsyth short serverlen, sourcelen;
22146439007SCharles.Forsyth char *all = nil, *p;
22246439007SCharles.Forsyth
22346439007SCharles.Forsyth for (i=0;; i++) {
22446439007SCharles.Forsyth ss = SQLDataSources(H(c), (i==0 ? SQL_FETCH_FIRST : SQL_FETCH_NEXT),
22546439007SCharles.Forsyth server, sizeof(server), &serverlen,
22646439007SCharles.Forsyth source, sizeof(source), &sourcelen);
22746439007SCharles.Forsyth if (ss != SQL_SUCCESS)
22846439007SCharles.Forsyth break;
229*ea0789e7SCharles.Forsyth snprint(buff, sizeof(buff), "%s:%s\n", server, source);
23046439007SCharles.Forsyth if (i == 0)
23146439007SCharles.Forsyth all = strdup(buff);
23246439007SCharles.Forsyth else {
23346439007SCharles.Forsyth p = all;
23446439007SCharles.Forsyth all = malloc(strlen(all)+strlen(buff)+1);
23546439007SCharles.Forsyth strcpy(all, p);
23646439007SCharles.Forsyth strcat(all, buff);
23746439007SCharles.Forsyth free(p);
23846439007SCharles.Forsyth }
23946439007SCharles.Forsyth }
24046439007SCharles.Forsyth return all;
24146439007SCharles.Forsyth }
24246439007SCharles.Forsyth
24346439007SCharles.Forsyth
24446439007SCharles.Forsyth int
sqlerr(Conv * c,int sqlstatus,char * errp,char * func,char * sqlcall)24546439007SCharles.Forsyth sqlerr(Conv *c, int sqlstatus, char *errp, char *func, char *sqlcall)
24646439007SCharles.Forsyth {
24746439007SCharles.Forsyth char *e;
24846439007SCharles.Forsyth
24946439007SCharles.Forsyth errp[0] = 0;
25046439007SCharles.Forsyth e = "failed";
25146439007SCharles.Forsyth if (sqlstatus == SQL_ERROR || sqlstatus == SQL_SUCCESS_WITH_INFO)
252*ea0789e7SCharles.Forsyth strecpy(errp, errp+ERRMAX, odbcerror(c, 0));
25346439007SCharles.Forsyth if (sqlstatus == SQL_SUCCESS_WITH_INFO)
25446439007SCharles.Forsyth e = "info";
25546439007SCharles.Forsyth if (sqlstatus != SQL_SUCCESS)
25646439007SCharles.Forsyth fprint(2, "%s: %s %s - %s\n", func, sqlcall, e, errp);
25746439007SCharles.Forsyth if (sqlstatus != SQL_SUCCESS && sqlstatus != SQL_SUCCESS_WITH_INFO)
25846439007SCharles.Forsyth return 1;
25946439007SCharles.Forsyth return 0;
26046439007SCharles.Forsyth }
26146439007SCharles.Forsyth
26246439007SCharles.Forsyth char*
odbcnewclient(Client * c)26346439007SCharles.Forsyth odbcnewclient(Client *c)
26446439007SCharles.Forsyth {
26546439007SCharles.Forsyth int ss;
26646439007SCharles.Forsyth
26746439007SCharles.Forsyth /* ---- */
26846439007SCharles.Forsyth c->u = styxmalloc(sizeof(Env));
26946439007SCharles.Forsyth ss = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &H(c));
27046439007SCharles.Forsyth if (ss != SQL_SUCCESS && ss != SQL_SUCCESS_WITH_INFO) {
27146439007SCharles.Forsyth fprint(2, "newclient: SQLAllocHandle failed\n");
27246439007SCharles.Forsyth return "SQLAllocHandle failed";
27346439007SCharles.Forsyth }
27446439007SCharles.Forsyth ss = SQLSetEnvAttr(H(c), SQL_ATTR_ODBC_VERSION, (char*)SQL_OV_ODBC2, 0);
27546439007SCharles.Forsyth if (ss != SQL_SUCCESS && ss != SQL_SUCCESS_WITH_INFO) {
27646439007SCharles.Forsyth fprint(2, "newclient: SQLSetEnvAttr failed\n");
27746439007SCharles.Forsyth return "SQLSetEnvAttr failed";
27846439007SCharles.Forsyth }
27946439007SCharles.Forsyth nclients++;
28046439007SCharles.Forsyth return nil;
28146439007SCharles.Forsyth }
28246439007SCharles.Forsyth
28346439007SCharles.Forsyth char*
odbcfreeclient(Client * c)28446439007SCharles.Forsyth odbcfreeclient(Client *c)
28546439007SCharles.Forsyth {
28646439007SCharles.Forsyth int ss;
28746439007SCharles.Forsyth
28846439007SCharles.Forsyth ss = SQLFreeHandle(SQL_HANDLE_ENV, H(c));
28946439007SCharles.Forsyth if (ss != SQL_SUCCESS && ss != SQL_SUCCESS_WITH_INFO)
29046439007SCharles.Forsyth fprint(2, "freeclient: SQLFreeHandle failed\n");
29146439007SCharles.Forsyth styxfree(c->u);
29246439007SCharles.Forsyth nclients--;
29346439007SCharles.Forsyth return nil;
29446439007SCharles.Forsyth }
29546439007SCharles.Forsyth
29646439007SCharles.Forsyth int
parsefields(char * lp,char ** fields,int n,char * sep)29746439007SCharles.Forsyth parsefields(char *lp, char **fields, int n, char *sep)
29846439007SCharles.Forsyth {
29946439007SCharles.Forsyth int i;
30046439007SCharles.Forsyth
30146439007SCharles.Forsyth for(i=0; lp && *lp && i<n; i++){
30246439007SCharles.Forsyth while(*lp && strchr(sep, *lp) != 0)
30346439007SCharles.Forsyth *lp++=0;
30446439007SCharles.Forsyth if(*lp == 0)
30546439007SCharles.Forsyth break;
30646439007SCharles.Forsyth fields[i]=lp;
30746439007SCharles.Forsyth while(*lp && strchr(sep, *lp) == 0)
30846439007SCharles.Forsyth lp++;
30946439007SCharles.Forsyth }
31046439007SCharles.Forsyth return i;
31146439007SCharles.Forsyth }
31246439007SCharles.Forsyth
31346439007SCharles.Forsyth void
odbcdisconnect(Conv * c)31446439007SCharles.Forsyth odbcdisconnect(Conv *c)
31546439007SCharles.Forsyth {
31646439007SCharles.Forsyth int ss;
31746439007SCharles.Forsyth
31846439007SCharles.Forsyth if(c->c.connected){
31946439007SCharles.Forsyth ss = SQLFreeHandle(SQL_HANDLE_STMT, c->s.h);
32046439007SCharles.Forsyth if (ss != SQL_SUCCESS && ss != SQL_SUCCESS_WITH_INFO)
32146439007SCharles.Forsyth fprint(2, "odbcdisconnect: SQLFreeHandle failed\n");
32246439007SCharles.Forsyth ss = SQLDisconnect(c->c.h);
32346439007SCharles.Forsyth if (ss != SQL_SUCCESS && ss != SQL_SUCCESS_WITH_INFO)
32446439007SCharles.Forsyth fprint(2, "odbcdisconnect: SQLDisconnect failed\n");
32546439007SCharles.Forsyth c->c.connected = 0;
32646439007SCharles.Forsyth }
32746439007SCharles.Forsyth }
32846439007SCharles.Forsyth
32946439007SCharles.Forsyth int
odbcconnect(Conv * c,char * server,char * user,char * auth,char * ename)33046439007SCharles.Forsyth odbcconnect(Conv *c, char *server, char *user, char *auth, char *ename)
33146439007SCharles.Forsyth {
33246439007SCharles.Forsyth int ss;
33346439007SCharles.Forsyth
33446439007SCharles.Forsyth odbcdisconnect(c);
33546439007SCharles.Forsyth ss = SQLConnect(c->c.h, server, SQL_NTS, user, strlen(user), auth, strlen(auth));
33646439007SCharles.Forsyth if (sqlerr(c, ss, ename, "odbcconnect", "SQLConnect"))
33746439007SCharles.Forsyth return -1;
33846439007SCharles.Forsyth c->c.connected = 1;
33946439007SCharles.Forsyth ss = SQLAllocHandle(SQL_HANDLE_STMT, c->c.h, &c->s.h);
34046439007SCharles.Forsyth if (sqlerr(c, ss, ename, "odbcconnect", "SQLAllocHandle"))
34146439007SCharles.Forsyth return -1;
34246439007SCharles.Forsyth return 0;
34346439007SCharles.Forsyth }
34446439007SCharles.Forsyth
34546439007SCharles.Forsyth int
odbcnewconv(Client * c,Conv * cv)34646439007SCharles.Forsyth odbcnewconv(Client *c, Conv *cv)
34746439007SCharles.Forsyth {
34846439007SCharles.Forsyth int ss;
34946439007SCharles.Forsyth
35046439007SCharles.Forsyth ss = SQLAllocHandle(SQL_HANDLE_DBC, H(c), &cv->c.h);
35146439007SCharles.Forsyth if (ss != SQL_SUCCESS && ss != SQL_SUCCESS_WITH_INFO) {
35246439007SCharles.Forsyth fprint(2, "odbcnewconv: SQLAllocHandle failed\n");
35346439007SCharles.Forsyth return -1;
35446439007SCharles.Forsyth }
35546439007SCharles.Forsyth return 0;
35646439007SCharles.Forsyth }
35746439007SCharles.Forsyth
35846439007SCharles.Forsyth void
odbcfreeconv(Conv * c)35946439007SCharles.Forsyth odbcfreeconv(Conv *c)
36046439007SCharles.Forsyth {
36146439007SCharles.Forsyth int ss;
36246439007SCharles.Forsyth
36346439007SCharles.Forsyth odbcdisconnect(c);
36446439007SCharles.Forsyth ss = SQLFreeHandle(SQL_HANDLE_DBC, c->c.h);
36546439007SCharles.Forsyth if (ss != SQL_SUCCESS && ss != SQL_SUCCESS_WITH_INFO)
36646439007SCharles.Forsyth fprint(2, "odbcfreeconv: SQLFreeHandle failed\n");
36746439007SCharles.Forsyth }
36846439007SCharles.Forsyth
36946439007SCharles.Forsyth /* Free up all memory used in the last query */
37046439007SCharles.Forsyth void
freestat(Stmt * s)37146439007SCharles.Forsyth freestat(Stmt *s)
37246439007SCharles.Forsyth {
37346439007SCharles.Forsyth int i;
37446439007SCharles.Forsyth if (s->ncols == 0)
37546439007SCharles.Forsyth return;
37646439007SCharles.Forsyth for(i=0; i<s->ncols; i++){
37746439007SCharles.Forsyth Column *d = &s->rec[i];
37846439007SCharles.Forsyth xfree(d->data, "freestat - data");
37946439007SCharles.Forsyth }
38046439007SCharles.Forsyth xfree(s->cols, "freestat - cols");
38146439007SCharles.Forsyth s->cols = 0;
38246439007SCharles.Forsyth xfree(s->rec, "freestat - rec");
38346439007SCharles.Forsyth s->rec = 0;
38446439007SCharles.Forsyth xfree(s->headstr, "freestat - headstr");
38546439007SCharles.Forsyth s->headstr = 0;
38646439007SCharles.Forsyth s->ncols = 0;
38746439007SCharles.Forsyth }
38846439007SCharles.Forsyth
38946439007SCharles.Forsyth
39046439007SCharles.Forsyth /* build an array describing the columns */
39146439007SCharles.Forsyth int
mkcols(Conv * c,char * ename)39246439007SCharles.Forsyth mkcols(Conv *c, char *ename)
39346439007SCharles.Forsyth {
39446439007SCharles.Forsyth Stmt *s;
39546439007SCharles.Forsyth int rv, i, err, hsize;
39646439007SCharles.Forsyth ushort ignore;
39746439007SCharles.Forsyth char *p;
39846439007SCharles.Forsyth
39946439007SCharles.Forsyth s = &c->s;
40046439007SCharles.Forsyth s->ncols = 0;
40146439007SCharles.Forsyth rv = SQLNumResultCols(s->h, &s->ncols);
40246439007SCharles.Forsyth if (sqlerr(c, rv, ename, "mkcols", "SQLNumResultCols"))
40346439007SCharles.Forsyth return -1;
40446439007SCharles.Forsyth s->cols = xmalloc(s->ncols*sizeof(Coltype));
40546439007SCharles.Forsyth err = 0;
40646439007SCharles.Forsyth hsize = 0;
40746439007SCharles.Forsyth for(i=0; i<s->ncols; i++){
40846439007SCharles.Forsyth Coltype *t = &s->cols[i];
40946439007SCharles.Forsyth rv = SQLDescribeCol(s->h, i+1, t->name, sizeof(t->name), &ignore, &t->type, &t->size, &t->digits, &t->nulls);
41046439007SCharles.Forsyth if (sqlerr(c, rv, ename, "mkcols", "SQLDescribeCol"))
41146439007SCharles.Forsyth err++;
41246439007SCharles.Forsyth if(t->size == 0 || t->size > MSGMAX) /* odbc should return 0 if size not available, not -1 */
41346439007SCharles.Forsyth t->size = DEFCOLSIZE;
41446439007SCharles.Forsyth hsize += strlen(t->name) + 1;
41546439007SCharles.Forsyth }
41646439007SCharles.Forsyth if (c->headings) {
41746439007SCharles.Forsyth hsize += 2;
41846439007SCharles.Forsyth s->headstr = xmalloc(hsize);
41946439007SCharles.Forsyth p = s->headstr;
42046439007SCharles.Forsyth for(i=0; i<s->ncols; i++) {
42146439007SCharles.Forsyth Coltype *t = &s->cols[i];
42246439007SCharles.Forsyth p += sprint(p, "%s%c", t->name, c->out.fs);
42346439007SCharles.Forsyth }
42446439007SCharles.Forsyth p[-1] = c->out.rs;
42546439007SCharles.Forsyth } else
42646439007SCharles.Forsyth s->headstr = 0;
42746439007SCharles.Forsyth return (err ? -1 : 0);
42846439007SCharles.Forsyth }
42946439007SCharles.Forsyth
43046439007SCharles.Forsyth /* build a record to hold `fetched' results */
43146439007SCharles.Forsyth int
mkrec(Conv * c,char * ename)43246439007SCharles.Forsyth mkrec(Conv *c, char *ename)
43346439007SCharles.Forsyth {
43446439007SCharles.Forsyth Stmt *s;
43546439007SCharles.Forsyth int rv, i;
43646439007SCharles.Forsyth
43746439007SCharles.Forsyth s = &c->s;
43846439007SCharles.Forsyth s->rec = xmalloc(s->ncols*sizeof(Column));
43946439007SCharles.Forsyth for(i=0; i<s->ncols; i++){
44046439007SCharles.Forsyth Coltype *t = &s->cols[i];
44146439007SCharles.Forsyth Column *d = &s->rec[i];
44246439007SCharles.Forsyth if (ODebug)
44346439007SCharles.Forsyth print("Column %d size=%ud type=%hd\n", i, t->size, t->type);
44446439007SCharles.Forsyth d->data = xmalloc(t->size+1); /* expects to zero terminate */
44546439007SCharles.Forsyth rv = SQLBindCol(s->h, i+1, SQL_C_CHAR, d->data, t->size+1, &d->len);
44646439007SCharles.Forsyth if (sqlerr(c, rv, ename, "mkrec", "SQLBindCol"))
44746439007SCharles.Forsyth return -1;
44846439007SCharles.Forsyth }
44946439007SCharles.Forsyth return 0;
45046439007SCharles.Forsyth }
45146439007SCharles.Forsyth
45246439007SCharles.Forsyth int
rowcount(Conv * c,char * ename)45346439007SCharles.Forsyth rowcount(Conv *c, char *ename)
45446439007SCharles.Forsyth {
45546439007SCharles.Forsyth Stmt *s;
45646439007SCharles.Forsyth int rv;
45746439007SCharles.Forsyth
45846439007SCharles.Forsyth s = &c->s;
45946439007SCharles.Forsyth s->nrows = 0;
46046439007SCharles.Forsyth rv = SQLRowCount(s->h, &s->nrows);
46146439007SCharles.Forsyth if (sqlerr(c, rv, ename, "rowcount", "SQLRowCount"))
46246439007SCharles.Forsyth return -1;
46346439007SCharles.Forsyth return 0;
46446439007SCharles.Forsyth }
46546439007SCharles.Forsyth
46646439007SCharles.Forsyth int
odbcfetch(Conv * c,char * ename)46746439007SCharles.Forsyth odbcfetch(Conv *c, char *ename)
46846439007SCharles.Forsyth {
46946439007SCharles.Forsyth Stmt *s = &c->s;
47046439007SCharles.Forsyth int rv;
47146439007SCharles.Forsyth
47246439007SCharles.Forsyth rv = SQLFetch(s->h);
47346439007SCharles.Forsyth if(rv == SQL_NO_DATA) {
47446439007SCharles.Forsyth freestat(s);
47546439007SCharles.Forsyth return 0;
47646439007SCharles.Forsyth }
47746439007SCharles.Forsyth if (sqlerr(c, rv, ename, "odbcfetch", "SQLFetch")) {
47846439007SCharles.Forsyth freestat(s);
47946439007SCharles.Forsyth return -1;
48046439007SCharles.Forsyth }
48146439007SCharles.Forsyth return 1;
48246439007SCharles.Forsyth }
48346439007SCharles.Forsyth
48446439007SCharles.Forsyth int
odbcresults(Conv * c,char * ename)48546439007SCharles.Forsyth odbcresults(Conv *c, char *ename)
48646439007SCharles.Forsyth {
48746439007SCharles.Forsyth if(mkcols(c, ename))
48846439007SCharles.Forsyth return -1;
48946439007SCharles.Forsyth if(mkrec(c, ename))
49046439007SCharles.Forsyth return -1;
49146439007SCharles.Forsyth if(rowcount(c, ename))
49246439007SCharles.Forsyth return -1;
49346439007SCharles.Forsyth return 0;
49446439007SCharles.Forsyth }
49546439007SCharles.Forsyth
49646439007SCharles.Forsyth void
struncate(char * s,long * len)49746439007SCharles.Forsyth struncate(char *s, long *len)
49846439007SCharles.Forsyth {
49946439007SCharles.Forsyth long i;
50046439007SCharles.Forsyth for (i=0; i<*len; i++)
50146439007SCharles.Forsyth if (s[i] == 0) {
50246439007SCharles.Forsyth *len = i;
50346439007SCharles.Forsyth return;
50446439007SCharles.Forsyth }
50546439007SCharles.Forsyth }
50646439007SCharles.Forsyth
50746439007SCharles.Forsyth void
fix_delim(char * p,int len,char delim)50846439007SCharles.Forsyth fix_delim(char *p, int len, char delim)
50946439007SCharles.Forsyth {
51046439007SCharles.Forsyth int i;
51146439007SCharles.Forsyth for (i=0; i<len; i++)
51246439007SCharles.Forsyth if (p[i] == delim)
51346439007SCharles.Forsyth p[i] = '\\';
51446439007SCharles.Forsyth }
51546439007SCharles.Forsyth
51646439007SCharles.Forsyth long
odbcdataread(Conv * c,void * a,long n,ulong offset,char * ename)51746439007SCharles.Forsyth odbcdataread(Conv *c, void *a, long n, ulong offset, char *ename)
51846439007SCharles.Forsyth {
51946439007SCharles.Forsyth Stmt *s = &c->s;
52046439007SCharles.Forsyth int i, r;
52146439007SCharles.Forsyth long left;
52246439007SCharles.Forsyth char *p, *lastp;
52346439007SCharles.Forsyth
52446439007SCharles.Forsyth if(c->c.connected == 0){
52546439007SCharles.Forsyth strcpy(ename, Enoconnect);
52646439007SCharles.Forsyth return -1;
52746439007SCharles.Forsyth }
52846439007SCharles.Forsyth if (s->cols == 0 || s->rec == 0)
529*ea0789e7SCharles.Forsyth return 0;
53046439007SCharles.Forsyth p = a;
53146439007SCharles.Forsyth left = n;
53246439007SCharles.Forsyth if (c->headings) {
53346439007SCharles.Forsyth r = strlen(s->headstr);
53446439007SCharles.Forsyth if (r && offset < r) {
53546439007SCharles.Forsyth memcpy(p, s->headstr+offset, r-offset);
53646439007SCharles.Forsyth p += r-offset;
53746439007SCharles.Forsyth left -= r-offset;
53846439007SCharles.Forsyth return n-left;
53946439007SCharles.Forsyth }
54046439007SCharles.Forsyth }
54146439007SCharles.Forsyth if((r=odbcfetch(c, ename)) < 0)
54246439007SCharles.Forsyth return -1;
54346439007SCharles.Forsyth if(r == 0)
54446439007SCharles.Forsyth return 0;
54546439007SCharles.Forsyth for(i=0; i<s->ncols; i++){
54646439007SCharles.Forsyth Coltype *t = &s->cols[i];
54746439007SCharles.Forsyth Column *d = &s->rec[i];
54846439007SCharles.Forsyth if (ODebug)
54946439007SCharles.Forsyth fprint(2, "Col %d Returned data len=%d\n", i, d->len);
55046439007SCharles.Forsyth if(d->len <= 0) /* SQL_NULL_DATA or strange error! */
55146439007SCharles.Forsyth d->len = 0;
55246439007SCharles.Forsyth if (d->len > t->size+1)
55346439007SCharles.Forsyth d->len = t->size+1;
55446439007SCharles.Forsyth if(left <= d->len+1) /* whole fields */
55546439007SCharles.Forsyth break;
55646439007SCharles.Forsyth struncate(d->data, &d->len); /* assume string data and stop on an embedded null */
55746439007SCharles.Forsyth memcpy(p, d->data, d->len);
55846439007SCharles.Forsyth lastp = p;
55946439007SCharles.Forsyth left -= d->len;
56046439007SCharles.Forsyth p += d->len;
56146439007SCharles.Forsyth fix_delim(lastp, d->len, '\n');
56246439007SCharles.Forsyth switch(c->out.style){
56346439007SCharles.Forsyth case Float:
56446439007SCharles.Forsyth fix_delim(lastp, d->len, c->out.fs);
56546439007SCharles.Forsyth *p++ = (i==s->ncols-1)? c->out.rs: c->out.fs;
56646439007SCharles.Forsyth left--;
56746439007SCharles.Forsyth break;
56846439007SCharles.Forsyth case Fixed:
56946439007SCharles.Forsyth r = t->size - d->len;
57046439007SCharles.Forsyth if(r < 0)
57146439007SCharles.Forsyth r = 0;
57246439007SCharles.Forsyth if(left < r)
57346439007SCharles.Forsyth r = left;
57446439007SCharles.Forsyth memset(p, ' ', r);
57546439007SCharles.Forsyth left -= r;
57646439007SCharles.Forsyth p += r;
57746439007SCharles.Forsyth break;
57846439007SCharles.Forsyth }
57946439007SCharles.Forsyth }
58046439007SCharles.Forsyth if (left < 0)
58146439007SCharles.Forsyth fprint(2, "*** left<0 n=%d left=%d\n", n, left);
58246439007SCharles.Forsyth return n-left;
58346439007SCharles.Forsyth }
58446439007SCharles.Forsyth
58546439007SCharles.Forsyth /*
58646439007SCharles.Forsyth * Returns a description of the format of a fixed width output
58746439007SCharles.Forsyth * record. `start' is the offset of the first character in the field.
58846439007SCharles.Forsyth * `end' is one greater than the offset of the last character of the field.
58946439007SCharles.Forsyth * `name' is the column name (which may contain spaces).
59046439007SCharles.Forsyth * `start' and `end' are terminated with a space, `name' with a newline.
59146439007SCharles.Forsyth * return 1 record containing one line for each field in the output:
59246439007SCharles.Forsyth * start1 end1 name1\n
59346439007SCharles.Forsyth * start2 end2 name2\n
59446439007SCharles.Forsyth * ....
59546439007SCharles.Forsyth */
59646439007SCharles.Forsyth long
odbcfmtread(Conv * c,void * a,long n,ulong offset,char * ename)59746439007SCharles.Forsyth odbcfmtread(Conv *c, void *a, long n, ulong offset, char *ename)
59846439007SCharles.Forsyth {
59946439007SCharles.Forsyth Stmt *s = &c->s;
60046439007SCharles.Forsyth int i, len;
60146439007SCharles.Forsyth long left, off;
60246439007SCharles.Forsyth char *p;
60346439007SCharles.Forsyth char buf[100];
60446439007SCharles.Forsyth
60546439007SCharles.Forsyth if(offset > 0)
60646439007SCharles.Forsyth return 0;
60746439007SCharles.Forsyth p = a;
60846439007SCharles.Forsyth left = n;
60946439007SCharles.Forsyth off = 0;
61046439007SCharles.Forsyth for(i=0; i<s->ncols; i++){
61146439007SCharles.Forsyth Coltype *t = &s->cols[i];
61246439007SCharles.Forsyth
613*ea0789e7SCharles.Forsyth len = snprint(buf, sizeof(buf), "%ld %ld %s\n", off, off+t->size, t->name);
61446439007SCharles.Forsyth off += t->size;
61546439007SCharles.Forsyth if(left < len)
61646439007SCharles.Forsyth break;
61746439007SCharles.Forsyth memcpy(p, buf, len);
61846439007SCharles.Forsyth left -= len;
61946439007SCharles.Forsyth p += len;
62046439007SCharles.Forsyth
62146439007SCharles.Forsyth }
62246439007SCharles.Forsyth return n-left;
62346439007SCharles.Forsyth }
62446439007SCharles.Forsyth
62546439007SCharles.Forsyth int
odbctables(Conv * c,char * ename)62646439007SCharles.Forsyth odbctables(Conv *c, char *ename)
62746439007SCharles.Forsyth {
62846439007SCharles.Forsyth int rv;
62946439007SCharles.Forsyth
63046439007SCharles.Forsyth if(c->c.connected == 0){
63146439007SCharles.Forsyth strcpy(ename, Enoconnect);
63246439007SCharles.Forsyth return -1;
63346439007SCharles.Forsyth }
63446439007SCharles.Forsyth rv = SQLCloseCursor(c->s.h);
63546439007SCharles.Forsyth rv = SQLTables(c->s.h, 0, 0, 0, 0, 0, 0, 0, 0);
63646439007SCharles.Forsyth if (sqlerr(c, rv, ename, "odbctables", "SQLTables"))
63746439007SCharles.Forsyth return -1;
63846439007SCharles.Forsyth if(odbcresults(c, ename))
63946439007SCharles.Forsyth return -1;
64046439007SCharles.Forsyth return 0;
64146439007SCharles.Forsyth }
64246439007SCharles.Forsyth
64346439007SCharles.Forsyth int
odbccolumns(Conv * c,char * table,char * ename)64446439007SCharles.Forsyth odbccolumns(Conv *c, char *table, char *ename)
64546439007SCharles.Forsyth {
64646439007SCharles.Forsyth int rv;
64746439007SCharles.Forsyth
64846439007SCharles.Forsyth if(c->c.connected == 0){
64946439007SCharles.Forsyth strcpy(ename, Enoconnect);
65046439007SCharles.Forsyth return -1;
65146439007SCharles.Forsyth }
65246439007SCharles.Forsyth rv = SQLCloseCursor(c->s.h);
65346439007SCharles.Forsyth rv = SQLColumns(c->s.h, 0, 0, 0, 0, table, strlen(table), 0, 0);
65446439007SCharles.Forsyth if (sqlerr(c, rv, ename, "odbccolumns", "SQLColumns"))
65546439007SCharles.Forsyth return -1;
65646439007SCharles.Forsyth if(odbcresults(c, ename))
65746439007SCharles.Forsyth return -1;
65846439007SCharles.Forsyth return 0;
65946439007SCharles.Forsyth }
66046439007SCharles.Forsyth
66146439007SCharles.Forsyth int
odbcexec(Conv * c,char * cmd,int cmdlen,char * ename)66246439007SCharles.Forsyth odbcexec(Conv *c, char *cmd, int cmdlen, char *ename)
66346439007SCharles.Forsyth {
66446439007SCharles.Forsyth int rv;
66546439007SCharles.Forsyth
66646439007SCharles.Forsyth if(c->c.connected == 0){
66746439007SCharles.Forsyth strcpy(ename, Enoconnect);
66846439007SCharles.Forsyth return -1;
66946439007SCharles.Forsyth }
67046439007SCharles.Forsyth SQLCloseCursor(c->s.h);
67146439007SCharles.Forsyth rv = SQLExecDirect(c->s.h, cmd, cmdlen);
67246439007SCharles.Forsyth if (sqlerr(c, rv, ename, "odbcexec", "SQLExecDirect"))
67346439007SCharles.Forsyth return -1;
67446439007SCharles.Forsyth if(odbcresults(c, ename))
67546439007SCharles.Forsyth return -1;
67646439007SCharles.Forsyth return 0;
67746439007SCharles.Forsyth }
67846439007SCharles.Forsyth
67946439007SCharles.Forsyth int
odbctrans(Conv * c,char * cmd,char * ename)68046439007SCharles.Forsyth odbctrans(Conv *c, char *cmd, char *ename)
68146439007SCharles.Forsyth {
68246439007SCharles.Forsyth int rv;
68346439007SCharles.Forsyth
68446439007SCharles.Forsyth if(strcmp(cmd, "auto") == 0){
68546439007SCharles.Forsyth rv = SQLSetConnectAttr(c->c.h, SQL_ATTR_AUTOCOMMIT, (char*)SQL_AUTOCOMMIT_ON, 0);
68646439007SCharles.Forsyth } else if(strcmp(cmd, "begin") == 0){
68746439007SCharles.Forsyth rv = SQLSetConnectAttr(c->c.h, SQL_ATTR_AUTOCOMMIT, (char*)SQL_AUTOCOMMIT_OFF, 0);
68846439007SCharles.Forsyth } else if(strcmp(cmd, "commit") == 0){
68946439007SCharles.Forsyth rv = SQLEndTran(SQL_HANDLE_DBC, c->c.h, SQL_COMMIT);
69046439007SCharles.Forsyth } else if(strcmp(cmd, "rollback") == 0){
69146439007SCharles.Forsyth rv = SQLEndTran(SQL_HANDLE_DBC, c->c.h, SQL_ROLLBACK);
69246439007SCharles.Forsyth } else {
69346439007SCharles.Forsyth strcpy(ename, Ebadarg);
69446439007SCharles.Forsyth return -1;
69546439007SCharles.Forsyth }
69646439007SCharles.Forsyth if (sqlerr(c, rv, ename, "odbctrans", "SQLSetConnectAttr/SQLEndTran"))
69746439007SCharles.Forsyth return -1;
69846439007SCharles.Forsyth return 0;
69946439007SCharles.Forsyth }
70046439007SCharles.Forsyth
70146439007SCharles.Forsyth int
readstr(ulong off,char * buf,ulong n,char * str)70246439007SCharles.Forsyth readstr(ulong off, char *buf, ulong n, char *str)
70346439007SCharles.Forsyth {
70446439007SCharles.Forsyth int size;
70546439007SCharles.Forsyth
70646439007SCharles.Forsyth size = strlen(str);
70746439007SCharles.Forsyth if(off >= size)
70846439007SCharles.Forsyth return 0;
70946439007SCharles.Forsyth if(off+n > size)
71046439007SCharles.Forsyth n = size-off;
71146439007SCharles.Forsyth memmove(buf, str+off, n);
71246439007SCharles.Forsyth return n;
71346439007SCharles.Forsyth }
71446439007SCharles.Forsyth
71546439007SCharles.Forsyth static void
newproto(char * name,int maxconv)71646439007SCharles.Forsyth newproto(char *name, int maxconv)
71746439007SCharles.Forsyth {
71846439007SCharles.Forsyth int l;
71946439007SCharles.Forsyth Proto *p;
72046439007SCharles.Forsyth
72146439007SCharles.Forsyth if(np >= MAXPROTO) {
72246439007SCharles.Forsyth print("no %s: increase MAXPROTO", name);
72346439007SCharles.Forsyth return;
72446439007SCharles.Forsyth }
72546439007SCharles.Forsyth
72646439007SCharles.Forsyth p = &proto[np];
72746439007SCharles.Forsyth p->name = strdup(name);
72846439007SCharles.Forsyth p->qid.path = QID(np, 0, Qprotodir);
72946439007SCharles.Forsyth p->qid.type = QTDIR;
73046439007SCharles.Forsyth p->x = np++;
73146439007SCharles.Forsyth p->maxconv = maxconv;
73246439007SCharles.Forsyth l = sizeof(Conv*)*(p->maxconv+1);
73346439007SCharles.Forsyth p->conv = xmalloc(l);
73446439007SCharles.Forsyth if(p->conv == 0)
73546439007SCharles.Forsyth fatal("no memory");
73646439007SCharles.Forsyth memset(p->conv, 0, l);
73746439007SCharles.Forsyth }
73846439007SCharles.Forsyth
73946439007SCharles.Forsyth char*
openmode(int * o)74046439007SCharles.Forsyth openmode(int *o)
74146439007SCharles.Forsyth {
74246439007SCharles.Forsyth if(*o >= (OTRUNC|OCEXEC|ORCLOSE|OEXEC)){
74346439007SCharles.Forsyth return Ebadarg;
74446439007SCharles.Forsyth }
74546439007SCharles.Forsyth *o &= ~(OTRUNC|OCEXEC|ORCLOSE);
74646439007SCharles.Forsyth if(*o > OEXEC){
74746439007SCharles.Forsyth return Ebadarg;
74846439007SCharles.Forsyth }
74946439007SCharles.Forsyth if(*o == OEXEC)
75046439007SCharles.Forsyth *o = OREAD;
75146439007SCharles.Forsyth return nil;
75246439007SCharles.Forsyth }
75346439007SCharles.Forsyth
75446439007SCharles.Forsyth static Conv*
protoclone(Proto * p,char * user)75546439007SCharles.Forsyth protoclone(Proto *p, char *user)
75646439007SCharles.Forsyth {
75746439007SCharles.Forsyth Conv *c, **pp, **ep;
75846439007SCharles.Forsyth uvlong nr;
75946439007SCharles.Forsyth char buf[16];
76046439007SCharles.Forsyth
76146439007SCharles.Forsyth c = 0;
76246439007SCharles.Forsyth ep = &p->conv[p->maxconv];
76346439007SCharles.Forsyth for(pp = p->conv; pp < ep; pp++) {
76446439007SCharles.Forsyth c = *pp;
76546439007SCharles.Forsyth if(c == 0) {
76646439007SCharles.Forsyth c = xmalloc(sizeof(Conv));
76746439007SCharles.Forsyth if(c == 0)
76846439007SCharles.Forsyth return 0;
76946439007SCharles.Forsyth c->ref = 1;
77046439007SCharles.Forsyth c->p = p;
77146439007SCharles.Forsyth c->x = pp - p->conv;
77246439007SCharles.Forsyth p->nc++;
77346439007SCharles.Forsyth *pp = c;
77446439007SCharles.Forsyth break;
77546439007SCharles.Forsyth }
77646439007SCharles.Forsyth if(c->ref == 0) {
77746439007SCharles.Forsyth c->ref++;
77846439007SCharles.Forsyth break;
77946439007SCharles.Forsyth }
78046439007SCharles.Forsyth }
78146439007SCharles.Forsyth if(pp >= ep)
78246439007SCharles.Forsyth return 0;
78346439007SCharles.Forsyth
78446439007SCharles.Forsyth c->owner = strdup(user);
78546439007SCharles.Forsyth c->perm = 0660;
78646439007SCharles.Forsyth c->state = "Open";
78746439007SCharles.Forsyth c->out = defoutput;
78846439007SCharles.Forsyth c->headings = 0;
78946439007SCharles.Forsyth c->errmsg[0] = 0;
79046439007SCharles.Forsyth
79146439007SCharles.Forsyth nr = QID(0, c->x, Qconvdir);
792*ea0789e7SCharles.Forsyth snprint(buf, sizeof(buf), "%d", c->x);
79346439007SCharles.Forsyth styxadddir(iserver, Qprotodir, nr, buf, 0555, c->owner);
79446439007SCharles.Forsyth styxaddfile(iserver, nr, QID(0, c->x, Qcmd), "cmd", c->perm, c->owner);
79546439007SCharles.Forsyth styxaddfile(iserver, nr, QID(0, c->x, Qctl), "ctl", c->perm, c->owner);
79646439007SCharles.Forsyth styxaddfile(iserver, nr, QID(0, c->x, Qdata), "data", c->perm, c->owner);
79746439007SCharles.Forsyth styxaddfile(iserver, nr, QID(0, c->x, Qerror), "error", c->perm, c->owner);
79846439007SCharles.Forsyth styxaddfile(iserver, nr, QID(0, c->x, Qformat), "format", c->perm, c->owner);
79946439007SCharles.Forsyth styxaddfile(iserver, nr, QID(0, c->x, Qsources), "sources", c->perm, c->owner);
80046439007SCharles.Forsyth styxaddfile(iserver, nr, QID(0, c->x, Qstatus), "status", 0444, c->owner);
80146439007SCharles.Forsyth
80246439007SCharles.Forsyth return c;
80346439007SCharles.Forsyth }
80446439007SCharles.Forsyth
80546439007SCharles.Forsyth char*
dbopen(Qid * qid,int omode)80646439007SCharles.Forsyth dbopen(Qid *qid, int omode)
80746439007SCharles.Forsyth {
80846439007SCharles.Forsyth Proto *p;
80946439007SCharles.Forsyth int perm;
81046439007SCharles.Forsyth Conv *cv;
81146439007SCharles.Forsyth char *user;
81246439007SCharles.Forsyth Qid q;
81346439007SCharles.Forsyth Client *c;
81446439007SCharles.Forsyth
81546439007SCharles.Forsyth q = *qid;
81646439007SCharles.Forsyth c = styxclient(iserver);
81746439007SCharles.Forsyth
81846439007SCharles.Forsyth perm = 0;
81946439007SCharles.Forsyth omode &= 3;
82046439007SCharles.Forsyth switch(omode) {
82146439007SCharles.Forsyth case OREAD:
82246439007SCharles.Forsyth perm = 4;
82346439007SCharles.Forsyth break;
82446439007SCharles.Forsyth case OWRITE:
82546439007SCharles.Forsyth perm = 2;
82646439007SCharles.Forsyth break;
82746439007SCharles.Forsyth case ORDWR:
82846439007SCharles.Forsyth perm = 6;
82946439007SCharles.Forsyth break;
83046439007SCharles.Forsyth }
83146439007SCharles.Forsyth
83246439007SCharles.Forsyth switch(TYPE(q)) {
83346439007SCharles.Forsyth default:
83446439007SCharles.Forsyth break;
83546439007SCharles.Forsyth case Qtopdir:
83646439007SCharles.Forsyth case Qprotodir:
83746439007SCharles.Forsyth case Qconvdir:
83846439007SCharles.Forsyth case Qstatus:
83946439007SCharles.Forsyth case Qformat:
84046439007SCharles.Forsyth case Qsources:
84146439007SCharles.Forsyth case Qerror:
84246439007SCharles.Forsyth if(omode != OREAD){
84346439007SCharles.Forsyth return Eperm;
84446439007SCharles.Forsyth }
84546439007SCharles.Forsyth break;
84646439007SCharles.Forsyth case Qclonus:
84746439007SCharles.Forsyth p = &proto[PROTO(q)];
848a60fa48cSCharles.Forsyth cv = protoclone(p, c->uname);
84946439007SCharles.Forsyth if(cv == 0){
85046439007SCharles.Forsyth return Enodev;
85146439007SCharles.Forsyth }
85246439007SCharles.Forsyth qid->path = QID(p->x, cv->x, Qctl);
85346439007SCharles.Forsyth qid->type = 0;
85446439007SCharles.Forsyth qid->vers = 0;
85546439007SCharles.Forsyth if(odbcnewconv(c, cv) != 0){
85646439007SCharles.Forsyth return Eodbcalloc;
85746439007SCharles.Forsyth }
85846439007SCharles.Forsyth break;
85946439007SCharles.Forsyth case Qdata:
86046439007SCharles.Forsyth case Qcmd:
86146439007SCharles.Forsyth case Qctl:
86246439007SCharles.Forsyth p = &proto[PROTO(q)];
86346439007SCharles.Forsyth cv = p->conv[CONV(q)];
864a60fa48cSCharles.Forsyth user = c->uname;
86546439007SCharles.Forsyth if((perm & (cv->perm>>6)) != perm) {
86646439007SCharles.Forsyth if(strcmp(user, cv->owner) != 0 ||
86746439007SCharles.Forsyth (perm & cv->perm) != perm) {
86846439007SCharles.Forsyth return Eperm;
86946439007SCharles.Forsyth }
87046439007SCharles.Forsyth }
87146439007SCharles.Forsyth cv->ref++;
87246439007SCharles.Forsyth if(cv->ref == 1) {
87346439007SCharles.Forsyth cv->state = "Open";
87446439007SCharles.Forsyth cv->owner = strdup(user);
87546439007SCharles.Forsyth cv->perm = 0660;
87646439007SCharles.Forsyth if(odbcnewconv(c, cv) != 0){
87746439007SCharles.Forsyth return Eodbcalloc;
87846439007SCharles.Forsyth }
87946439007SCharles.Forsyth }
88046439007SCharles.Forsyth break;
88146439007SCharles.Forsyth }
88246439007SCharles.Forsyth return openmode(&omode);
88346439007SCharles.Forsyth }
88446439007SCharles.Forsyth
88546439007SCharles.Forsyth char*
dbclose(Qid qid,int mode)88646439007SCharles.Forsyth dbclose(Qid qid, int mode)
88746439007SCharles.Forsyth {
88846439007SCharles.Forsyth Conv *cc;
88946439007SCharles.Forsyth
89046439007SCharles.Forsyth USED(mode);
89146439007SCharles.Forsyth switch(TYPE(qid)) {
89246439007SCharles.Forsyth case Qctl:
89346439007SCharles.Forsyth case Qcmd:
89446439007SCharles.Forsyth case Qdata:
89546439007SCharles.Forsyth cc = proto[PROTO(qid)].conv[CONV(qid)];
89646439007SCharles.Forsyth if(--cc->ref != 0)
89746439007SCharles.Forsyth break;
89846439007SCharles.Forsyth cc->owner = inferno;
89946439007SCharles.Forsyth cc->perm = 0666;
90046439007SCharles.Forsyth cc->state = "Closed";
90146439007SCharles.Forsyth odbcfreeconv(cc);
90246439007SCharles.Forsyth styxrmfile(iserver, QID(0, cc->x, Qconvdir));
90346439007SCharles.Forsyth break;
90446439007SCharles.Forsyth }
90546439007SCharles.Forsyth return nil;
90646439007SCharles.Forsyth }
90746439007SCharles.Forsyth
908*ea0789e7SCharles.Forsyth static char ebuf[ERRMAX];
90946439007SCharles.Forsyth
91046439007SCharles.Forsyth char*
dbread(Qid qid,char * ba,ulong * n,vlong offset)91146439007SCharles.Forsyth dbread(Qid qid, char *ba, ulong *n, vlong offset)
91246439007SCharles.Forsyth {
91346439007SCharles.Forsyth uchar *a = ba;
91446439007SCharles.Forsyth Conv *c;
91546439007SCharles.Forsyth Proto *x;
91646439007SCharles.Forsyth char buf[128], *p, *s;
91746439007SCharles.Forsyth long r;
91846439007SCharles.Forsyth ulong m;
91946439007SCharles.Forsyth
92046439007SCharles.Forsyth m = *n;
92146439007SCharles.Forsyth ebuf[0] = 0;
92246439007SCharles.Forsyth p = a;
92346439007SCharles.Forsyth switch(TYPE(qid)) {
92446439007SCharles.Forsyth default:
92546439007SCharles.Forsyth return Eperm;
92646439007SCharles.Forsyth case Qnclients:
92746439007SCharles.Forsyth snprint(buf, sizeof(buf), "%d\n", nclients);
92846439007SCharles.Forsyth *n = readstr(offset, p, m, buf);
92946439007SCharles.Forsyth return nil;
93046439007SCharles.Forsyth case Qprotodir:
93146439007SCharles.Forsyth case Qtopdir:
93246439007SCharles.Forsyth case Qconvdir:
93346439007SCharles.Forsyth return "bad read of directory";
93446439007SCharles.Forsyth case Qctl:
935*ea0789e7SCharles.Forsyth snprint(buf, sizeof(buf), "%ld", CONV(qid));
93646439007SCharles.Forsyth *n = readstr(offset, p, m, buf);
93746439007SCharles.Forsyth return nil;
93846439007SCharles.Forsyth case Qstatus:
93946439007SCharles.Forsyth x = &proto[PROTO(qid)];
94046439007SCharles.Forsyth c = x->conv[CONV(qid)];
94146439007SCharles.Forsyth snprint(buf, sizeof(buf), "%s/%d %ld %s %s\n",
94246439007SCharles.Forsyth c->p->name, c->x, c->ref, c->state, "");
94346439007SCharles.Forsyth *n = readstr(offset, p, m, buf);
94446439007SCharles.Forsyth return nil;
94546439007SCharles.Forsyth case Qdata:
94646439007SCharles.Forsyth c = proto[PROTO(qid)].conv[CONV(qid)];
94746439007SCharles.Forsyth *n = odbcdataread(c, a, m, offset, ebuf);
94846439007SCharles.Forsyth if(ebuf[0] != 0)
94946439007SCharles.Forsyth return ebuf;
95046439007SCharles.Forsyth return nil;
95146439007SCharles.Forsyth case Qformat:
95246439007SCharles.Forsyth c = proto[PROTO(qid)].conv[CONV(qid)];
95346439007SCharles.Forsyth *n = odbcfmtread(c, a, m, offset, ebuf);
95446439007SCharles.Forsyth if(ebuf[0] != 0)
95546439007SCharles.Forsyth return ebuf;
95646439007SCharles.Forsyth return nil;
95746439007SCharles.Forsyth case Qerror:
95846439007SCharles.Forsyth c = proto[PROTO(qid)].conv[CONV(qid)];
95946439007SCharles.Forsyth *n = readstr(offset, p, m, odbcerror(c, 1));
96046439007SCharles.Forsyth return nil;
96146439007SCharles.Forsyth case Qsources:
96246439007SCharles.Forsyth c = proto[PROTO(qid)].conv[CONV(qid)];
96346439007SCharles.Forsyth s = odbcsources(styxclient(iserver));
96446439007SCharles.Forsyth r = readstr(offset, p, m, s);
96546439007SCharles.Forsyth free(s);
96646439007SCharles.Forsyth *n = r;
96746439007SCharles.Forsyth return nil;
96846439007SCharles.Forsyth }
96946439007SCharles.Forsyth return nil;
97046439007SCharles.Forsyth }
97146439007SCharles.Forsyth
97246439007SCharles.Forsyth char*
dbwrite(Qid qid,char * ba,ulong * n,vlong offset)97346439007SCharles.Forsyth dbwrite(Qid qid, char *ba, ulong *n, vlong offset)
97446439007SCharles.Forsyth {
97546439007SCharles.Forsyth uchar *a = ba;
97646439007SCharles.Forsyth int nf;
97746439007SCharles.Forsyth Conv *c;
97846439007SCharles.Forsyth Proto *x;
97946439007SCharles.Forsyth char *fields[10], buf[512], safebuf[512];
98046439007SCharles.Forsyth ulong m;
98146439007SCharles.Forsyth
98246439007SCharles.Forsyth m = *n;
98346439007SCharles.Forsyth ebuf[0] = 0;
98446439007SCharles.Forsyth switch(TYPE(qid)) {
98546439007SCharles.Forsyth default:
98646439007SCharles.Forsyth return Eperm;
98746439007SCharles.Forsyth case Qctl:
98846439007SCharles.Forsyth x = &proto[PROTO(qid)];
98946439007SCharles.Forsyth c = x->conv[CONV(qid)];
99046439007SCharles.Forsyth //
99146439007SCharles.Forsyth if(m > sizeof(buf)-1)
99246439007SCharles.Forsyth m = sizeof(buf)-1;
99346439007SCharles.Forsyth memmove(buf, a, m);
99446439007SCharles.Forsyth buf[m] = '\0';
99546439007SCharles.Forsyth if (ODebug)
99646439007SCharles.Forsyth fprint(2, "write Qctl: <%s>\n", buf);
99746439007SCharles.Forsyth fields[0] = 0;
99846439007SCharles.Forsyth nf = parsefields(buf, fields, sizeof(fields)/sizeof(*fields), " \n\t");
99946439007SCharles.Forsyth if (nf == 0) {
100046439007SCharles.Forsyth return Ebadarg;
100146439007SCharles.Forsyth }
100246439007SCharles.Forsyth if(strcmp(fields[0], "connect") == 0){ /* connect database [user!auth] */
100346439007SCharles.Forsyth char *afields[2];
100446439007SCharles.Forsyth char *user = "";
100546439007SCharles.Forsyth char *auth = "";
100646439007SCharles.Forsyth switch(nf){
100746439007SCharles.Forsyth default:
100846439007SCharles.Forsyth return Ebadarg;
100946439007SCharles.Forsyth case 2:
101046439007SCharles.Forsyth break;
101146439007SCharles.Forsyth case 3:
101246439007SCharles.Forsyth nf = parsefields(fields[2], afields, 2, "!");
101346439007SCharles.Forsyth switch(nf){
101446439007SCharles.Forsyth case 2:
101546439007SCharles.Forsyth user = afields[0];
101646439007SCharles.Forsyth auth = afields[1];
101746439007SCharles.Forsyth break;
101846439007SCharles.Forsyth case 1:
101946439007SCharles.Forsyth if(fields[2][0] == 0)
102046439007SCharles.Forsyth auth = afields[0];
102146439007SCharles.Forsyth else
102246439007SCharles.Forsyth user = afields[0];
102346439007SCharles.Forsyth break;
102446439007SCharles.Forsyth default:
102546439007SCharles.Forsyth break;
102646439007SCharles.Forsyth }
102746439007SCharles.Forsyth break;
102846439007SCharles.Forsyth }
102946439007SCharles.Forsyth if(odbcconnect(c, fields[1], user, auth, ebuf) < 0)
103046439007SCharles.Forsyth return ebuf;
103146439007SCharles.Forsyth c->state = "Connected";
103246439007SCharles.Forsyth } else if(strcmp(fields[0], "disconnect") == 0){
103346439007SCharles.Forsyth odbcdisconnect(c);
103446439007SCharles.Forsyth c->state = "Disconnected";
103546439007SCharles.Forsyth } else if(strcmp(fields[0], "fixed") == 0){
103646439007SCharles.Forsyth c->out = defoutput;
103746439007SCharles.Forsyth c->out.style = Fixed;
103846439007SCharles.Forsyth } else if(strcmp(fields[0], "float") == 0){
103946439007SCharles.Forsyth c->out = defoutput;
104046439007SCharles.Forsyth c->out.style = Float;
104146439007SCharles.Forsyth if(nf > 1)
104246439007SCharles.Forsyth c->out.fs = fields[1][0];
104346439007SCharles.Forsyth if(nf > 2)
104446439007SCharles.Forsyth c->out.rs = fields[2][0];
104546439007SCharles.Forsyth } else if(strcmp(fields[0], "headings") == 0){
104646439007SCharles.Forsyth c->headings = 1;
104746439007SCharles.Forsyth } else if(strcmp(fields[0], "noheadings") == 0){
104846439007SCharles.Forsyth c->headings = 0;
104946439007SCharles.Forsyth } else if(strcmp(fields[0], "trans") == 0){ /* begin, auto, commit, rollback */
105046439007SCharles.Forsyth if(nf < 2){
105146439007SCharles.Forsyth return Ebadarg;
105246439007SCharles.Forsyth }
105346439007SCharles.Forsyth if(odbctrans(c, fields[1], ebuf) < 0)
105446439007SCharles.Forsyth return ebuf;
105546439007SCharles.Forsyth } else {
105646439007SCharles.Forsyth return Ebadcmd;
105746439007SCharles.Forsyth }
105846439007SCharles.Forsyth *n = m;
105946439007SCharles.Forsyth return nil;
106046439007SCharles.Forsyth case Qcmd:
106146439007SCharles.Forsyth x = &proto[PROTO(qid)];
106246439007SCharles.Forsyth c = x->conv[CONV(qid)];
106346439007SCharles.Forsyth if(m > sizeof(buf)-1)
106446439007SCharles.Forsyth m = sizeof(buf)-1;
106546439007SCharles.Forsyth memmove(buf, a, m);
106646439007SCharles.Forsyth buf[m] = '\0';
106746439007SCharles.Forsyth if (ODebug)
106846439007SCharles.Forsyth fprint(2, "write Qcmd: <%s>\n", buf);
106946439007SCharles.Forsyth memmove(safebuf, a, m);
107046439007SCharles.Forsyth safebuf[m] = '\0';
107146439007SCharles.Forsyth fields[0] = 0;
107246439007SCharles.Forsyth nf = parsefields(buf, fields, 3, " \n\t");
107346439007SCharles.Forsyth if (nf == 0) {
107446439007SCharles.Forsyth return Ebadarg;
107546439007SCharles.Forsyth }
107646439007SCharles.Forsyth if(strcmp(fields[0], "tables") == 0){
107746439007SCharles.Forsyth if(odbctables(c, ebuf))
107846439007SCharles.Forsyth return ebuf;
107946439007SCharles.Forsyth }else if(strcmp(fields[0], "columns") == 0){
108046439007SCharles.Forsyth if(nf < 2){
108146439007SCharles.Forsyth return Ebadarg;
108246439007SCharles.Forsyth }
108346439007SCharles.Forsyth if(odbccolumns(c, &safebuf[strlen(fields[0])+1], ebuf)) /* allow for spaces in table name */
108446439007SCharles.Forsyth return ebuf;
108546439007SCharles.Forsyth } else
108646439007SCharles.Forsyth if (odbcexec(c, a, m, ebuf))
108746439007SCharles.Forsyth return ebuf;
108846439007SCharles.Forsyth *n = m;
108946439007SCharles.Forsyth return nil;
109046439007SCharles.Forsyth case Qdata:
109146439007SCharles.Forsyth return Eperm;
109246439007SCharles.Forsyth }
109346439007SCharles.Forsyth return nil;
109446439007SCharles.Forsyth }
109546439007SCharles.Forsyth
109646439007SCharles.Forsyth void
badusage(void)1097*ea0789e7SCharles.Forsyth badusage(void)
109846439007SCharles.Forsyth {
109946439007SCharles.Forsyth fprint(2, "Usage: odbc [-d] [-p port]\n");
110046439007SCharles.Forsyth exit(1);
110146439007SCharles.Forsyth }
110246439007SCharles.Forsyth
110346439007SCharles.Forsyth Styxops ops = {
110446439007SCharles.Forsyth odbcnewclient, /* newclient */
110546439007SCharles.Forsyth odbcfreeclient, /* freeclient */
110646439007SCharles.Forsyth
110746439007SCharles.Forsyth nil, /* attach */
110846439007SCharles.Forsyth nil, /* walk */
110946439007SCharles.Forsyth dbopen, /* open */
111046439007SCharles.Forsyth nil, /* create */
111146439007SCharles.Forsyth dbread, /* read */
111246439007SCharles.Forsyth dbwrite, /* write */
111346439007SCharles.Forsyth dbclose, /* close */
111446439007SCharles.Forsyth nil, /* remove */
111546439007SCharles.Forsyth nil, /* stat */
111646439007SCharles.Forsyth nil, /* wstat */
111746439007SCharles.Forsyth };
111846439007SCharles.Forsyth
111946439007SCharles.Forsyth void
main(int argc,char * argv[])112046439007SCharles.Forsyth main(int argc, char *argv[])
112146439007SCharles.Forsyth {
112246439007SCharles.Forsyth Styxserver s;
112346439007SCharles.Forsyth
112446439007SCharles.Forsyth ARGBEGIN {
112546439007SCharles.Forsyth default:
112646439007SCharles.Forsyth badusage();
112746439007SCharles.Forsyth case 'd': /* Debug */
112846439007SCharles.Forsyth ODebug = 1;
112946439007SCharles.Forsyth styxdebug();
113046439007SCharles.Forsyth break;
113146439007SCharles.Forsyth case 'p': /* Debug */
113246439007SCharles.Forsyth netport = EARGF(badusage());
113346439007SCharles.Forsyth break;
113446439007SCharles.Forsyth } ARGEND
113546439007SCharles.Forsyth
113646439007SCharles.Forsyth iserver = &s;
113746439007SCharles.Forsyth styxinit(&s, &ops, netport, -1, 1);
113846439007SCharles.Forsyth styxaddfile(&s, Qroot, Qnclients, "nclients", 0444, inferno);
113946439007SCharles.Forsyth styxadddir(&s, Qroot, Qprotodir, "db", 0555, inferno);
11406ab1f7a0SCharles.Forsyth styxaddfile(&s, Qprotodir, Qclonus, "new", 0666, inferno);
114146439007SCharles.Forsyth newproto("db", 100);
114246439007SCharles.Forsyth for (;;) {
114346439007SCharles.Forsyth styxwait(&s);
114446439007SCharles.Forsyth styxprocess(&s);
114546439007SCharles.Forsyth }
114646439007SCharles.Forsyth styxend(&s);
114746439007SCharles.Forsyth }
1148