added backwards compat layer to old mysql module

This commit is contained in:
David Anderson 2006-04-24 10:27:25 +00:00
parent 768880fa92
commit 1c5b8670d9
9 changed files with 556 additions and 8 deletions

View File

@ -6,7 +6,6 @@ using namespace SourceMod;
using namespace SourceHook; using namespace SourceHook;
MysqlDriver g_Mysql; MysqlDriver g_Mysql;
List<unsigned int> g_ConnectionInfo;
void FreeConnection(void *p, unsigned int num) void FreeConnection(void *p, unsigned int num)
{ {
@ -17,8 +16,6 @@ void FreeConnection(void *p, unsigned int num)
free(cn->pass); free(cn->pass);
free(cn->db); free(cn->db);
g_ConnectionInfo.remove(num);
delete cn; delete cn;
} }
@ -60,8 +57,6 @@ static cell AMX_NATIVE_CALL SQL_MakeDbTuple(AMX *amx, cell *params)
unsigned int num = MakeHandle(sql, Handle_Connection, FreeConnection); unsigned int num = MakeHandle(sql, Handle_Connection, FreeConnection);
g_ConnectionInfo.push_back(num);
return num; return num;
} }

View File

@ -78,3 +78,30 @@ bool FreeHandle(unsigned int num)
return true; return true;
} }
void FreeAllHandles(HandleType type)
{
QHandle *q;
for (size_t i = 0; i < g_Handles.size(); i++)
{
q = g_Handles[i];
if (q && !q->isfree && q->type == type)
{
FreeHandle((unsigned int)i);
}
}
}
void FreeHandleTable()
{
QHandle *q;
for (size_t i = 0; i < g_Handles.size(); i++)
{
q = g_Handles[i];
if (q && !q->isfree)
FreeHandle((unsigned int)i);
}
g_Handles.clear();
while (!g_FreeHandles.empty())
g_FreeHandles.pop();
}

View File

@ -5,4 +5,16 @@ void OnAmxxAttach()
{ {
MF_AddNatives(g_BaseSqlNatives); MF_AddNatives(g_BaseSqlNatives);
MF_AddNatives(g_ThreadSqlNatives); MF_AddNatives(g_ThreadSqlNatives);
MF_RegisterFunction(&g_Mysql, "GetSqlDriver");
if (!MF_RequestFunction("GetDbDriver"))
{
MF_AddNatives(g_OldCompatNatives);
}
}
void ServerDeactivate_Post()
{
FreeAllHandles(Handle_OldResult);
FreeAllHandles(Handle_OldDb);
FreeAllHandles(Handle_Connection);
} }

View File

@ -126,6 +126,9 @@
<File <File
RelativePath=".\module.cpp"> RelativePath=".\module.cpp">
</File> </File>
<File
RelativePath=".\oldcompat_sql.cpp">
</File>
<File <File
RelativePath=".\threading.cpp"> RelativePath=".\threading.cpp">
</File> </File>

View File

@ -21,7 +21,8 @@ enum HandleType
Handle_Connection = 0, Handle_Connection = 0,
Handle_Database, Handle_Database,
Handle_Query, Handle_Query,
Handle_ThreadQuery, Handle_OldDb,
Handle_OldResult,
}; };
struct SQL_Connection struct SQL_Connection
@ -38,12 +39,14 @@ typedef void (*FREEHANDLE)(void *, unsigned int);
unsigned int MakeHandle(void *ptr, HandleType type, FREEHANDLE f); unsigned int MakeHandle(void *ptr, HandleType type, FREEHANDLE f);
void *GetHandle(unsigned int num, HandleType type); void *GetHandle(unsigned int num, HandleType type);
bool FreeHandle(unsigned int num); bool FreeHandle(unsigned int num);
void FreeAllHandles(HandleType type);
void FreeHandleTable();
extern AMX_NATIVE_INFO g_BaseSqlNatives[]; extern AMX_NATIVE_INFO g_BaseSqlNatives[];
extern AMX_NATIVE_INFO g_ThreadSqlNatives[]; extern AMX_NATIVE_INFO g_ThreadSqlNatives[];
extern AMX_NATIVE_INFO g_OldCompatNatives[];
extern MainThreader g_Threader; extern MainThreader g_Threader;
extern ThreadWorker *g_pWorker; extern ThreadWorker *g_pWorker;
extern SourceMod::MysqlDriver g_Mysql; extern SourceMod::MysqlDriver g_Mysql;
#endif //_INCLUDE_AMXMODX_MYSQL2_HEADER_H #endif //_INCLUDE_AMXMODX_MYSQL2_HEADER_H

