⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 freetdsconnection.c

📁 适合于Unix/Linux下的一个持久数据库连接池
💻 C
📖 第 1 页 / 共 3 页
字号:
// Copyright (c) 1999-2001  David Muse// See the file COPYING for more information#include <freetdsconnection.h>#include <tdsver.h>#include <config.h>#ifndef HAVE_FREETDS_FUNCTION_DEFINITIONS	#include <ctfunctions.h>#endif#include <datatypes.h>#include <rudiments/stringbuffer.h>#include <rudiments/charstring.h>#include <rudiments/rawbuffer.h>#include <stdio.h>#include <stdlib.h>stringbuffer	*freetdsconnection::errorstring;bool		freetdsconnection::deadconnection;freetdsconnection::freetdsconnection() : sqlrconnection_svr() {	errorstring=NULL;	dbused=false;	// LAME: freetds only supports 1 cursor, but sqlrelay uses a	// multi-cursor paradigm, so we'll allow sqlrelay to think we're using	// more than 1 cursor, but really we're only using one, so some things	// won't work but there'll be no hard errors	singlecursor=NULL;	singlecursorrefcount=0;	dbversion=NULL;}freetdsconnection::~freetdsconnection() {	delete errorstring;	delete[] dbversion;}uint16_t freetdsconnection::getNumberOfConnectStringVars() {	return NUM_CONNECT_STRING_VARS;}void freetdsconnection::handleConnectString() {	sybase=connectStringValue("sybase");	lang=connectStringValue("lang");	setUser(connectStringValue("user"));	setPassword(connectStringValue("password"));	server=connectStringValue("server");	db=connectStringValue("db");	charset=connectStringValue("charset");	language=connectStringValue("language");	hostname=connectStringValue("hostname");	packetsize=connectStringValue("packetsize");}bool freetdsconnection::logIn(bool printerrors) {	// set sybase	if (sybase && sybase[0] && !environment::setValue("SYBASE",sybase)) {		logInError("Failed to set SYBASE environment variable.",1);		return false;	}	// set lang	if (lang && lang[0] && !environment::setValue("LANG",lang)) {		logInError("Failed to set LANG environment variable.",1);		return false;	}	// set server	if (server && server[0] && !environment::setValue("DSQUERY",server)) {		logInError("Failed to set DSQUERY environment variable.",2);		return false;	}	// allocate a context	context=(CS_CONTEXT *)NULL;	if (cs_ctx_alloc(CS_VERSION_100,&context)!=CS_SUCCEED) {		logInError("failed to allocate a context structure",2);		return false;	}	// init the context	if (ct_init(context,CS_VERSION_100)!=CS_SUCCEED) {		logInError("failed to initialize a context structure",3);		return false;	}	// configure the error handling callbacks	if (cs_config(context,CS_SET,CS_MESSAGE_CB,		(CS_VOID *)freetdsconnection::csMessageCallback,CS_UNUSED,			(CS_INT *)NULL)			!=CS_SUCCEED) {		logInError("failed to set a cslib error message callback",4);		return false;	}	if (ct_callback(context,NULL,CS_SET,CS_CLIENTMSG_CB,		(CS_VOID *)freetdsconnection::clientMessageCallback)			!=CS_SUCCEED) {		logInError("failed to set a client error message callback",4);		return false;	}	if (ct_callback(context,NULL,CS_SET,CS_SERVERMSG_CB,		(CS_VOID *)freetdsconnection::serverMessageCallback)			!=CS_SUCCEED) {		logInError("failed to set a server error message callback",4);		return false;	}	// allocate a connection	if (ct_con_alloc(context,&dbconn)!=CS_SUCCEED) {		logInError("failed to allocate a connection structure",4);		return false;	}	// set the user to use	const char	*user=getUser();	if (ct_con_props(dbconn,CS_SET,CS_USERNAME,			(CS_VOID *)((user && user[0])?user:""),			CS_NULLTERM,(CS_INT *)NULL)!=CS_SUCCEED) {		logInError("failed to set the user",5);		return false;	}	// set the password to use	const char	*password=getPassword();	if (ct_con_props(dbconn,CS_SET,CS_PASSWORD,			(CS_VOID *)((password && password[0])?password:""),			CS_NULLTERM,(CS_INT *)NULL)!=CS_SUCCEED) {		logInError("failed to set the password",5);		return false;	}	// set application name	if (ct_con_props(dbconn,CS_SET,CS_APPNAME,(CS_VOID *)"sqlrelay",			CS_NULLTERM,(CS_INT *)NULL)!=CS_SUCCEED) {		logInError("failed to set the application name",5);		return false;	}	// set hostname	if (hostname && hostname[0] &&		ct_con_props(dbconn,CS_SET,CS_HOSTNAME,(CS_VOID *)hostname,				CS_NULLTERM,(CS_INT *)NULL)!=CS_SUCCEED) {			logInError("failed to set the hostname",5);		return false;	}	// set packetsize	uint16_t	ps=charstring::toInteger(packetsize);	if (packetsize && packetsize[0] &&		ct_con_props(dbconn,CS_SET,CS_PACKETSIZE,				(CS_VOID *)&ps,sizeof(ps),				(CS_INT *)NULL)!=CS_SUCCEED) {		logInError("failed to set the packetsize",5);		return false;	}	// FIXME: support this	// set encryption	/*if (encryption && charstring::toInteger(encryption)==1) {		// FIXME: need to set CS_SEC_CHALLENGE/CS_SEC_NEGOTIATE		// parameters too		CS_INT	enc=CS_TRUE;		if (ct_con_props(dbconn,CS_SET,CS_SEC_ENCRYPTION,			(CS_VOID *)&enc,			CS_UNUSED,(CS_INT *)NULL)!=CS_SUCCEED) {			logInError("failed to set the encryption",5);			return false;		}	}*/	// init locale	locale=NULL;	if (cs_loc_alloc(context,&locale)!=CS_SUCCEED) {		logInError("failed to allocate a locale structure",5);		return false;	}	if (cs_locale(context,CS_SET,locale,CS_LC_ALL,(CS_CHAR *)NULL,			CS_UNUSED,(CS_INT *)NULL)!=CS_SUCCEED) {		logInError("failed to initialize a locale structure",6);		return false;	}	// set language	if (language && language[0] &&		cs_locale(context,CS_SET,locale,CS_SYB_LANG,			(CS_CHAR *)language,CS_NULLTERM,(CS_INT *)NULL)!=				CS_SUCCEED) {		logInError("failed to set the language",6);		return false;	}	// set charset	if (charset && charset[0] &&		cs_locale(context,CS_SET,locale,CS_SYB_CHARSET,			(CS_CHAR *)charset,CS_NULLTERM,(CS_INT *)NULL)!=				CS_SUCCEED) {		logInError("failed to set the charset",6);		return false;	}	// set locale	if (ct_con_props(dbconn,CS_SET,CS_LOC_PROP,(CS_VOID *)locale,				CS_UNUSED,(CS_INT *)NULL)!=CS_SUCCEED) {		logInError("failed to set the locale",6);		return false;	}	// connect to the database	if (ct_connect(dbconn,(CS_CHAR *)NULL,(CS_INT)0)!=CS_SUCCEED) {		logInError("failed to connect to the database",6);		return false;	}	return true;}void freetdsconnection::logInError(const char *error, uint16_t stage) {	fprintf(stderr,"%s\n",error);	if (errorstring) {		fprintf(stderr,"%s\n",errorstring->getString());	}	if (stage>5) {		cs_loc_drop(context,locale);	}	if (stage>4) {		ct_con_drop(dbconn);	}	if (stage>3) {		ct_exit(context,CS_UNUSED);	}	if (stage>2) {		cs_ctx_drop(context);	}}sqlrcursor_svr *freetdsconnection::initCursor() {	// LAME: freetds only supports 1 cursor, but sqlrelay uses a	// multi-cursor paradigm, so we'll allow sqlrelay to think we're using	// more than 1 cursor, but really we're only using one, so some things	// won't work but there'll be no hard errors	singlecursorrefcount++;	if (singlecursor) {		return singlecursor;	}	singlecursor=new freetdscursor((sqlrconnection_svr *)this);	return singlecursor;	//return (sqlrcursor_svr *)new freetdscursor((sqlrconnection_svr *)this);}void freetdsconnection::deleteCursor(sqlrcursor_svr *curs) {	// LAME: freetds only supports 1 cursor, but sqlrelay uses a	// multi-cursor paradigm, so we'll allow sqlrelay to think we're using	// more than 1 cursor, but really we're only using one, so some things	// won't work but there'll be no hard errors	singlecursorrefcount--;	if (!singlecursorrefcount) {		delete singlecursor;		singlecursor=NULL;	}	//delete (freetdscursor *)curs;}void freetdsconnection::logOut() {	cs_loc_drop(context,locale);	ct_close(dbconn,CS_UNUSED);	ct_con_drop(dbconn);	ct_exit(context,CS_UNUSED);	cs_ctx_drop(context);}const char *freetdsconnection::identify() {	return "freetds";}const char *freetdsconnection::dbVersion() {	return dbversion;}const char *freetdsconnection::bindFormat() {	return "@*";}char freetdsconnection::bindVariablePrefix() {	return '@';}freetdscursor::freetdscursor(sqlrconnection_svr *conn) : sqlrcursor_svr(conn) {	// LAME: freetds only supports 1 cursor, but sqlrelay uses a	// multi-cursor paradigm, so we'll allow sqlrelay to think we're using	// more than 1 cursor, but really we're only using one, so some things	// won't work but there'll be no hard errors	opencount=0;	#if defined(VERSION_NO)	char	*versionstring=charstring::duplicate(VERSION_NO);	#elif defined(TDS_VERSION_NO)	char	*versionstring=charstring::duplicate(TDS_VERSION_NO);	#else	char	*versionstring=charstring::duplicate("freetds v0.00.0");	#endif	char	*v=charstring::findFirst(versionstring,'v');	if (v) {		*v=(char)NULL;		majorversion=charstring::toInteger(v+1);		char	*firstdot=charstring::findFirst(v+1,'.');		if (firstdot) {			*firstdot=(char)NULL;			minorversion=charstring::toInteger(firstdot+1);			char	*seconddot=				charstring::findFirst(firstdot+1,'.');			if (seconddot) {				*seconddot=(char)NULL;				patchlevel=charstring::toInteger(seconddot+1);			} else {				patchlevel=0;			}		} else {			minorversion=0;			patchlevel=0;		}	} else {		majorversion=0;		minorversion=0;		patchlevel=0;	}	prepared=false;	freetdsconn=(freetdsconnection *)conn;	cmd=NULL;	languagecmd=NULL;	cursorcmd=NULL;	cursorname=NULL;	// replace the regular expressions used to detect creation of a	// temporary table	createtemp.compile("(create|CREATE)[ \\t\\r\\n]+(table|TABLE)[ \\t\\r\\n]+#");	createtemp.study();	cursorquery.compile("^(select|SELECT)[ \\t\\r\\n]+");	cursorquery.study();	rpcquery.compile("^(execute|EXECUTE|exec|EXEC)[ \\t\\r\\n]+");	rpcquery.study();}freetdscursor::~freetdscursor() {	closeCursor();	delete[] cursorname;}bool freetdscursor::openCursor(uint16_t id) {	// LAME: freetds only supports 1 cursor, but sqlrelay uses a	// multi-cursor paradigm, so we'll allow sqlrelay to think we're using	// more than 1 cursor, but really we're only using one, so some things	// won't work but there'll be no hard errors	opencount++;	if (opencount>1) {		return true;	}	//freetdsconn->abortAllCursors();	clean=true;	cursorname=charstring::parseNumber(id);	if (ct_cmd_alloc(freetdsconn->dbconn,&languagecmd)!=CS_SUCCEED) {		return false;	}	if (ct_cmd_alloc(freetdsconn->dbconn,&cursorcmd)!=CS_SUCCEED) {		return false;	}	cmd=NULL;	// switch to the correct database	// (only do this once per connection)	bool	retval=true;	if (freetdsconn->db && freetdsconn->db[0] && !freetdsconn->dbused) {		uint32_t	len=charstring::length(freetdsconn->db)+4;		char		query[len+1];		snprintf(query,len+1,"use %s",freetdsconn->db);		if (!(prepareQuery(query,len) &&				executeQuery(query,len,true))) {			bool	live;			fprintf(stderr,"%s\n",errorMessage(&live));			retval=false;		} else {			freetdsconn->dbused=true;		}		cleanUpData(true,true);	}	if (!freetdsconn->dbversion) {		char	*query="sp_version installmaster";		int32_t	len=charstring::length(query);		if (!(prepareQuery(query,len) &&				executeQuery(query,len,true) &&				fetchRow())) {			freetdsconn->dbversion=				charstring::duplicate("unknown");		} else {			const char	*space=				charstring::findFirst(data[1][0],' ');			freetdsconn->dbversion=				charstring::duplicate(data[1][0],							space-data[1][0]);		}		cleanUpData(true,true);	}	return (retval && sqlrcursor_svr::openCursor(id));}bool freetdscursor::closeCursor() {	// LAME: freetds only supports 1 cursor, but sqlrelay uses a	// multi-cursor paradigm, so we'll allow sqlrelay to think we're using	// more than 1 cursor, but really we're only using one, so some things	// won't work but there'll be no hard errors	if (opencount>1) {		return true;	}	opencount--;	bool	retval=true;	if (languagecmd) {		retval=(ct_cmd_drop(languagecmd)==CS_SUCCEED);		languagecmd=NULL;	}	if (cursorcmd) {		retval=(retval && (ct_cmd_drop(cursorcmd)==CS_SUCCEED));		cursorcmd=NULL;	}	cmd=NULL;	return retval;}bool freetdscursor::prepareQuery(const char *query, uint32_t length) {	// if the client aborts while a query is in the middle of running,	// commit or rollback will be called, potentially before cleanUpData	// is called and, since we're really only using 1 cursor, it will fail	// unless cleanUpData gets called, so just to make sure, we'll call it	// here	cleanUpData(true,true);	clean=true;	this->query=(char *)query;	this->length=length;	paramindex=0;	outbindindex=0;	isrpcquery=false;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -