Charles.Forsyth20060303-partialeea662d19 years agoHistory
998 lines · 23.0 KB · C
RawDownload
////	infdb - NT data base daemon for Inferno////	Copyright 1997 Lucent Technologies////	May 1997//#include <stdio.h>#include <string.h>#include <stdlib.h>#include <fcntl.h>#ifdef WIN32#include <winsock.h>#include <SQL.h>#include <SQLEXT.h>#else#include <unistd.h>#include <sql.h>#include <sqlext.h>#define max(a, b)        ((a) > (b) ? (a) : (b))#define strnicmp strncasecmp#endif #define MAXCOLS	100#define BUFSIZE	8192#define REQ_HEADER_SIZE 18#define RES_HEADER_SIZE 22#define OFFSET_LENGTH 2#define OFFSET_STREAM 14#define OFFSET_REQ_DATA 18#define OFFSET_RETURN 18#define OFFSET_RES_DATA 22 #define	CONN_ALLOC_FAIL		1#define STREAM_ALLOC_FAIL	2#define STREAM_BAD_ID		3#define LAST_ERROR_NO		4  ////	Deal with one connection.  Use stdin and stdout to read and write messages.//  Each incoming message is answered before reading the next incoming message.// typedef int STATUS;#define			OK		 0#define			WARN	-1#define			ERR		-2 typedef struct {	int		state;#define			SQLC_FREE	0#define			SQLC_INUSE	1	int		connid;	int		refcount;	UCHAR	user[48];	UCHAR	passwd[48];	UCHAR	dbname[48];	UCHAR	errmsg[256];	HDBC	hdbc;} SQLConn;  typedef struct {	int		state;#define			SQLS_FREE	0#define			SQLS_INUSE	1	int		streamid;	int		connid;	HSTMT	hstmt;	UCHAR	errmsg[256];	UCHAR	colname[MAXCOLS][32];	SWORD	coltype[MAXCOLS];	SWORD	colnamelen;	SWORD	nullable;	UDWORD	collen[MAXCOLS];	SWORD	scale;	SDWORD	outlen[MAXCOLS];	UCHAR	*data[MAXCOLS];	SWORD	nresultcols;	SDWORD	rowcount;	SWORD	rownum;	RETCODE	rc;	UCHAR	*setdata[MAXCOLS];	SDWORD	setdatalen[MAXCOLS];} SQLStream;  typedef struct {	HENV		henv;	int			maxconn;	int			numconn;	SQLConn		**scarray;	int			maxstream;	int			numstream;	SQLStream	**ssarray;} SQLEnv;  typedef struct {	char	mtype;	char	version;	int		nbytes;	int		sstream;	int		retcode;	int		bytesNotRead;	char	*data;} DBMSG, *DBMSGP;  int			getCommand		(DBMSGP msgp, UCHAR *buf, int bufsiz);void		sendResponse	(char type, int lendata, int sstream, int retcode, char *data);void		sendError		(char *errmsg, int sstream);void		print_err		(SQLEnv *sqle, int connid, int streamid, UCHAR * buf, int bufsiz);UDWORD		display_size	(SWORD coltype, UDWORD collen, UCHAR *colname); STATUS		newSqlEnv		(SQLEnv **sqle);STATUS		freeSqlEnv		(SQLEnv **sqle); STATUS		newSqlConn		(SQLEnv *sqle, char *info, int *connid);STATUS		mapSqlConn		(SQLEnv *sqle, int connid, SQLConn **sqlc);STATUS		freeSqlConn		(SQLEnv *sqle, int connid); STATUS		newSqlStream	(SQLEnv *sqle, int connid, int *streamid);STATUS		mapSqlStream	(SQLEnv *sqle, int streamid, SQLStream **sqls);STATUS		freeSqlStream	(SQLEnv *sqle, int streamid); STATUS		parseConnInfo	(SQLConn *sqlc, char *info); char	*iError[] = {	"INFDB: DB connection allocation failed",	"INFDB: couldn't allocate SQL stream",	"INFDB: bad SQL stream identifier"}; intmain(int argc, char *argv[]){	int			i;	int			notdone = 1;	int			infErrno;	DBMSG		msg;	SQLEnv		*sqle = NULL;	SQLStream	*sqls;	char		buf[BUFSIZE];	char		outbuf[BUFSIZE];	char		errmsg[256];	STATUS		rc;  	//	We just have to talk to stdin and stdout.  However, stdout may be open	//	in text mode, which is bad for data.  Set it to binary mode. #ifdef WIN32	_setmode(0, _O_BINARY);	_setmode(1, _O_BINARY);#endif 	rc = newSqlEnv(&sqle);	if ( rc != OK ) {		sendError("INFDB: Failed to allocate SQL environment.", -1);		return -1;	}     while ( notdone ) {		int		bytesRead; 		bytesRead = 0;		if ( (bytesRead = getCommand(&msg, buf, sizeof(buf))) <= 0 ) {			continue;		}		msg.retcode = 0;		infErrno = 0; 		switch ( msg.mtype ) {		  // Initiate a new connection.		  case 'I':		  {			int connid; 			rc = newSqlConn(sqle, msg.data, &connid);			if ( rc != OK ) {				infErrno = CONN_ALLOC_FAIL;				break;			}			/*			// Need a new SQLStream to make subsequent requests.			rc = newSqlStream(sqle, connid, &streamid);			if ( rc != OK )	{				infErrno = STREAM_ALLOC_FAIL;				break;		    } 			sprintf(outbuf, "%d", streamid);			*/			sprintf(outbuf, "%d", connid);			sendResponse('i', strlen(outbuf), msg.sstream, 0, outbuf);			break;		  }  		  case 'O':		  {			// open an SQL stream.			int connid, streamid; 			connid = atoi(msg.data);			rc = newSqlStream(sqle, connid, &streamid);			if (rc != OK) {				infErrno = STREAM_ALLOC_FAIL;				break;			} 			sprintf(outbuf, "%d", streamid);			sendResponse('o', strlen(outbuf), msg.sstream, 0, outbuf);			break;		  }  		  case 'K':			// klose an SQL stream			rc = freeSqlStream(sqle, msg.sstream);			sendResponse('k', 0, msg.sstream, 0, "");			break;  		  case 'C': 			// request number of columns			rc = mapSqlStream(sqle, msg.sstream, &sqls);			if ( rc != OK ) {				infErrno = STREAM_BAD_ID;				break;			} 			sprintf(outbuf, "%d", sqls->nresultcols);			sendResponse('c', strlen(outbuf), msg.sstream, 0, outbuf);			break;  		  case 'N':																		 			// fetch next row			rc = mapSqlStream(sqle, msg.sstream, &sqls);			if ( rc != OK ) {				infErrno = STREAM_BAD_ID;				break;			}					sqls->errmsg[0] = '\0';			rc = SQLFetch(sqls->hstmt);			if ( rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO ) {				sqls->rownum++;				//	if ( rc == SQL_SUCCESS_WITH_INFO ) {					//	fprintf(stderr, "SQLFetch got SQL_SUCCESS_WITH_INFO\n");				//	}				/*		Get the data for all columns	*/				for ( i = 0; i < sqls->nresultcols; i++ ) {					rc = SQLGetData(sqls->hstmt, (UWORD)(i+1),									(sqls->coltype[i] == SQL_LONGVARBINARY ||									 sqls->coltype[i] == SQL_LONGVARCHAR) ? SQL_C_DEFAULT :																			SQL_C_CHAR,									sqls->data[i], sqls->collen[i], &sqls->outlen[i]);					if ( rc == SQL_SUCCESS_WITH_INFO &&											(UDWORD) sqls->outlen[i] > sqls->collen[i] ) {						UCHAR	*tmp; 						tmp = (UCHAR *) realloc(sqls->data[i], sqls->outlen[i]+1);						if ( tmp != NULL ) {							SDWORD	dummy;							sqls->data[i] = tmp;							rc = SQLGetData(sqls->hstmt, (UWORD)(i+1), SQL_C_DEFAULT,											&tmp[sqls->collen[i]], sqls->outlen[i], &dummy);							sqls->collen[i] = sqls->outlen[i];							sqls->data[i][sqls->outlen[i]] = 0;						}					}					else if ( rc != SQL_SUCCESS ) {						sprintf(sqls->errmsg, "Problem retrieving data from data base, col %d", i+1);						msg.retcode = 2;					}				}			}			else if ( rc == SQL_NO_DATA_FOUND ) {				sqls->rownum = 0;				msg.retcode = 1;			}			else {				sqls->rownum = -1;				//	Probably should get some status from ODBC for message				sprintf(sqls->errmsg, "Error occurred in fetching data");			}			if ( sqls->rownum < 0 ) {				sendError(errmsg, msg.sstream);			}			else {				sprintf(outbuf, "%d", sqls->rownum);				//	rownum should be <= rowcount				sendResponse('n', strlen(outbuf), msg.sstream, msg.retcode, outbuf);			}			break;  		  case 'H':			// request an error message, if any			rc = mapSqlStream(sqle, msg.sstream, &sqls);			if ( rc != OK ) {				infErrno = STREAM_BAD_ID;				break;			}					sendError(sqls->errmsg, msg.sstream);			sqls->errmsg[0] = 0;			break;  		  case 'P':			// request write data			// in Inferno, param nums start at 0; in ODBC/SQL, they start at 1			// This leaves outdatalen[0] unused, hence available as final SQLBindParameter arg.			rc = mapSqlStream(sqle, msg.sstream, &sqls);			if ( rc != OK ) {				infErrno = STREAM_BAD_ID;				break;			}					sqls->errmsg[0] = 0;			if ( (i = atoi(msg.data) + 1) < 1 || i >= MAXCOLS ) {				sendError("Illegal param number", msg.sstream);			}			else {				int		len;				char	*p = msg.data + 4;		// data points to param number 				len = msg.nbytes - 4;			// number of data chars				if ( len < 0 ) {					sendError("Write phase error II", msg.sstream);					break;				}				if ( sqls->setdata[i] != NULL ) {					free(sqls->setdata[i]);				}				sqls->setdata[i] = (char *) malloc(len + 1);				if ( sqls->setdata[i] == NULL ) {					sendError("Allocation error in server", msg.sstream);					break;				}				//	Copy data we have into buffer, and if we don't have it all yet,				//	try to get the rest.				sqls->setdatalen[i] = len++;		// adjust len for trailing \n				bytesRead = &buf[bytesRead] - p;	// number data bytes we have read				memcpy(sqls->setdata[i], p, bytesRead);				len -= bytesRead;					// number bytes still to read,				while ( len > 0 ) {					int	n; 					if ( (n = read(0, sqls->setdata[i] + bytesRead, len)) <= 0 ) {						break;					}					bytesRead += n;					len -= n;				}				if ( len > 0 ) {					sendError("Couldn't read all of parameter", msg.sstream);					break;				}				rc = SQLBindParameter(sqls->hstmt, (UWORD)i, SQL_PARAM_INPUT,									SQL_C_BINARY, SQL_LONGVARBINARY,									sqls->setdatalen[i], 0, (PTR) i, 0, sqls->setdatalen);				if ( rc != SQL_SUCCESS ) {					sendError("BindParameter failed: maybe not supported", msg.sstream);					break;				}				sqls->setdatalen[0] = SQL_LEN_DATA_AT_EXEC(0);				sprintf(outbuf, "%d", bytesRead - 1);				sendResponse('p', strlen(outbuf), msg.sstream, 0, outbuf);			}			break;  		  case 'R':			// request read data			rc = mapSqlStream(sqle, msg.sstream, &sqls);			if ( rc != OK ) {				infErrno = STREAM_BAD_ID;				break;			}					if ( (i = atoi(msg.data)) < 0 || i >= sqls->nresultcols || sqls->rownum <= 0 ) {				sendError(sqls->rownum <= 0 ? "No current row" : "Illegal column number", msg.sstream);			}			else if ( sqls->outlen[i] == SQL_NULL_DATA || sqls->outlen[i] == SQL_NO_TOTAL ) {				sendResponse('r', 0, msg.sstream, 0, "");			}			else {				if ( sqls->coltype[i] == SQL_VARCHAR ) {					sqls->outlen[i] = strlen(sqls->data[i]);				}				sendResponse('r', sqls->outlen[i], msg.sstream, 0, sqls->data[i]);			}			break;  		  case 'T':			// request column title			rc = mapSqlStream(sqle, msg.sstream, &sqls);			if ( rc != OK ) {				infErrno = STREAM_BAD_ID;				break;			}					if ( (i = atoi(msg.data)) < 0 || i >= sqls->nresultcols ) {				sendError("Illegal column number", msg.sstream);			}			else {				sendResponse('t', strlen(sqls->colname[i]), msg.sstream, 0, sqls->colname[i]);			}			break;  		  case 'W':	    			// execute command			rc = mapSqlStream(sqle, msg.sstream, &sqls);			if ( rc != OK ) {				infErrno = STREAM_BAD_ID;				break;			}					if ( sqls->hstmt ) {				SQLFreeStmt(sqls->hstmt, SQL_CLOSE);				SQLFreeStmt(sqls->hstmt, SQL_UNBIND);			}			//	Look for special extensions			if ( strnicmp(msg.data, "commit", 6) == 0 ) {				SQLConn	*sqlc; 				rc = mapSqlConn(sqle, sqls->connid, &sqlc);				rc = SQLTransact(SQL_NULL_HENV, sqlc->hdbc, SQL_COMMIT);			}			else if ( strnicmp(msg.data, "rollback", 8) == 0 ) {				SQLConn	*sqlc; 				rc = mapSqlConn(sqle, sqls->connid, &sqlc);				rc = SQLTransact(SQL_NULL_HENV, sqlc->hdbc, SQL_ROLLBACK);			} 			else if ( strnicmp(msg.data, "tables", 6) == 0 ) {				rc = SQLTables(sqls->hstmt, NULL, 0, NULL, 0, NULL, 0, NULL, 0);			}			else if ( strnicmp(msg.data, "columns", 7) == 0 ) {				UCHAR	*tbl;								for ( tbl = msg.data+8; *tbl == ' ' || *tbl == '\t'; tbl++ ) { } 				rc = SQLColumns(sqls->hstmt, NULL, 0, NULL, 0, tbl, SQL_NTS, NULL, 0);			}			else {				rc = SQLExecDirect(sqls->hstmt, msg.data, SQL_NTS);			}			outbuf[0] = '\0';			while ( rc == SQL_NEED_DATA ) {				PTR	pToken;//				SDWORD	pnum; 				rc = SQLParamData(sqls->hstmt, &pToken);//				pnum = (SDWORD) pToken;#define pnum (int)pToken				if ( rc == SQL_NEED_DATA ) {					int	retcode; 					if ( sqls->setdata[pnum] == NULL || sqls->setdatalen[pnum] <= 0 ) {						sprintf(outbuf, "Parameter %d not set\n", pnum);						break;					}					for ( i = 0; i < sqls->setdatalen[pnum]; ) {						int		togo; 						togo = 1024;						if ( sqls->setdatalen[pnum] - i < 1024 ) {							togo = sqls->setdatalen[pnum] - i;						}						retcode = SQLPutData(sqls->hstmt,													sqls->setdata[pnum] + i, togo);						i += togo;						if ( retcode != SQL_SUCCESS ) {							print_err(sqle, -1, msg.sstream, &outbuf[strlen(outbuf)], sizeof (outbuf) - strlen(outbuf));							break;						}					}					if ( retcode != SQL_SUCCESS /* && retcode != SQL_SUCCESS_WITH_INFO */) {						break;					}				}			}			if ( rc != SQL_SUCCESS ) {				strcat(outbuf, "Command execution failed\n");				switch ( rc ) {				case SQL_SUCCESS_WITH_INFO:					strcat(outbuf, ": SQL_SUCCESS_WITH_INFO");					print_err(sqle, -1, msg.sstream, &outbuf[strlen(outbuf)], sizeof (outbuf) - strlen(outbuf));					break;				case SQL_ERROR:					strcat(outbuf, ": SQL_ERROR");

Lines 1–500 of 998.