From 527ca0efb731a0f00ca5b23ad4c91a2705b1948f Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 28 Jun 2004 23:20:04 +0000 Subject: [PATCH] New DBI API. --- dlls/mssql/mssql.cpp | 534 ++++++++++++++++++++------------------- dlls/mssql/mssql.h | 23 +- dlls/mssql/mssql.vcproj | 5 +- dlls/mssql/mssql_amx.cpp | 305 ++++++++++++++++++++++ dlls/mssql/mssql_amx.h | 63 +++++ 5 files changed, 649 insertions(+), 281 deletions(-) create mode 100755 dlls/mssql/mssql_amx.cpp create mode 100755 dlls/mssql/mssql_amx.h diff --git a/dlls/mssql/mssql.cpp b/dlls/mssql/mssql.cpp index 4506ba27..40c7aebe 100755 --- a/dlls/mssql/mssql.cpp +++ b/dlls/mssql/mssql.cpp @@ -1,339 +1,357 @@ -/* by David "BAILOPAN" Anderson -* http://www.bailopan.com +/* AMX Mod X +* MSSQL Module * -* This program is free software; you can redistribute it and/or modify it -* under the terms of the GNU General Public License as published by the -* Free Software Foundation; either version 2 of the License, or (at -* your option) any later version. +* by BAILOPAN * -* This program is distributed in the hope that it will be useful, but -* WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. +* This file is part of AMX Mod X. * -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software Foundation, -* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. */ -#include "mssql.h" + +#include +#include "mssql_amx.h" +#include "amxxmodule.h" using namespace std; -std::vector DBList; +std::vector Results; +std::vector DBList; -std::string error; -int lastError = 0; - -bool msdb::Kill() -{ - host.clear(); - pass.clear(); - dbname.clear(); - user.clear(); - free = true; - try { - cn->Close(); - cn = NULL; - if (res) - res->Close(); - res = NULL; - } catch(_com_error &e) { - _bstr_t bstrSource(e.Description()); - error.assign((LPCSTR)bstrSource); - lastError = e.Error(); - return false; - } - - return true; -} - -bool msdb::Connect() -{ - HRESULT hr; - cstr.assign("Provider=sqloledb;Network Library=DBMSSOCN;"); - cstr.append("Data Source="); - cstr.append(host); - cstr.append(";Initial Catalog="); - cstr.append(dbname); - cstr.append(";User ID="); - cstr.append(user); - cstr.append(";Password="); - cstr.append(pass); - try { - hr = cn.CreateInstance(__uuidof(ADODB::Connection)); - cn->Open(cstr.c_str(), user.c_str(), pass.c_str(), NULL); - } catch (_com_error &e) { - _bstr_t bstrSource(e.Description()); - error.assign((LPCSTR)bstrSource); - lastError = e.Error(); - return false; - } - - return 1; -} - -int sql_exists(char *user, char *pass, char *db, char *host) -{ - std::vector::iterator i; +int sql_exists(const char* host,const char* user,const char* pass,const char* dbase) { + vector::iterator i; int id = 0; for (i=DBList.begin(); i!=DBList.end(); i++) { id++; - if (((*i)->user.compare(user) == 0) && - ((*i)->pass.compare(pass) == 0) && - ((*i)->dbname.compare(db) == 0) && - ((*i)->host.compare(host) == 0) && - (!(*i)->free)) { - - return id; + if (((*i)->Host.compare(host) == 0) && + ((*i)->Username.compare(user) == 0) && + ((*i)->Password.compare(pass) == 0) && + ((*i)->Database.compare(dbase) == 0) && + (!(*i)->isFree)) { + return id; } } - return -1; } -static cell AMX_NATIVE_CALL mssql_connect(AMX *amx, cell *params) -{ - int len; - unsigned int i; - msdb *c = NULL; - char *host = MF_GetAmxString(amx, params[1], 0, &len); - char *user = MF_GetAmxString(amx, params[2], 1, &len); - char *pass = MF_GetAmxString(amx, params[3], 2, &len); - char *dbn = MF_GetAmxString(amx, params[4], 3, &len); +// /////////////////////////////// +// mssql natives for AMX scripting +// /////////////////////////////// - int id = sql_exists(user, pass, dbn, host); - if (id >= 0) +// sql = mssql_connect(host[],user[],pass[],dbname[],error[],maxlength) : +// - open connection +static cell AMX_NATIVE_CALL sql_connect(AMX *amx, cell *params) // 6 param +{ + int i; + char *host = MF_GetAmxString(amx,params[1], 0, &i); + char *user = MF_GetAmxString(amx,params[2], 1, &i); + char *pass = MF_GetAmxString(amx,params[3], 2, &i); + char *dbname = MF_GetAmxString(amx,params[4], 3, &i); + i = 0; + + if (!strlen(host) || !strlen(user) || !strlen(dbname)) { + MF_RaiseAmxError(amx, AMX_ERR_NATIVE); + return -1; + } + + int id = sql_exists(host,user,pass,dbname); + + if (id > 0) return id; - id = -1; - for (i=0; ifree) { + + SQL *c=NULL; + + for (i=0; (unsigned int)iisFree) { id = i; break; } } - if (id < 0) { - c = new msdb; - DBList.push_back(c); - id = DBList.size() - 1; + if (id>=0) { + c = DBList[id]; } else { - c = DBList.at(id); + c = new SQL; + DBList.push_back(c); + id = (unsigned int)(DBList.size() - 1); } - c->host.assign(host); - c->user.assign(user); - c->pass.assign(pass); - c->dbname.assign(dbn); - - try { - if (c->Connect()) { - c->free = false; - return id+1; - } - } catch (_com_error &e) { - _bstr_t bstrSource(e.Description()); - error.assign((LPCSTR)bstrSource); - lastError = e.Error(); - MF_SetAmxString(amx, params[5], error.c_str(), params[6]); + + if (!c->Connect(host, user, pass, dbname)) + { + MF_SetAmxString(amx, params[5], c->ErrorStr.c_str(), params[6]); return -1; } - c->free = true; - return -1; + MF_SetAmxString(amx,params[5],"",params[6]); + + return id+1; } -static cell AMX_NATIVE_CALL mssql_close(AMX *amx, cell *params) +// mssql_error(sql,dest[],maxlength) +// - store maxlength characters from mssql error in current row to dest +static cell AMX_NATIVE_CALL sql_error(AMX *amx, cell *params) // 3 params { - unsigned int id = params[1] - 1; - - if (id >= DBList.size() || DBList.at(id)->free) { - error.assign("Invalid handle."); + unsigned int id = params[1]-1; + if (id >= DBList.size() || DBList[id]->isFree) + { MF_RaiseAmxError(amx, AMX_ERR_NATIVE); return 0; } - return DBList.at(id)->Kill(); -} - -static cell AMX_NATIVE_CALL mssql_query(AMX *amx, cell *params) -{ - unsigned int id = params[1] - 1; + SQL *sql = DBList[id]; - if (id >= DBList.size() || DBList.at(id)->free) { - error.assign("Invalid handle."); - MF_RaiseAmxError(amx, AMX_ERR_NATIVE); - return 0; - } - - msdb *c = NULL; - c = DBList.at(id); - - try { - if (c->res) { - c->res->Close(); - c->res = NULL; - } - } catch (_com_error &e) { - /* Nothing */ - } - - int len; - const char *query = MF_FormatAmxString(amx, params, 2, &len); - c->resStart = false; - - try { - HRESULT hr = c->res.CreateInstance(__uuidof(ADODB::Recordset)); - if (FAILED(hr)) { - return 0; - } - c->res->CursorType = ADODB::adOpenStatic; - c->res->Open((_bstr_t)query, (_bstr_t)c->cstr.c_str(), ADODB::adOpenForwardOnly, ADODB::adLockReadOnly, ADODB::adCmdText); - c->resStart = true; - } catch (_com_error &e) { - _bstr_t bstrSource(e.Description()); - error.assign((LPCSTR)bstrSource); - lastError = e.Error(); - return -1; - } - - try { - c->res->MoveFirst(); - } catch (_com_error &e) { + if (sql->ErrorStr.size() > 1) + { + MF_SetAmxString(amx, params[2], sql->ErrorStr.c_str(), params[3]); + sql->ErrorStr.assign(""); return 1; + } else { + if (sql->ErrorStr.size() > 1) + { + MF_SetAmxString(amx, params[2], sql->ErrorStr.c_str(), params[3]); + sql->ErrorStr.assign(""); + return 1; + } } + MF_SetAmxString(amx, params[2], "", params[3]); + + return 0; +} + +// mssql_query(sql,query[]) - returns 0 on success, <0 on failure, >0 on result set +static cell AMX_NATIVE_CALL sql_query(AMX *amx, cell *params) // 2 params +{ + unsigned int id = params[1]-1; + + if (id >= DBList.size() || DBList[id]->isFree) { + MF_Log("Invalid Database Handle %d", id); + MF_RaiseAmxError(amx, AMX_ERR_NATIVE); + return -1; + } + + int len = 0; + const char *query = MF_FormatAmxString(amx, params, 2, &len); + + SQL *sql = DBList[id]; + + return sql->Query(query); //Return the result set handle, if any +} + +// mssql_nextrow(sql) : +// - read next row +// - return : +// . number of line +// . 0 at end +static cell AMX_NATIVE_CALL sql_nextrow(AMX *amx, cell *params) // 1 param +{ + unsigned int id = params[1]-1; + + if (id >= Results.size() || Results[id]->isFree) + { + MF_Log("Invalid result handle %d", id); + MF_RaiseAmxError(amx, AMX_ERR_NATIVE); + return 0; + } + + SQLResult *Result = Results[id]; + + return Result->Nextrow(); +} + + +// mssql_close(sql) : +// - free result +// - close connection +static cell AMX_NATIVE_CALL sql_close(AMX *amx, cell *params) // 1 param +{ + unsigned int id = params[1]-1; + if (id >= DBList.size() || DBList[id]->isFree) { + MF_Log("Invalid Database Handle %d", id); + MF_RaiseAmxError(amx, AMX_ERR_NATIVE); + return 0; + } + + SQL *sql = DBList[id]; + + sql->Disconnect(); return 1; } -static cell AMX_NATIVE_CALL mssql_nextrow(AMX *amx, cell *params) +//Returns a field from a query result handle. +// 2 param - returns integer +// 3 param - stores float in cell byref +// 4 param - stores string +static cell AMX_NATIVE_CALL sql_getfield(AMX *amx, cell *params) // 2-4 params { - unsigned int id = params[1] - 1; - - if (id >= DBList.size() || DBList.at(id)->free) { - error.assign("Invalid handle."); + unsigned int id = params[1]-1; + + if (id >= Results.size() || Results[id]->isFree) + { + MF_Log("Invalid result handle %d", id); MF_RaiseAmxError(amx, AMX_ERR_NATIVE); return 0; } - msdb *c = NULL; - c = DBList.at(id); - - if (c->res == NULL) + SQLResult *Result = Results[id]; + int numParams = (*params)/sizeof(cell); + cell *fAddr = NULL; + const char *field = Result->GetField(id); + if (field == NULL) + { + MF_RaiseAmxError(amx, AMX_ERR_NATIVE); return 0; + } - try { - if (c->res->ADOEOF) - return 0; - c->res->MoveNext(); - if (c->res->ADOEOF) - return 0; + switch (numParams) + { + case 2: + return atoi(field); + break; + case 3: + fAddr = MF_GetAmxAddr(amx, params[3]); + *fAddr = amx_ftoc((REAL)atof(field)); return 1; - } catch (_com_error &e) { - _bstr_t bstrSource(e.Description()); - error.assign((LPCSTR)bstrSource); - lastError = e.Error(); - return -1; + break; + case 4: + return MF_SetAmxString(amx, params[3], field?field:"", params[4]); + break; + default: + break; } return 0; } -static cell AMX_NATIVE_CALL mssql_getfield(AMX *amx, cell *params) +//Returns a field from a query result handle. +// 2 param - returns integer +// 3 param - stores float in cell byref +// 4 param - stores string +static cell AMX_NATIVE_CALL sql_getresult(AMX *amx, cell *params) // 4 params { - unsigned int id = params[1] - 1; - - if (id >= DBList.size() || DBList.at(id)->free) { - error.assign("Invalid handle."); + unsigned int id = params[1]-1; + + if (id >= Results.size() || Results[id]->isFree) + { + MF_Log("Invalid result handle %d", id); MF_RaiseAmxError(amx, AMX_ERR_NATIVE); return 0; } - msdb *c = NULL; - c = DBList.at(id); - - try { - if (c->res->ADOEOF) - return 0; - ADODB::FieldPtr pFld = NULL; - _variant_t index = (short)params[2]; - pFld = c->res->Fields->GetItem(&index); - _variant_t FldVal = pFld->GetValue(); - switch (FldVal.vt) - { - case (VT_BOOL): - if (FldVal.boolVal) { - MF_SetAmxString(amx, params[3], "1", params[4]); - } else { - MF_SetAmxString(amx, params[3], "0", params[4]); - } - break; - case (VT_BSTR): - MF_SetAmxString(amx, params[3], (LPCSTR)(_bstr_t)FldVal.bstrVal, params[4]); - break; - case (VT_I4): - MF_SetAmxString(amx, params[3], (LPCSTR)FldVal.iVal, params[4]); - break; - case (VT_EMPTY): - MF_SetAmxString(amx, params[3], (LPCSTR)FldVal.iVal, params[4]); - break; - default: - return 0; - break; - } - } catch (_com_error &e) { - _bstr_t bstrSource(e.Description()); - error.assign((LPCSTR)bstrSource); - lastError = e.Error(); - return -1; + SQLResult *Result = Results[id]; + int numParams = (*params)/sizeof(cell); + cell *fAddr = NULL; + int len = 0; + const char *column = MF_GetAmxString(amx, params[2], 0, &len); + const char *field = Result->GetField(id); + if (field == NULL) + { + MF_RaiseAmxError(amx, AMX_ERR_NATIVE); + return 0; } + switch (numParams) + { + case 2: + return atoi(field); + break; + case 3: + fAddr = MF_GetAmxAddr(amx, params[3]); + *fAddr = amx_ftoc((REAL)atof(field)); + return 1; + break; + case 4: + return MF_SetAmxString(amx, params[3], field?field:"", params[4]); + break; + default: + break; + } + + return 0; +} + +static cell AMX_NATIVE_CALL sql_free_result(AMX *amx, cell *params) +{ + unsigned int id = params[1]-1; + + if (id >= Results.size() || Results[id]->isFree) + { + MF_Log("Invalid result handle %d", id); + MF_RaiseAmxError(amx, AMX_ERR_NATIVE); + return 0; + } + + SQLResult *Result = Results[id]; + + Result->FreeResult(); + return 1; } -static cell AMX_NATIVE_CALL mssql_error(AMX *amx, cell *params) +static cell AMX_NATIVE_CALL sql_num_rows(AMX *amx, cell *params) { - MF_SetAmxString(amx, params[2], error.c_str(), params[3]); - return lastError; + unsigned int id = params[1]-1; + + if (id >= Results.size() || Results[id]->isFree) + { + MF_Log("Invalid result handle %d", id); + MF_RaiseAmxError(amx, AMX_ERR_NATIVE); + return 0; + } + + SQLResult *Result = Results[id]; + + return (cell)Result->NumRows(); } -static cell AMX_NATIVE_CALL dbi_type(AMX *amx, cell *params) +static cell AMX_NATIVE_CALL sql_type(AMX *amx, cell *params) { return MF_SetAmxString(amx, params[1], "mssql", params[2]); } +AMX_NATIVE_INFO mssql_Natives[] = { + { "dbi_connect", sql_connect }, + { "dbi_query", sql_query }, + { "dbi_field", sql_getfield }, + { "dbi_nextrow", sql_nextrow }, + { "dbi_close", sql_close }, + { "dbi_error", sql_error }, + { "dbi_type", sql_type }, + { "dbi_free_result", sql_free_result }, + { "dbi_num_rows", sql_num_rows }, + { "dbi_result", sql_getresult }, + { NULL, NULL } +}; void OnAmxxAttach() { MF_AddNatives(mssql_Natives); - if(FAILED(::CoInitialize(NULL))) - return; } -void onAmxxDetach() +void OnAmxxDetach() { - std::vector::iterator i; - for (i=DBList.begin(); i!=DBList.end(); i++) { - (*i)->Kill(); - } - ::CoUninitialize(); - return; + Results.clear(); + DBList.clear(); } - -AMX_NATIVE_INFO mssql_Natives[] = { - {"mssql_connect", mssql_connect}, - {"dbi_connect", mssql_connect}, - {"mssql_close", mssql_close}, - {"dbi_close", mssql_close}, - {"mssql_query", mssql_query}, - {"dbi_query", mssql_query}, - {"mssql_getfield", mssql_getfield}, - {"dbi_getfield", mssql_getfield}, - {"mssql_nextrow", mssql_nextrow}, - {"dbi_nextrow", mssql_nextrow}, - {"mssql_error", mssql_error}, - {"dbi_error", mssql_error}, - {"dbi_type", dbi_type}, - - {NULL, NULL}, - /////////////////// -}; \ No newline at end of file diff --git a/dlls/mssql/mssql.h b/dlls/mssql/mssql.h index fc55c0bd..93447554 100755 --- a/dlls/mssql/mssql.h +++ b/dlls/mssql/mssql.h @@ -22,29 +22,8 @@ #import "c:\Program Files\Common Files\System\ADO\msado15.dll" rename("EOF", "ADOEOF") #include #include -#include + #include "amxxmodule.h" -class msdb -{ -public: - ADODB::_ConnectionPtr cn; - ADODB::_RecordsetPtr res; - msdb() { free = true; res=NULL; resStart = false; } - ~msdb() { Kill(); } - std::string user; - std::string pass; - std::string dbname; - std::string host; - std::string cstr; - std::string error; - bool Connect(); - bool Kill(); - bool free; - bool resStart; -}; - -extern std::vector DBList; -extern AMX_NATIVE_INFO mssql_Natives[]; #endif //_INCLUDE_MSSQL_H diff --git a/dlls/mssql/mssql.vcproj b/dlls/mssql/mssql.vcproj index 62cf9218..0a9b3461 100755 --- a/dlls/mssql/mssql.vcproj +++ b/dlls/mssql/mssql.vcproj @@ -118,6 +118,9 @@ + + @@ -137,7 +140,7 @@ Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"> + RelativePath=".\mssql_amx.h"> ADOEOF) + { + return ""; + } + ADODB::FieldPtr pFld = NULL; + _variant_t index = (short)field; + pFld = res->Fields->GetItem(&index); + _variant_t FldVal = pFld->GetValue(); + switch (FldVal.vt) + { + case (VT_BOOL): + if (FldVal.boolVal) { + return "1"; + } else { + return "0"; + } + break; + case (VT_BSTR): + LastResult.assign((LPCSTR)(_bstr_t)FldVal.bstrVal); + break; + case (VT_I4): + sprintf(buf, "%d", FldVal.iVal); + buf[255] = 0; + LastResult.assign(buf); + break; + case (VT_EMPTY): + sprintf(buf, "%d", FldVal.iVal); + buf[255] = 0; + LastResult.assign(buf); + break; + default: + LastResult.assign(""); + break; + } + } catch (_com_error &e) { + sql->Error(e); + return 0; + } + + return LastResult.c_str(); +} + +const char *SQLResult::GetField(const char *field) +{ + if (isFree) + { + return ""; + } + + char buf[256]; + + try { + if (res->ADOEOF) + { + return ""; + } + ADODB::FieldPtr pFld = NULL; + pFld = res->Fields->GetItem(field); + _variant_t FldVal = pFld->GetValue(); + switch (FldVal.vt) + { + case (VT_BOOL): + if (FldVal.boolVal) { + return "1"; + } else { + return "0"; + } + break; + case (VT_BSTR): + LastResult.assign((_bstr_t)FldVal.bstrVal); + break; + case (VT_I4): + sprintf(buf, "%d", FldVal.iVal); + buf[255] = 0; + LastResult.assign(buf); + break; + case (VT_EMPTY): + sprintf(buf, "%d", FldVal.iVal); + buf[255] = 0; + LastResult.assign(buf); + break; + default: + LastResult.assign(""); + break; + } + } catch (_com_error &e) { + sql->Error(e); + return 0; + } + + return LastResult.c_str(); +} + +unsigned int SQLResult::NumRows() +{ + if (isFree) + return 0; + + return (unsigned int)(res->RecordCount); +} \ No newline at end of file diff --git a/dlls/mssql/mssql_amx.h b/dlls/mssql/mssql_amx.h new file mode 100755 index 00000000..8d52e412 --- /dev/null +++ b/dlls/mssql/mssql_amx.h @@ -0,0 +1,63 @@ +#ifndef _INCLUDE_MSSQL_H +#define _INCLUDE_MSSQL_H + +#import "c:\Program Files\Common Files\System\ADO\msado15.dll" rename("EOF", "ADOEOF") + +#include +#include +#include +#include "amxxmodule.h" + +class SQL +{ +public: + SQL(); + ~SQL(); + int Connect(const char *host, const char *user, const char *pass, const char *base); + int Query(const char *query); + void Disconnect(); + int Error(_com_error &e); + + ADODB::_ConnectionPtr cn; + + std::string ErrorStr; + int ErrorCode; + + std::string Host; + std::string Password; + std::string Username; + std::string Database; + std::string cstr; + + bool isFree; +}; + +class SQLResult +{ +public: + SQLResult(); + ~SQLResult(); + int Query(SQL *cn, const char *query); + bool Nextrow(); + void FreeResult(); + const char *GetField(unsigned int field); + const char *GetField(const char *field); + unsigned int NumRows(); + + int FieldCount; + int RowCount; + bool isFree; + bool isStart; + + SQL *sql; + + ADODB::_RecordsetPtr res; + std::string LastResult; +}; + +char *amx_string(AMX *amx, cell ¶m, int &len); + +extern std::vector Results; +extern std::vector DBList; + +#endif //MSSQL \ No newline at end of file