Charles.Forsyth20060303-partialeea662d19 years agoHistory
1146 lines · 21.8 KB · C
RawDownload
#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.