📄 freetdsconnection.c
字号:
// 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 + -