#ifdef WINDOWSNT#include <windows.h>#endif#include <lib9.h>#include <styx.h>#include "styxserver.h"/* #include <winsock.h> */ #define DEFCOLSIZE 10000 static int ODebug; char Eodbcalloc[] = "no free ODBC handles";char Enoconnect[] = "no ODBC connection"; static char *netport = "6700";static char *inferno = "inferno"; Styxserver *iserver; /* ----- */#include <sql.h>#include <sqlext.h> int nclients = 0; typedef struct Env Env;struct Env{ SQLHENV h; /* ODBC environment handle */}; typedef struct Conn Conn;struct Conn{ SQLHDBC h; /* ODBC connection handle */ int connected;}; typedef struct Coltype Coltype;struct Coltype{ char name[255]; ushort type; SQLUINTEGER size; ushort digits; ushort nulls;}; typedef struct Column Column;struct Column{ char *data; SQLINTEGER len;}; typedef struct Stmt Stmt;struct Stmt{ SQLHSTMT h; /* ODBC statement handle */ ushort ncols; /* number of columns in result */ ulong nrows; /* number of rows affected by update, insert, delete */ Coltype *cols; /* column descriptions */ Column *rec; /* data record */ char *headstr; /* column headings if requested */}; /* ----- */enum{ Qtopdir = 0, /* top level directory */ Qnclients, Qprotodir, Qclonus, Qconvdir, Qdata, Qcmd, Qctl, Qstatus, Qformat, Qsources, Qerror, MAXPROTO = 1};#define TYPE(x) ((x).path & 0xf)#define CONV(x) (((x).path >> 4)&0xfff)#define PROTO(x) (((x).path >> 16)&0xff)#define QID(p, c, y) (((p)<<16) | ((c)<<4) | (y)) typedef struct Proto Proto;typedef struct Conv Conv;typedef struct Output Output; struct Output { enum {Fixed, Float} style; /* output style */ uchar fs; /* float: field separator */ uchar rs; /* float: record separator */};Output defoutput = {Float, '|', '\n'}; struct Conv{ int x; int ref; int perm; char *owner; char* state; Proto* p; /*-----*/ Conn c; Stmt s; Output out; int headings; char errmsg[400]; /* odbc error messages can be big */}; struct Proto{ int x; char *name; uint nc; int maxconv; Conv** conv; Qid qid;}; typedef struct Dirtab Dirtab;struct Dirtab{ char name[255]; Qid qid; long length; long perm;}; static int np;static Proto proto[MAXPROTO];static Conv* protoclone(Proto*, char*); typedef int Devgen(Fid*, char *, Dirtab*, int, int, Dir*); struct xClient { /* ---- */ Env e;}; #define H(c) ((Env*)(c->u))->h voidfatal(char *fmt, ...){ char buf[1024], *out; va_list arg; out = vseprint(buf, buf+sizeof(buf), "Fatal error: ", 0); va_start(arg, fmt); out = vseprint(out, buf+sizeof(buf), fmt, arg); va_end(arg); write(2, buf, out-buf); exit(1);} #define ASSERT(A,B) xassert((int)A,B) voidxassert(int true, char *reason){ if(!true) fatal("assertion failed: %s\n", reason);} void *xmalloc(int bytes){ char *m = malloc(bytes); if(m) memset(m, 0, bytes);// print("xmalloc: %lux (%d)\n", m, bytes); return m;} voidxfree(void *p, char *from){// print("xfree: %lux [%s]\n", p, from); free(p);} char *odbcerror(Conv *cv, int lasterr){ char sqlstate[6]; long native; char *mp; short msglen; if(cv == 0) return ""; if(lasterr) return cv->errmsg; if(cv->c.connected) SQLGetDiagRec(SQL_HANDLE_STMT, cv->s.h, 1, sqlstate, &native, cv->errmsg, sizeof(cv->errmsg), &msglen); else SQLGetDiagRec(SQL_HANDLE_DBC, cv->c.h, 1, sqlstate, &native, cv->errmsg, sizeof(cv->errmsg), &msglen); cv->errmsg[msglen]=0; /* fprint(2, "c: sqlstate: %s, msg %s\n", sqlstate, cv->errmsg); */ if((mp=strrchr(cv->errmsg, ']')) != 0) return mp+1; return cv->errmsg;} char *odbcsources(Client *c){ int ss, i; char server[SQL_MAX_DSN_LENGTH+1]; char source[1024]; char buff[1024+SQL_MAX_DSN_LENGTH+1]; short serverlen, sourcelen; char *all = nil, *p; for (i=0;; i++) { ss = SQLDataSources(H(c), (i==0 ? SQL_FETCH_FIRST : SQL_FETCH_NEXT), server, sizeof(server), &serverlen, source, sizeof(source), &sourcelen); if (ss != SQL_SUCCESS) break; sprint(buff, "%s:%s\n", server, source); if (i == 0) all = strdup(buff); else { p = all; all = malloc(strlen(all)+strlen(buff)+1); strcpy(all, p); strcat(all, buff); free(p); } } return all;} intsqlerr(Conv *c, int sqlstatus, char *errp, char *func, char *sqlcall){ char *e; errp[0] = 0; e = "failed"; if (sqlstatus == SQL_ERROR || sqlstatus == SQL_SUCCESS_WITH_INFO) strcat(errp, odbcerror(c, 0)); if (sqlstatus == SQL_SUCCESS_WITH_INFO) e = "info"; if (sqlstatus != SQL_SUCCESS) fprint(2, "%s: %s %s - %s\n", func, sqlcall, e, errp); if (sqlstatus != SQL_SUCCESS && sqlstatus != SQL_SUCCESS_WITH_INFO) return 1; return 0;} char*odbcnewclient(Client *c){ int ss; /* ---- */ c->u = styxmalloc(sizeof(Env)); ss = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &H(c)); if (ss != SQL_SUCCESS && ss != SQL_SUCCESS_WITH_INFO) { fprint(2, "newclient: SQLAllocHandle failed\n"); return "SQLAllocHandle failed"; } ss = SQLSetEnvAttr(H(c), SQL_ATTR_ODBC_VERSION, (char*)SQL_OV_ODBC2, 0); if (ss != SQL_SUCCESS && ss != SQL_SUCCESS_WITH_INFO) { fprint(2, "newclient: SQLSetEnvAttr failed\n"); return "SQLSetEnvAttr failed"; } nclients++; return nil;} char*odbcfreeclient(Client *c){ int ss; ss = SQLFreeHandle(SQL_HANDLE_ENV, H(c)); if (ss != SQL_SUCCESS && ss != SQL_SUCCESS_WITH_INFO) fprint(2, "freeclient: SQLFreeHandle failed\n"); styxfree(c->u); nclients--; return nil;} intparsefields(char *lp, char **fields, int n, char *sep){ int i; for(i=0; lp && *lp && i<n; i++){ while(*lp && strchr(sep, *lp) != 0) *lp++=0; if(*lp == 0) break; fields[i]=lp; while(*lp && strchr(sep, *lp) == 0) lp++; } return i;} voidodbcdisconnect(Conv *c){ int ss; if(c->c.connected){ ss = SQLFreeHandle(SQL_HANDLE_STMT, c->s.h); if (ss != SQL_SUCCESS && ss != SQL_SUCCESS_WITH_INFO) fprint(2, "odbcdisconnect: SQLFreeHandle failed\n"); ss = SQLDisconnect(c->c.h); if (ss != SQL_SUCCESS && ss != SQL_SUCCESS_WITH_INFO) fprint(2, "odbcdisconnect: SQLDisconnect failed\n"); c->c.connected = 0; }} intodbcconnect(Conv *c, char *server, char *user, char *auth, char *ename){ int ss; odbcdisconnect(c); ss = SQLConnect(c->c.h, server, SQL_NTS, user, strlen(user), auth, strlen(auth)); if (sqlerr(c, ss, ename, "odbcconnect", "SQLConnect")) return -1; c->c.connected = 1; ss = SQLAllocHandle(SQL_HANDLE_STMT, c->c.h, &c->s.h); if (sqlerr(c, ss, ename, "odbcconnect", "SQLAllocHandle")) return -1; return 0;} intodbcnewconv(Client *c, Conv *cv){ int ss; ss = SQLAllocHandle(SQL_HANDLE_DBC, H(c), &cv->c.h); if (ss != SQL_SUCCESS && ss != SQL_SUCCESS_WITH_INFO) { fprint(2, "odbcnewconv: SQLAllocHandle failed\n"); return -1; } return 0;} voidodbcfreeconv(Conv *c){ int ss; odbcdisconnect(c); ss = SQLFreeHandle(SQL_HANDLE_DBC, c->c.h); if (ss != SQL_SUCCESS && ss != SQL_SUCCESS_WITH_INFO) fprint(2, "odbcfreeconv: SQLFreeHandle failed\n");} /* Free up all memory used in the last query */voidfreestat(Stmt *s){ int i; if (s->ncols == 0) return; for(i=0; i<s->ncols; i++){ Column *d = &s->rec[i]; xfree(d->data, "freestat - data"); } xfree(s->cols, "freestat - cols"); s->cols = 0; xfree(s->rec, "freestat - rec"); s->rec = 0; xfree(s->headstr, "freestat - headstr"); s->headstr = 0; s->ncols = 0;} /* build an array describing the columns */intmkcols(Conv *c, char *ename){ Stmt *s; int rv, i, err, hsize; ushort ignore; char *p; s = &c->s; s->ncols = 0; rv = SQLNumResultCols(s->h, &s->ncols); if (sqlerr(c, rv, ename, "mkcols", "SQLNumResultCols")) return -1; s->cols = xmalloc(s->ncols*sizeof(Coltype)); err = 0; hsize = 0; for(i=0; i<s->ncols; i++){ Coltype *t = &s->cols[i]; rv = SQLDescribeCol(s->h, i+1, t->name, sizeof(t->name), &ignore, &t->type, &t->size, &t->digits, &t->nulls); if (sqlerr(c, rv, ename, "mkcols", "SQLDescribeCol")) err++; if(t->size == 0 || t->size > MSGMAX) /* odbc should return 0 if size not available, not -1 */ t->size = DEFCOLSIZE; hsize += strlen(t->name) + 1; } if (c->headings) { hsize += 2; s->headstr = xmalloc(hsize); p = s->headstr; for(i=0; i<s->ncols; i++) { Coltype *t = &s->cols[i]; p += sprint(p, "%s%c", t->name, c->out.fs); } p[-1] = c->out.rs; } else s->headstr = 0; return (err ? -1 : 0);} /* build a record to hold `fetched' results */intmkrec(Conv *c, char *ename){ Stmt *s; int rv, i; s = &c->s; s->rec = xmalloc(s->ncols*sizeof(Column)); for(i=0; i<s->ncols; i++){ Coltype *t = &s->cols[i]; Column *d = &s->rec[i]; if (ODebug) print("Column %d size=%ud type=%hd\n", i, t->size, t->type); d->data = xmalloc(t->size+1); /* expects to zero terminate */ rv = SQLBindCol(s->h, i+1, SQL_C_CHAR, d->data, t->size+1, &d->len); if (sqlerr(c, rv, ename, "mkrec", "SQLBindCol")) return -1; } return 0;} introwcount(Conv *c, char *ename){ Stmt *s; int rv; s = &c->s; s->nrows = 0; rv = SQLRowCount(s->h, &s->nrows); if (sqlerr(c, rv, ename, "rowcount", "SQLRowCount")) return -1; return 0;} intodbcfetch(Conv *c, char *ename){ Stmt *s = &c->s; int rv; rv = SQLFetch(s->h); if(rv == SQL_NO_DATA) { freestat(s); return 0; } if (sqlerr(c, rv, ename, "odbcfetch", "SQLFetch")) { freestat(s); return -1; } return 1;} intodbcresults(Conv *c, char *ename){ if(mkcols(c, ename)) return -1; if(mkrec(c, ename)) return -1; if(rowcount(c, ename)) return -1; return 0;} voidstruncate(char *s, long *len){ long i; for (i=0; i<*len; i++) if (s[i] == 0) {Lines 1–500 of 1146. Load more
#ifdef WINDOWSNT #include <windows.h> #endif #include <lib9.h> #include <styx.h> #include "styxserver.h" /* #include <winsock.h> */ #define DEFCOLSIZE 10000 static int ODebug; char Eodbcalloc[] = "no free ODBC handles"; char Enoconnect[] = "no ODBC connection"; static char *netport = "6700"; static char *inferno = "inferno"; Styxserver *iserver; /* ----- */ #include <sql.h> #include <sqlext.h> int nclients = 0; typedef struct Env Env; struct Env { SQLHENV h; /* ODBC environment handle */ }; typedef struct Conn Conn; struct Conn { SQLHDBC h; /* ODBC connection handle */ int connected; }; typedef struct Coltype Coltype; struct Coltype { char name[255]; ushort type; SQLUINTEGER size; ushort digits; ushort nulls; }; typedef struct Column Column; struct Column { char *data; SQLINTEGER len; }; typedef struct Stmt Stmt; struct Stmt { SQLHSTMT h; /* ODBC statement handle */ ushort ncols; /* number of columns in result */ ulong nrows; /* number of rows affected by update, insert, delete */ Coltype *cols; /* column descriptions */ Column *rec; /* data record */ char *headstr; /* column headings if requested */ }; /* ----- */ enum { Qtopdir = 0, /* top level directory */ Qnclients, Qprotodir, Qclonus, Qconvdir, Qdata, Qcmd, Qctl, Qstatus, Qformat, Qsources, Qerror, MAXPROTO = 1 }; #define TYPE(x) ((x).path & 0xf) #define CONV(x) (((x).path >> 4)&0xfff) #define PROTO(x) (((x).path >> 16)&0xff) #define QID(p, c, y) (((p)<<16) | ((c)<<4) | (y)) typedef struct Proto Proto; typedef struct Conv Conv; typedef struct Output Output; struct Output { enum {Fixed, Float} style; /* output style */ uchar fs; /* float: field separator */ uchar rs; /* float: record separator */ }; Output defoutput = {Float, '|', '\n'}; struct Conv { int x; int ref; int perm; char *owner; char* state; Proto* p; /*-----*/ Conn c; Stmt s; Output out; int headings; char errmsg[400]; /* odbc error messages can be big */ }; struct Proto { int x; char *name; uint nc; int maxconv; Conv** conv; Qid qid; }; typedef struct Dirtab Dirtab; struct Dirtab { char name[255]; Qid qid; long length; long perm; }; static int np; static Proto proto[MAXPROTO]; static Conv* protoclone(Proto*, char*); typedef int Devgen(Fid*, char *, Dirtab*, int, int, Dir*); struct xClient { /* ---- */ Env e; }; #define H(c) ((Env*)(c->u))->h void fatal(char *fmt, ...) { char buf[1024], *out; va_list arg; out = vseprint(buf, buf+sizeof(buf), "Fatal error: ", 0); va_start(arg, fmt); out = vseprint(out, buf+sizeof(buf), fmt, arg); va_end(arg); write(2, buf, out-buf); exit(1); } #define ASSERT(A,B) xassert((int)A,B) void xassert(int true, char *reason) { if(!true) fatal("assertion failed: %s\n", reason); } void * xmalloc(int bytes) { char *m = malloc(bytes); if(m) memset(m, 0, bytes); // print("xmalloc: %lux (%d)\n", m, bytes); return m; } void xfree(void *p, char *from) { // print("xfree: %lux [%s]\n", p, from); free(p); } char * odbcerror(Conv *cv, int lasterr) { char sqlstate[6]; long native; char *mp; short msglen; if(cv == 0) return ""; if(lasterr) return cv->errmsg; if(cv->c.connected) SQLGetDiagRec(SQL_HANDLE_STMT, cv->s.h, 1, sqlstate, &native, cv->errmsg, sizeof(cv->errmsg), &msglen); else SQLGetDiagRec(SQL_HANDLE_DBC, cv->c.h, 1, sqlstate, &native, cv->errmsg, sizeof(cv->errmsg), &msglen); cv->errmsg[msglen]=0; /* fprint(2, "c: sqlstate: %s, msg %s\n", sqlstate, cv->errmsg); */ if((mp=strrchr(cv->errmsg, ']')) != 0) return mp+1; return cv->errmsg; } char *odbcsources(Client *c) { int ss, i; char server[SQL_MAX_DSN_LENGTH+1]; char source[1024]; char buff[1024+SQL_MAX_DSN_LENGTH+1]; short serverlen, sourcelen; char *all = nil, *p; for (i=0;; i++) { ss = SQLDataSources(H(c), (i==0 ? SQL_FETCH_FIRST : SQL_FETCH_NEXT), server, sizeof(server), &serverlen, source, sizeof(source), &sourcelen); if (ss != SQL_SUCCESS) break; sprint(buff, "%s:%s\n", server, source); if (i == 0) all = strdup(buff); else { p = all; all = malloc(strlen(all)+strlen(buff)+1); strcpy(all, p); strcat(all, buff); free(p); } } return all; } int sqlerr(Conv *c, int sqlstatus, char *errp, char *func, char *sqlcall) { char *e; errp[0] = 0; e = "failed"; if (sqlstatus == SQL_ERROR || sqlstatus == SQL_SUCCESS_WITH_INFO) strcat(errp, odbcerror(c, 0)); if (sqlstatus == SQL_SUCCESS_WITH_INFO) e = "info"; if (sqlstatus != SQL_SUCCESS) fprint(2, "%s: %s %s - %s\n", func, sqlcall, e, errp); if (sqlstatus != SQL_SUCCESS && sqlstatus != SQL_SUCCESS_WITH_INFO) return 1; return 0; } char* odbcnewclient(Client *c) { int ss; /* ---- */ c->u = styxmalloc(sizeof(Env)); ss = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &H(c)); if (ss != SQL_SUCCESS && ss != SQL_SUCCESS_WITH_INFO) { fprint(2, "newclient: SQLAllocHandle failed\n"); return "SQLAllocHandle failed"; } ss = SQLSetEnvAttr(H(c), SQL_ATTR_ODBC_VERSION, (char*)SQL_OV_ODBC2, 0); if (ss != SQL_SUCCESS && ss != SQL_SUCCESS_WITH_INFO) { fprint(2, "newclient: SQLSetEnvAttr failed\n"); return "SQLSetEnvAttr failed"; } nclients++; return nil; } char* odbcfreeclient(Client *c) { int ss; ss = SQLFreeHandle(SQL_HANDLE_ENV, H(c)); if (ss != SQL_SUCCESS && ss != SQL_SUCCESS_WITH_INFO) fprint(2, "freeclient: SQLFreeHandle failed\n"); styxfree(c->u); nclients--; return nil; } int parsefields(char *lp, char **fields, int n, char *sep) { int i; for(i=0; lp && *lp && i<n; i++){ while(*lp && strchr(sep, *lp) != 0) *lp++=0; if(*lp == 0) break; fields[i]=lp; while(*lp && strchr(sep, *lp) == 0) lp++; } return i; } void odbcdisconnect(Conv *c) { int ss; if(c->c.connected){ ss = SQLFreeHandle(SQL_HANDLE_STMT, c->s.h); if (ss != SQL_SUCCESS && ss != SQL_SUCCESS_WITH_INFO) fprint(2, "odbcdisconnect: SQLFreeHandle failed\n"); ss = SQLDisconnect(c->c.h); if (ss != SQL_SUCCESS && ss != SQL_SUCCESS_WITH_INFO) fprint(2, "odbcdisconnect: SQLDisconnect failed\n"); c->c.connected = 0; } } int odbcconnect(Conv *c, char *server, char *user, char *auth, char *ename) { int ss; odbcdisconnect(c); ss = SQLConnect(c->c.h, server, SQL_NTS, user, strlen(user), auth, strlen(auth)); if (sqlerr(c, ss, ename, "odbcconnect", "SQLConnect")) return -1; c->c.connected = 1; ss = SQLAllocHandle(SQL_HANDLE_STMT, c->c.h, &c->s.h); if (sqlerr(c, ss, ename, "odbcconnect", "SQLAllocHandle")) return -1; return 0; } int odbcnewconv(Client *c, Conv *cv) { int ss; ss = SQLAllocHandle(SQL_HANDLE_DBC, H(c), &cv->c.h); if (ss != SQL_SUCCESS && ss != SQL_SUCCESS_WITH_INFO) { fprint(2, "odbcnewconv: SQLAllocHandle failed\n"); return -1; } return 0; } void odbcfreeconv(Conv *c) { int ss; odbcdisconnect(c); ss = SQLFreeHandle(SQL_HANDLE_DBC, c->c.h); if (ss != SQL_SUCCESS && ss != SQL_SUCCESS_WITH_INFO) fprint(2, "odbcfreeconv: SQLFreeHandle failed\n"); } /* Free up all memory used in the last query */ void freestat(Stmt *s) { int i; if (s->ncols == 0) return; for(i=0; i<s->ncols; i++){ Column *d = &s->rec[i]; xfree(d->data, "freestat - data"); } xfree(s->cols, "freestat - cols"); s->cols = 0; xfree(s->rec, "freestat - rec"); s->rec = 0; xfree(s->headstr, "freestat - headstr"); s->headstr = 0; s->ncols = 0; } /* build an array describing the columns */ int mkcols(Conv *c, char *ename) { Stmt *s; int rv, i, err, hsize; ushort ignore; char *p; s = &c->s; s->ncols = 0; rv = SQLNumResultCols(s->h, &s->ncols); if (sqlerr(c, rv, ename, "mkcols", "SQLNumResultCols")) return -1; s->cols = xmalloc(s->ncols*sizeof(Coltype)); err = 0; hsize = 0; for(i=0; i<s->ncols; i++){ Coltype *t = &s->cols[i]; rv = SQLDescribeCol(s->h, i+1, t->name, sizeof(t->name), &ignore, &t->type, &t->size, &t->digits, &t->nulls); if (sqlerr(c, rv, ename, "mkcols", "SQLDescribeCol")) err++; if(t->size == 0 || t->size > MSGMAX) /* odbc should return 0 if size not available, not -1 */ t->size = DEFCOLSIZE; hsize += strlen(t->name) + 1; } if (c->headings) { hsize += 2; s->headstr = xmalloc(hsize); p = s->headstr; for(i=0; i<s->ncols; i++) { Coltype *t = &s->cols[i]; p += sprint(p, "%s%c", t->name, c->out.fs); } p[-1] = c->out.rs; } else s->headstr = 0; return (err ? -1 : 0); } /* build a record to hold `fetched' results */ int mkrec(Conv *c, char *ename) { Stmt *s; int rv, i; s = &c->s; s->rec = xmalloc(s->ncols*sizeof(Column)); for(i=0; i<s->ncols; i++){ Coltype *t = &s->cols[i]; Column *d = &s->rec[i]; if (ODebug) print("Column %d size=%ud type=%hd\n", i, t->size, t->type); d->data = xmalloc(t->size+1); /* expects to zero terminate */ rv = SQLBindCol(s->h, i+1, SQL_C_CHAR, d->data, t->size+1, &d->len); if (sqlerr(c, rv, ename, "mkrec", "SQLBindCol")) return -1; } return 0; } int rowcount(Conv *c, char *ename) { Stmt *s; int rv; s = &c->s; s->nrows = 0; rv = SQLRowCount(s->h, &s->nrows); if (sqlerr(c, rv, ename, "rowcount", "SQLRowCount")) return -1; return 0; } int odbcfetch(Conv *c, char *ename) { Stmt *s = &c->s; int rv; rv = SQLFetch(s->h); if(rv == SQL_NO_DATA) { freestat(s); return 0; } if (sqlerr(c, rv, ename, "odbcfetch", "SQLFetch")) { freestat(s); return -1; } return 1; } int odbcresults(Conv *c, char *ename) { if(mkcols(c, ename)) return -1; if(mkrec(c, ename)) return -1; if(rowcount(c, ename)) return -1; return 0; } void struncate(char *s, long *len) { long i; for (i=0; i<*len; i++) if (s[i] == 0) {