View File

@ -0,0 +1,429 @@
#include "mysql2_header.h"
struct olddb_s
{
IDatabase *pDatabase;
char error[255];
int errcode;
};
struct oldresult_s
{
IQuery *pQuery;
QueryInfo info;
bool firstCall;
};
void FreeOldDb(void *ptr, unsigned int hndl)
{
olddb_s *old = (olddb_s *)ptr;
if (old->pDatabase)
{
old->pDatabase->FreeHandle();
old->pDatabase = NULL;
}
delete old;
}
void FreeOldResult(void *ptr, unsigned int hndl)
{
oldresult_s *oldres = (oldresult_s *)ptr;
if (oldres->pQuery)
{
oldres->pQuery->FreeHandle();
oldres->pQuery = NULL;
}
delete oldres;
}
//native Sql:dbi_connect(_host[], _user[], _pass[], _dbname[], _error[]="", _maxlength=0);
static cell AMX_NATIVE_CALL dbi_connect(AMX *amx, cell *params)
{
int len;
DatabaseInfo info;
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 *name = MF_GetAmxString(amx, params[4], 3, &len);
char *p = strchr(host, ':');
if (p)
{
info.port = atoi(p+1);
*p = '\0';
} else {
info.port = 0;
}
info.host = host;
info.user = user;
info.pass = pass;
info.database = name;
int err;
char error[512];
IDatabase *pDatabase = g_Mysql.Connect(&info, &err, error, sizeof(error)-1);
if (!pDatabase)
{
MF_SetAmxString(amx, params[5], error, params[6]);
return 0;
}
olddb_s *old = new olddb_s;
int hndl;
old->pDatabase = pDatabase;
hndl = MakeHandle(old, Handle_OldDb, FreeOldDb);
return hndl;
}
//native Result:dbi_query(Sql:_sql, _query[], {Float,_}:...);
static cell AMX_NATIVE_CALL dbi_query(AMX *amx, cell *params)
{
olddb_s *old = (olddb_s *)GetHandle(params[1], Handle_OldDb);
if (!old)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid DBI handle %d", params[1]);
return -1;
}
int len;
char *queryString = MF_FormatAmxString(amx, params, 2, &len);
IQuery *pQuery = old->pDatabase->PrepareQuery(queryString);
QueryInfo info;
old->error[0] = '\0';
old->errcode = 0;
if (!pQuery->Execute(&info, old->error, 254))
{
old->errcode = info.errorcode;
return -1;
} else {
if (info.rs && info.rs->RowCount())
{
oldresult_s *oldrs = new oldresult_s;
int hndl;
oldrs->info = info;
oldrs->pQuery = pQuery;
hndl = MakeHandle(oldrs, Handle_OldResult, FreeOldResult);
return hndl;
} else {
pQuery->FreeHandle();
return 0;
}
}
/** never reach here */
return 0;
}
//native Result:dbi_query2(Sql:_sql, &rows, _query[], {Float,_}:...);
static cell AMX_NATIVE_CALL dbi_query2(AMX *amx, cell *params)
{
olddb_s *old = (olddb_s *)GetHandle(params[1], Handle_OldDb);
if (!old)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid DBI handle %d", params[1]);
return -1;
}
int len;
char *queryString = MF_FormatAmxString(amx, params, 3, &len);
IQuery *pQuery = old->pDatabase->PrepareQuery(queryString);
QueryInfo info;
old->error[0] = '\0';
old->errcode = 0;
if (!pQuery->Execute(&info, old->error, 254))
{
old->errcode = info.errorcode;
return -1;
} else {
cell *addr = MF_GetAmxAddr(amx, params[2]);
*addr = static_cast<cell>(info.affected_rows);
if (info.rs && info.rs->RowCount())
{
oldresult_s *oldrs = new oldresult_s;
int hndl;
oldrs->info = info;
oldrs->pQuery = pQuery;
oldrs->firstCall = true;
hndl = MakeHandle(oldrs, Handle_OldResult, FreeOldResult);
return hndl;
} else {
pQuery->FreeHandle();
return 0;
}
}
/** never reach here */
return 0;
}
//native dbi_nextrow(Result:_result);
static cell AMX_NATIVE_CALL dbi_nextrow(AMX *amx, cell *params)
{
oldresult_s *oldrs = (oldresult_s *)GetHandle(params[1], Handle_OldResult);
if (!oldrs)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid DBI result handle %d", params[1]);
return 0;
}
if (oldrs->firstCall)
{
oldrs->firstCall = false;
return (oldrs->info.rs->IsDone() ? 0 : 1);
} else {
oldrs->info.rs->NextRow();
return (oldrs->info.rs->IsDone() ? 0 : 1);
}
}
//native dbi_field(Result:_result, _fieldnum, {Float,_}:... );
static cell AMX_NATIVE_CALL dbi_field(AMX *amx, cell *params)
{
oldresult_s *oldrs = (oldresult_s *)GetHandle(params[1], Handle_OldResult);
if (!oldrs)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid DBI result handle %d", params[1]);
return 0;
}
IResultSet *rs = oldrs->info.rs;
IResultRow *rr = rs->GetRow();
unsigned int num = (unsigned int)params[2] - 1;
if (num >= rs->FieldCount())
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid column %d", params[2]);
return 0;
}
cell stype = params[0] / sizeof(cell);
const char *data = rr->GetString(num);
if (!data)
data = "";
switch (stype)
{
case 2:
{
return atoi(data);
break;
}
case 3:
{
cell *destaddr = MF_GetAmxAddr(amx, params[3]);
REAL fdata = atof(data);
*destaddr = amx_ftoc(fdata);
return 1;
break;
}
case 4:
{
return MF_SetAmxString(amx, params[3], data, params[4]);
break;
}
}
/** never reach here */
return 0;
}
//native dbi_result(Result:_result, _field[], {Float,_}:... );
static cell AMX_NATIVE_CALL dbi_result(AMX *amx, cell *params)
{
oldresult_s *oldrs = (oldresult_s *)GetHandle(params[1], Handle_OldResult);
if (!oldrs)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid DBI result handle %d", params[1]);
return 0;
}
IResultSet *rs = oldrs->info.rs;
IResultRow *rr = rs->GetRow();
unsigned int num;
bool found = false;
unsigned int fields = rs->FieldCount();
int len;
char *field = MF_GetAmxString(amx, params[2], 0, &len);
num = -1;
for (unsigned int i=0; i<fields; i++)
{
if (strcmp(field, rs->FieldNumToName(i)) == 0)
{
num = i;
found = true;
break;
}
}
if (!found)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Unknown column \"%s\"", field);
return 0;
}
cell stype = params[0] / sizeof(cell);
const char *data = rr->GetString(num);
if (!data)
data = "";
switch (stype)
{
case 2:
{
return atoi(data);
break;
}
case 3:
{
cell *destaddr = MF_GetAmxAddr(amx, params[3]);
REAL fdata = atof(data);
*destaddr = amx_ftoc(fdata);
return 1;
break;
}
case 4:
{
return MF_SetAmxString(amx, params[3], data, params[4]);
break;
}
}
/** never reach here */
return 0;
}
//native dbi_num_rows(Result:_result);
static cell AMX_NATIVE_CALL dbi_num_rows(AMX *amx, cell *params)
{
oldresult_s *oldrs = (oldresult_s *)GetHandle(params[1], Handle_OldResult);
if (!oldrs)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid DBI result handle %d", params[1]);
return 0;
}
return oldrs->info.rs->RowCount();
}
//native dbi_free_result(&Result:result);
static cell AMX_NATIVE_CALL dbi_free_result(AMX *amx, cell *params)
{
cell *_r = MF_GetAmxAddr(amx, params[1]);
cell num = *_r;
oldresult_s *oldrs = (oldresult_s *)GetHandle(num, Handle_OldResult);
if (!oldrs)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid DBI result handle %d", num);
return 0;
}
FreeHandle(num);
*_r = 0;
return 1;
}
//native dbi_close(&Sql:_sql);
static cell AMX_NATIVE_CALL dbi_close(AMX *amx, cell *params)
{
cell *_r = MF_GetAmxAddr(amx, params[1]);
cell num = *_r;
olddb_s *old = (olddb_s *)GetHandle(num, Handle_OldDb);
if (!old)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid DBI handle %d", num);
return -1;
}
FreeHandle(num);
*_r = 0;
return 1;
}
//native dbi_error(Sql:_sql, _error[], _len);
static cell AMX_NATIVE_CALL dbi_error(AMX *amx, cell *params)
{
olddb_s *old = (olddb_s *)GetHandle(params[1], Handle_OldDb);
if (!old)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid DBI handle %d", params[1]);
return -1;
}
MF_SetAmxString(amx, params[2], old->error, params[3]);
return old->errcode;
}
//native dbi_type(_type[], _len);
static cell AMX_NATIVE_CALL dbi_type(AMX *amx, cell *params)
{
return MF_SetAmxString(amx, params[1], "mysql", params[2]);
}
//native dbi_num_fields(Result:result);
static cell AMX_NATIVE_CALL dbi_num_fields(AMX *amx, cell *params)
{
oldresult_s *oldrs = (oldresult_s *)GetHandle(params[1], Handle_OldResult);
if (!oldrs)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid DBI result handle %d", params[1]);
return 0;
}
return oldrs->info.rs->FieldCount();
}
//native dbi_field_name(Result:result, field, name[], maxLength);
static cell AMX_NATIVE_CALL dbi_field_name(AMX *amx, cell *params)
{
oldresult_s *oldrs = (oldresult_s *)GetHandle(params[1], Handle_OldResult);
if (!oldrs)
{
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid DBI result handle %d", params[1]);
return 0;
}
const char *name = oldrs->info.rs->FieldNumToName(static_cast<unsigned int>(params[2]-1));
if (!name)
return 0;
MF_SetAmxString(amx, params[3], name, params[4]);
return 1;
}
AMX_NATIVE_INFO g_OldCompatNatives[] =
{
{ "dbi_connect", dbi_connect },
{ "dbi_query", dbi_query },
{ "dbi_query2", dbi_query2 },
{ "dbi_field", dbi_field },
{ "dbi_nextrow", dbi_nextrow },
{ "dbi_close", dbi_close },
{ "dbi_error", dbi_error },
{ "dbi_type", dbi_type },
{ "dbi_free_result", dbi_free_result },
{ "dbi_num_rows", dbi_num_rows },
{ "dbi_result", dbi_result },
{ "dbi_num_fields", dbi_num_fields },
{ "dbi_field_name", dbi_field_name },
{ NULL, NULL }
};

View File

@ -137,7 +137,7 @@
// #define FN_ClientCommand_Post ClientCommand_Post // #define FN_ClientCommand_Post ClientCommand_Post
// #define FN_ClientUserInfoChanged_Post ClientUserInfoChanged_Post // #define FN_ClientUserInfoChanged_Post ClientUserInfoChanged_Post
// #define FN_ServerActivate_Post ServerActivate_Post // #define FN_ServerActivate_Post ServerActivate_Post
// #define FN_ServerDeactivate_Post ServerDeactivate_Post #define FN_ServerDeactivate_Post ServerDeactivate_Post
// #define FN_PlayerPreThink_Post PlayerPreThink_Post // #define FN_PlayerPreThink_Post PlayerPreThink_Post
// #define FN_PlayerPostThink_Post PlayerPostThink_Post // #define FN_PlayerPostThink_Post PlayerPostThink_Post
// #define FN_StartFrame_Post StartFrame_Post // #define FN_StartFrame_Post StartFrame_Post

View File

@ -1,6 +1,7 @@
#include <amxmodx> #include <amxmodx>
#include <amxmisc> #include <amxmisc>
#include <sqlx> #include <sqlx>
#include <dbi>
new Handle:g_DbInfo new Handle:g_DbInfo
new g_QueryNum new g_QueryNum
@ -10,6 +11,7 @@ public plugin_init()
register_plugin("SQLX Test", "1.0", "BAILOPAN") register_plugin("SQLX Test", "1.0", "BAILOPAN")
register_srvcmd("sqlx_test_normal", "SqlxTest_Normal") register_srvcmd("sqlx_test_normal", "SqlxTest_Normal")
register_srvcmd("sqlx_test_thread", "SqlxTest_Thread") register_srvcmd("sqlx_test_thread", "SqlxTest_Thread")
register_srvcmd("sqlx_test_old1", "SqlxTest_Old1")
new configsDir[64] new configsDir[64]
get_configsdir(configsDir, 63) get_configsdir(configsDir, 63)
@ -33,6 +35,9 @@ public plugin_cfg()
g_DbInfo = SQL_MakeDbTuple(host, user, pass, db) g_DbInfo = SQL_MakeDbTuple(host, user, pass, db)
} }
/**
* Note that this function works for both threaded and non-threaded queries.
*/
PrintQueryData(Handle:query) PrintQueryData(Handle:query)
{ {
new columns = SQL_NumColumns(query) new columns = SQL_NumColumns(query)
@ -56,6 +61,9 @@ PrintQueryData(Handle:query)
} }
} }
/**
* Handler for when a threaded query is resolved.
*/
public GetMyStuff(failstate, Handle:query, error[], errnum, data[], size) public GetMyStuff(failstate, Handle:query, error[], errnum, data[], size)
{ {
server_print("Resolved query %d at: %f", data[0], get_gametime()) server_print("Resolved query %d at: %f", data[0], get_gametime())
@ -73,6 +81,9 @@ public GetMyStuff(failstate, Handle:query, error[], errnum, data[], size)
} }
} }
/**
* Starts a threaded query.
*/
public SqlxTest_Thread() public SqlxTest_Thread()
{ {
new query[512] new query[512]
@ -87,6 +98,9 @@ public SqlxTest_Thread()
g_QueryNum++ g_QueryNum++
} }
/**
* Does a normal query.
*/
public SqlxTest_Normal() public SqlxTest_Normal()
{ {
new errnum, error[255] new errnum, error[255]
@ -114,6 +128,69 @@ public SqlxTest_Normal()
SQL_FreeHandle(db) SQL_FreeHandle(db)
} }
/**
* Wrapper for an old-style connection.
*/
Sql:OldInitDatabase()
{
new host[64]
new user[64]
new pass[64]
new db[64]
get_cvar_string("amx_sql_host", host, 63)
get_cvar_string("amx_sql_user", user, 63)
get_cvar_string("amx_sql_pass", pass, 63)
get_cvar_string("amx_sql_db", db, 63)
new error[255]
new Sql:sql = dbi_connect(host, user, pass, db, error, 254)
if (sql < SQL_OK)
{
server_print("Connection failure: %s", error)
return SQL_FAILED
}
return sql
}
/**
* Tests index-based lookup
*/
public SqlxTest_Old1()
{
new Sql:sql = OldInitDatabase()
if (sql < SQL_OK)
return
new Result:res = dbi_query(sql, "SELECT * FROM gaben")
if (res == RESULT_FAILED)
{
new error[255]
new code = dbi_error(sql, error, 254)
server_print("Result failed! [%d]: %s", code, error)
} else if (res == RESULT_NONE) {
server_print("No result set returned.")
} else {
new cols[2][32]
new str[32]
dbi_field_name(res, 1, cols[0], 31)
dbi_field_name(res, 2, cols[1], 31)
new row, num
while (dbi_nextrow(res) > 0)
{
num = dbi_field(res, 1)
dbi_field(res, 2, str, 31)
server_print("[%d]: %s=%d, %s=%s", row, cols[0], num, cols[1], str)
row++
}
dbi_free_result(res)
}
dbi_close(sql)
}
public plugin_end() public plugin_end()
{ {
SQL_FreeHandle(g_DbInfo) SQL_FreeHandle(g_DbInfo)

View File

@ -36,6 +36,8 @@ void OnAmxxDetach()
} }
g_QueueLock->Unlock(); g_QueueLock->Unlock();
g_QueueLock->DestroyThis(); g_QueueLock->DestroyThis();
FreeHandleTable();
} }
//public QueryHandler(state, Handle:query, error[], errnum, data[], size) //public QueryHandler(state, Handle:query, error[], errnum, data[], size)