📄 mysqlconnection.c
字号:
// Copyright (c) 1999-2001 David Muse// See the file COPYING for more information#include <rudiments/charstring.h>#include <rudiments/rawbuffer.h>#include <mysqlconnection.h>#if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID>=32200 #include <errmsg.h>#endif#include <datatypes.h>#include <config.h>#include <stdlib.h>#include <unistd.h>#ifdef MYSQL_OPT_RECONNECTconst my_bool mysqlconnection::mytrue=TRUE;#endifmysqlconnection::mysqlconnection() : sqlrconnection_svr() { connected=false;#ifdef HAVE_MYSQL_STMT_PREPARE fakebinds=false;#endif dbversion=NULL; // start this at false because we don't need to do a commit before // the first query when we very first start up firstquery=false;}mysqlconnection::~mysqlconnection() { delete[] dbversion;}uint16_t mysqlconnection::getNumberOfConnectStringVars() { return NUM_CONNECT_STRING_VARS;}void mysqlconnection::handleConnectString() { setUser(connectStringValue("user")); setPassword(connectStringValue("password")); db=connectStringValue("db"); host=connectStringValue("host"); port=connectStringValue("port"); socket=connectStringValue("socket");#ifdef HAVE_MYSQL_STMT_PREPARE fakebinds=!charstring::compare(connectStringValue("fakebinds"),"yes");#endif}bool mysqlconnection::logIn(bool printerrors) { // Handle host. // For really old versions of mysql, a NULL host indicates that the // unix socket should be used. There's no way to specify what unix // socket or inet port to connect to, those values are hardcoded // into the client library. // For some newer versions, a NULL host causes problems, but an empty // string is safe.#ifdef HAVE_MYSQL_REAL_CONNECT_FOR_SURE const char *hostval=(host && host[0])?host:"";#else const char *hostval=(host && host[0])?host:NULL;#endif // Handle db. const char *dbval=(db && db[0])?db:""; // log in const char *user=getUser(); const char *password=getPassword();#ifdef HAVE_MYSQL_REAL_CONNECT_FOR_SURE // Handle port and socket. int portval=(port && port[0])?charstring::toInteger(port):0; const char *socketval=(socket && socket[0])?socket:NULL; unsigned long clientflag=0; #ifdef CLIENT_MULTI_STATEMENTS clientflag=CLIENT_MULTI_STATEMENTS; #endif #if MYSQL_VERSION_ID>=32200 // initialize database connection structure if (!mysql_init(&mysql)) { if (printerrors) { fprintf(stderr,"mysql_init failed\n"); } return false; } if (!mysql_real_connect(&mysql,hostval,user,password,dbval, portval,socketval,clientflag)) { #else if (!mysql_real_connect(&mysql,hostval,user,password, portval,socketval,clientflag)) { #endif if (printerrors) { fprintf(stderr,"mysql_real_connect failed: %s\n", mysql_error(&mysql)); }#else if (!mysql_connect(&mysql,hostval,user,password)) { if (printerrors) { fprintf(stderr,"mysql_connect failed: %s\n", mysql_error(&mysql)); }#endif logOut(); return false; }#ifdef MYSQL_OPT_RECONNECT // Enable autoreconnect in the C api // (ordinarily mysql_options should be called before mysql_connect, // but not for this option) mysql_options(&mysql,MYSQL_OPT_RECONNECT,&mytrue);#endif#ifdef MYSQL_SELECT_DB if (mysql_select_db(&mysql,dbval)) { if (printerrors) { fprintf(stderr,"mysql_select_db failed: %s\n", mysql_error(&mysql)); } logOut(); return false; }#endif connected=true;#ifdef HAVE_MYSQL_STMT_PREPARE // fake binds when connected to older servers#ifdef HAVE_MYSQL_GET_SERVER_VERSION if (mysql_get_server_version(&mysql)<40102) { fakebinds=true; }#else char **list; uint64_t listlen; charstring::split(mysql_get_server_info(&mysql), ".",true,&list,&listlen); if (listlen==3) { uint64_t major=charstring::toUnsignedInteger(list[0]); uint64_t minor=charstring::toUnsignedInteger(list[1]); uint64_t patch=charstring::toUnsignedInteger(list[2]); if (major>4 || (major==4 && minor>1) || (major==4 && minor==1 && patch>=2)) { fakebinds=true; } for (uint64_t index=0; index<listlen; index++) { delete[] list[index]; } delete[] list; }#endif#endif return true;}#ifdef HAVE_MYSQL_CHANGE_USERbool mysqlconnection::changeUser(const char *newuser, const char *newpassword) { return !mysql_change_user(&mysql,newuser,newpassword, (char *)((db && db[0])?db:""));}#endifsqlrcursor_svr *mysqlconnection::initCursor() { return (sqlrcursor_svr *)new mysqlcursor((sqlrconnection_svr *)this);}void mysqlconnection::deleteCursor(sqlrcursor_svr *curs) { delete (mysqlcursor *)curs;}void mysqlconnection::logOut() { connected=false; mysql_close(&mysql);}#ifdef HAVE_MYSQL_PINGbool mysqlconnection::ping() { return (!mysql_ping(&mysql))?true:false;}#endifconst char *mysqlconnection::identify() { return "mysql";}const char *mysqlconnection::dbVersion() { delete[] dbversion; dbversion=charstring::duplicate(mysql_get_server_info(&mysql)); return dbversion;}const char *mysqlconnection::bindFormat() {#ifdef HAVE_MYSQL_STMT_PREPARE if (fakebinds) { return sqlrconnection_svr::bindFormat(); } else { return "?"; }#else return sqlrconnection_svr::bindFormat();#endif}bool mysqlconnection::isTransactional() { return true;}bool mysqlconnection::autoCommitOn() {#ifdef HAVE_MYSQL_AUTOCOMMIT return !mysql_autocommit(&mysql,true);#else // do nothing return true;#endif}bool mysqlconnection::autoCommitOff() {#ifdef HAVE_MYSQL_AUTOCOMMIT return !mysql_autocommit(&mysql,false);#else // do nothing return true;#endif}bool mysqlconnection::commit() {#ifdef HAVE_MYSQL_COMMIT return !mysql_commit(&mysql);#else // do nothing return true;#endif}bool mysqlconnection::rollback() {#ifdef HAVE_MYSQL_ROLLBACK return !mysql_rollback(&mysql);#else // do nothing return true;#endif}#ifdef HAVE_MYSQL_STMT_PREPAREshort mysqlconnection::nonNullBindValue() { return 0;}short mysqlconnection::nullBindValue() { return 1;}#endifvoid mysqlconnection::endSession() { firstquery=true;}mysqlcursor::mysqlcursor(sqlrconnection_svr *conn) : sqlrcursor_svr(conn) { mysqlconn=(mysqlconnection *)conn; mysqlresult=NULL; columnnames=NULL;#ifdef HAVE_MYSQL_STMT_PREPARE usestmtprepare=true; unsupportedbystmt.compile("^\\s*(((create|CREATE|drop|DROP)\\s+" "(procedure|PROCEDURE|function|FUNCTION))|" "(CALL|call)|(START|start)|(BEGIN|begin))\\s+"); unsupportedbystmt.study(); stmt=mysql_stmt_init(&mysqlconn->mysql); for (unsigned short index=0; index<MAX_SELECT_LIST_SIZE; index++) { fieldbind[index].buffer_type=MYSQL_TYPE_STRING; fieldbind[index].buffer=(char *)&field[index]; fieldbind[index].buffer_length=MAX_ITEM_BUFFER_SIZE; fieldbind[index].is_null=&isnull[index]; fieldbind[index].length=&fieldlength[index]; }#endif}mysqlcursor::~mysqlcursor() { delete[] columnnames;#ifdef HAVE_MYSQL_STMT_PREPARE mysql_stmt_free_result(stmt); mysql_stmt_close(stmt); if (mysqlresult) { mysql_free_result(mysqlresult); }#endif}#ifdef HAVE_MYSQL_STMT_PREPAREbool mysqlcursor::prepareQuery(const char *query, uint32_t length) { // if this if the first query of the session, do a commit first, // doing this will refresh this connection with any data committed // by other connections, which is what would happen if a new client // connected directly to mysql if (mysqlconn->firstquery) { mysqlconn->commit(); mysqlconn->firstquery=false; } if (mysqlconn->fakebinds) { return true; } // can't use stmt API to run a couple of types of queries as of 5.0 usestmtprepare=true; if (unsupportedbystmt.match(query)) { usestmtprepare=false; return true; } // store inbindcount here, otherwise if rebinding/reexecution occurs and // the client tries to bind more variables than were defined when the // query was prepared, it would cause the inputBind methods to attempt // to address beyond the end of the various arrays bindcount=inbindcount; // reset bind counter bindcounter=0; // re-init bind buffers rawbuffer::zero(&bind,sizeof(bind)); return !mysql_stmt_prepare(stmt,query,length);}#endifbool mysqlcursor::supportsNativeBinds() {#ifdef HAVE_MYSQL_STMT_PREPARE return (!mysqlconn->fakebinds && usestmtprepare);#else return false;#endif}#ifdef HAVE_MYSQL_STMT_PREPAREbool mysqlcursor::inputBindString(const char *variable, uint16_t variablesize, const char *value, uint16_t valuesize, int16_t *isnull) { if (mysqlconn->fakebinds || !usestmtprepare) { return true; } // don't attempt to bind beyond the number of // variables defined when the query was prepared if (bindcounter>bindcount) { return false; } bindvaluesize[bindcounter]=valuesize; if (*isnull) { bind[bindcounter].buffer_type=MYSQL_TYPE_NULL; bind[bindcounter].buffer=(void *)NULL; bind[bindcounter].buffer_length=0; bind[bindcounter].length=0; } else { bind[bindcounter].buffer_type=MYSQL_TYPE_STRING; bind[bindcounter].buffer=(void *)value; bind[bindcounter].buffer_length=valuesize; bind[bindcounter].length=&bindvaluesize[bindcounter]; } bind[bindcounter].is_null=(my_bool *)isnull; bindcounter++; return true;}bool mysqlcursor::inputBindInteger(const char *variable, uint16_t variablesize, int64_t *value) { if (mysqlconn->fakebinds || !usestmtprepare) { return true; } // don't attempt to bind beyond the number of // variables defined when the query was prepared if (bindcounter>bindcount) { return false; } bindvaluesize[bindcounter]=sizeof(int64_t); if (*isnull) { bind[bindcounter].buffer_type=MYSQL_TYPE_NULL; bind[bindcounter].buffer=(void *)NULL; bind[bindcounter].buffer_length=0; bind[bindcounter].length=0; } else { bind[bindcounter].buffer_type=MYSQL_TYPE_LONGLONG; bind[bindcounter].buffer=(void *)value; bind[bindcounter].buffer_length=sizeof(int64_t); bind[bindcounter].length=&bindvaluesize[bindcounter]; } bind[bindcounter].is_null=(my_bool *)isnull; bindcounter++; return true;}bool mysqlcursor::inputBindDouble(const char *variable, uint16_t variablesize, double *value, uint32_t precision, uint32_t scale) { if (mysqlconn->fakebinds || !usestmtprepare) { return true; } // don't attempt to bind beyond the number of // variables defined when the query was prepared if (bindcounter>bindcount) { return false; } bindvaluesize[bindcounter]=sizeof(double); if (*isnull) { bind[bindcounter].buffer_type=MYSQL_TYPE_NULL; bind[bindcounter].buffer=(void *)NULL; bind[bindcounter].buffer_length=0; bind[bindcounter].length=0; } else { bind[bindcounter].buffer_type=MYSQL_TYPE_DOUBLE; bind[bindcounter].buffer=(void *)value; bind[bindcounter].buffer_length=sizeof(double); bind[bindcounter].length=&bindvaluesize[bindcounter]; } bind[bindcounter].is_null=(my_bool *)isnull; bindcounter++; return true;}bool mysqlcursor::inputBindBlob(const char *variable, uint16_t variablesize, const char *value, uint32_t valuesize, int16_t *isnull) { if (mysqlconn->fakebinds || !usestmtprepare) { return true; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -