-initial import of database natives + config
-initial import of completed database layer -CreateIdentity now requires a non-optional second pointer. This breaks backwards compatibility for CreateIdentity(), however, this is not a function extension authors are supposed to be calling --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40874
This commit is contained in:
parent
d461239e74
commit
e334e5f7e7
15
configs/databases.cfg
Normal file
15
configs/databases.cfg
Normal file
@ -0,0 +1,15 @@
|
||||
"Databases"
|
||||
{
|
||||
"driver_default" "mysql"
|
||||
|
||||
"default"
|
||||
{
|
||||
"driver" "default"
|
||||
"host" "localhost"
|
||||
"database" "sourcemod"
|
||||
"user" "root"
|
||||
"pass" ""
|
||||
//"timeout" "0"
|
||||
//"port" "0"
|
||||
}
|
||||
}
|
@ -16,9 +16,23 @@
|
||||
#include "HandleSys.h"
|
||||
#include "ShareSys.h"
|
||||
#include "sourcemod.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "TextParsers.h"
|
||||
#include "Logger.h"
|
||||
#include "ExtensionSys.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define DBPARSE_LEVEL_NONE 0
|
||||
#define DBPARSE_LEVEL_MAIN 1
|
||||
#define DBPARSE_LEVEL_DATABASE 2
|
||||
|
||||
DBManager g_DBMan;
|
||||
|
||||
DBManager::DBManager()
|
||||
: m_StrTab(512), m_ParseLevel(0), m_ParseState(0), m_pDefault(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
void DBManager::OnSourceModAllInitialized()
|
||||
{
|
||||
HandleAccess sec;
|
||||
@ -31,6 +45,23 @@ void DBManager::OnSourceModAllInitialized()
|
||||
m_DatabaseType = g_HandleSys.CreateType("IDatabase", this, 0, NULL, NULL, g_pCoreIdent, NULL);
|
||||
|
||||
g_ShareSys.AddInterface(NULL, this);
|
||||
|
||||
g_SourceMod.BuildPath(Path_SM, m_Filename, sizeof(m_Filename), "configs/databases.cfg");
|
||||
}
|
||||
|
||||
void DBManager::OnSourceModLevelChange(const char *mapName)
|
||||
{
|
||||
SMCParseError err;
|
||||
unsigned int line = 0;
|
||||
if ((err = g_TextParser.ParseFile_SMC(m_Filename, this, &line, NULL)) != SMCParse_Okay)
|
||||
{
|
||||
g_Logger.LogError("[SM] Detected parse error(s) in file \"%s\"", m_Filename);
|
||||
if (err != SMCParse_Custom)
|
||||
{
|
||||
const char *txt = g_TextParser.GetSMCErrorString(err);
|
||||
g_Logger.LogError("[SM] Line %d: %s", line, txt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DBManager::OnSourceModShutdown()
|
||||
@ -64,23 +95,173 @@ void DBManager::OnHandleDestroy(HandleType_t type, void *object)
|
||||
}
|
||||
}
|
||||
|
||||
bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength)
|
||||
void DBManager::ReadSMC_ParseStart()
|
||||
{
|
||||
const DatabaseInfo *pInfo = FindDatabaseConf(name);
|
||||
m_confs.clear();
|
||||
m_ParseLevel = 0;
|
||||
m_ParseState = DBPARSE_LEVEL_NONE;
|
||||
m_StrTab.Reset();
|
||||
m_DefDriver.clear();
|
||||
}
|
||||
|
||||
for (size_t i=0; i<m_drivers.size(); i++)
|
||||
ConfDbInfo s_CurInfo;
|
||||
SMCParseResult DBManager::ReadSMC_NewSection(const char *name, bool opt_quotes)
|
||||
{
|
||||
if (m_ParseLevel)
|
||||
{
|
||||
if (strcasecmp(pInfo->driver, m_drivers[i]->GetIdentifier()) == 0)
|
||||
m_ParseLevel++;
|
||||
return SMCParse_Continue;
|
||||
}
|
||||
|
||||
if (m_ParseState == DBPARSE_LEVEL_NONE)
|
||||
{
|
||||
if (strcmp(name, "Databases") == 0)
|
||||
{
|
||||
*pdr = m_drivers[i];
|
||||
*pdb = m_drivers[i]->Connect(pInfo, persistent, error, maxlength);
|
||||
return (*pdb == NULL);
|
||||
m_ParseState = DBPARSE_LEVEL_MAIN;
|
||||
} else {
|
||||
m_ParseLevel++;
|
||||
}
|
||||
} else if (m_ParseState == DBPARSE_LEVEL_MAIN) {
|
||||
s_CurInfo = ConfDbInfo();
|
||||
s_CurInfo.database = m_StrTab.AddString(name);
|
||||
m_ParseState = DBPARSE_LEVEL_DATABASE;
|
||||
} else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
|
||||
m_ParseLevel++;
|
||||
}
|
||||
|
||||
return SMCParse_Continue;
|
||||
}
|
||||
|
||||
SMCParseResult DBManager::ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes)
|
||||
{
|
||||
if (m_ParseLevel)
|
||||
{
|
||||
return SMCParse_Continue;
|
||||
}
|
||||
|
||||
if (m_ParseState == DBPARSE_LEVEL_MAIN)
|
||||
{
|
||||
if (strcmp(key, "driver_default") == 0)
|
||||
{
|
||||
m_DefDriver.assign(value);
|
||||
}
|
||||
} else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
|
||||
if (strcmp(key, "driver") == 0)
|
||||
{
|
||||
if (strcmp(value, "default") != 0)
|
||||
{
|
||||
s_CurInfo.driver = m_StrTab.AddString(value);
|
||||
}
|
||||
} else if (strcmp(key, "database") == 0) {
|
||||
s_CurInfo.database = m_StrTab.AddString(value);
|
||||
} else if (strcmp(key, "host") == 0) {
|
||||
s_CurInfo.host = m_StrTab.AddString(value);
|
||||
} else if (strcmp(key, "user") == 0) {
|
||||
s_CurInfo.user = m_StrTab.AddString(value);
|
||||
} else if (strcmp(key, "pass") == 0) {
|
||||
s_CurInfo.pass = m_StrTab.AddString(value);
|
||||
} else if (strcmp(key, "timeout") == 0) {
|
||||
s_CurInfo.info.maxTimeout = atoi(value);
|
||||
} else if (strcmp(key, "port") == 0) {
|
||||
s_CurInfo.info.port = atoi(value);
|
||||
}
|
||||
}
|
||||
|
||||
*pdr = NULL;
|
||||
return SMCParse_Continue;
|
||||
}
|
||||
|
||||
#define ASSIGN_VAR(var) \
|
||||
if (s_CurInfo.var == -1) { \
|
||||
s_CurInfo.info.var = ""; \
|
||||
} else { \
|
||||
s_CurInfo.info.var = m_StrTab.GetString(s_CurInfo.var); \
|
||||
}
|
||||
|
||||
SMCParseResult DBManager::ReadSMC_LeavingSection()
|
||||
{
|
||||
if (m_ParseLevel)
|
||||
{
|
||||
m_ParseLevel--;
|
||||
return SMCParse_Continue;
|
||||
}
|
||||
|
||||
if (m_ParseState == DBPARSE_LEVEL_DATABASE)
|
||||
{
|
||||
/* Set all of the info members to either a blank string
|
||||
* or the string pointer from the string table.
|
||||
*/
|
||||
ASSIGN_VAR(driver);
|
||||
ASSIGN_VAR(database);
|
||||
ASSIGN_VAR(host);
|
||||
ASSIGN_VAR(user);
|
||||
ASSIGN_VAR(pass);
|
||||
|
||||
/* Save it.. */
|
||||
m_confs.push_back(s_CurInfo);
|
||||
|
||||
/* Go up one level */
|
||||
m_ParseState = DBPARSE_LEVEL_MAIN;
|
||||
} else if (m_ParseState == DBPARSE_LEVEL_MAIN) {
|
||||
m_ParseState = DBPARSE_LEVEL_NONE;
|
||||
return SMCParse_Halt;
|
||||
}
|
||||
|
||||
return SMCParse_Continue;
|
||||
}
|
||||
#undef ASSIGN_VAR
|
||||
|
||||
void DBManager::ReadSMC_ParseEnd(bool halted, bool failed)
|
||||
{
|
||||
}
|
||||
|
||||
bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength)
|
||||
{
|
||||
ConfDbInfo *pInfo = GetDatabaseConf(name);
|
||||
|
||||
if (!pInfo)
|
||||
{
|
||||
if (pdr)
|
||||
{
|
||||
*pdr = NULL;
|
||||
}
|
||||
*pdb = NULL;
|
||||
UTIL_Format(error, maxlength, "Configuration \"%s\" not found", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pInfo->realDriver)
|
||||
{
|
||||
/* Try to assign a real driver pointer */
|
||||
if (pInfo->info.driver[0] == '\0')
|
||||
{
|
||||
if (!m_pDefault && m_DefDriver.size() > 0)
|
||||
{
|
||||
m_pDefault = FindOrLoadDriver(m_DefDriver.c_str());
|
||||
}
|
||||
pInfo->realDriver = m_pDefault;
|
||||
} else {
|
||||
pInfo->realDriver = FindOrLoadDriver(pInfo->info.driver);
|
||||
}
|
||||
}
|
||||
|
||||
if (pInfo->realDriver)
|
||||
{
|
||||
if (pdr)
|
||||
{
|
||||
*pdr = pInfo->realDriver;
|
||||
}
|
||||
*pdb = pInfo->realDriver->Connect(&pInfo->info, persistent, error, maxlength);
|
||||
return (*pdb != NULL);
|
||||
}
|
||||
|
||||
if (pdr)
|
||||
{
|
||||
*pdr = NULL;
|
||||
}
|
||||
*pdb = NULL;
|
||||
|
||||
UTIL_Format(error, maxlength, "Driver \"%s\" not found", pInfo->driver);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -99,6 +280,27 @@ void DBManager::RemoveDriver(IDBDriver *pDriver)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure NOTHING references this! */
|
||||
List<ConfDbInfo>::iterator iter;
|
||||
for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
|
||||
{
|
||||
ConfDbInfo &db = (*iter);
|
||||
if (db.realDriver == pDriver)
|
||||
{
|
||||
db.realDriver = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IDBDriver *DBManager::GetDefaultDriver()
|
||||
{
|
||||
if (!m_pDefault && m_DefDriver.size() > 0)
|
||||
{
|
||||
m_pDefault = FindOrLoadDriver(m_DefDriver.c_str());
|
||||
}
|
||||
|
||||
return m_pDefault;
|
||||
}
|
||||
|
||||
Handle_t DBManager::CreateHandle(DBHandleType dtype, void *ptr, IdentityToken_t *pToken)
|
||||
@ -158,6 +360,58 @@ IDBDriver *DBManager::GetDriver(unsigned int index)
|
||||
|
||||
const DatabaseInfo *DBManager::FindDatabaseConf(const char *name)
|
||||
{
|
||||
/* :TODO: */
|
||||
ConfDbInfo *info = GetDatabaseConf(name);
|
||||
if (!info)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &info->info;
|
||||
}
|
||||
|
||||
ConfDbInfo *DBManager::GetDatabaseConf(const char *name)
|
||||
{
|
||||
List<ConfDbInfo>::iterator iter;
|
||||
|
||||
for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
|
||||
{
|
||||
ConfDbInfo &conf = (*iter);
|
||||
if (strcmp(m_StrTab.GetString(conf.name), name) == 0)
|
||||
{
|
||||
return &conf;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IDBDriver *DBManager::FindOrLoadDriver(const char *name)
|
||||
{
|
||||
size_t last_size = m_drivers.size();
|
||||
for (size_t i=0; i<last_size; i++)
|
||||
{
|
||||
if (strcmp(m_drivers[i]->GetIdentifier(), name) == 0)
|
||||
{
|
||||
return m_drivers[i];
|
||||
}
|
||||
}
|
||||
|
||||
char filename[PLATFORM_MAX_PATH];
|
||||
UTIL_Format(filename, sizeof(filename), "dbi.%s", name);
|
||||
|
||||
IExtension *pExt = g_Extensions.LoadAutoExtension(filename);
|
||||
if (!pExt || !pExt->IsLoaded() || m_drivers.size() <= last_size)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* last_size is now gauranteed to be a valid index.
|
||||
* The identifier must match the name.
|
||||
*/
|
||||
if (strcmp(m_drivers[last_size]->GetIdentifier(), name) == 0)
|
||||
{
|
||||
return m_drivers[last_size];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -18,19 +18,43 @@
|
||||
#include <IDBDriver.h>
|
||||
#include "sm_globals.h"
|
||||
#include <sh_vector.h>
|
||||
#include <sh_string.h>
|
||||
#include <sh_list.h>
|
||||
#include <ITextParsers.h>
|
||||
#include "sm_memtable.h"
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
struct ConfDbInfo
|
||||
{
|
||||
ConfDbInfo() : name(-1), driver(-1), host(-1), user(-1), pass(-1),
|
||||
database(-1), realDriver(NULL)
|
||||
{
|
||||
}
|
||||
int name;
|
||||
int driver;
|
||||
int host;
|
||||
int user;
|
||||
int pass;
|
||||
int database;
|
||||
IDBDriver *realDriver;
|
||||
DatabaseInfo info;
|
||||
};
|
||||
|
||||
class DBManager :
|
||||
public IDBManager,
|
||||
public SMGlobalClass,
|
||||
public IHandleTypeDispatch
|
||||
public IHandleTypeDispatch,
|
||||
public ITextListener_SMC
|
||||
{
|
||||
public:
|
||||
DBManager();
|
||||
public:
|
||||
const char *GetInterfaceName();
|
||||
unsigned int GetInterfaceVersion();
|
||||
public: //SMGlobalClass
|
||||
void OnSourceModAllInitialized();
|
||||
void OnSourceModLevelChange(const char *mapName);
|
||||
void OnSourceModShutdown();
|
||||
public: //IHandleTypeDispatch
|
||||
void OnHandleDestroy(HandleType_t type, void *object);
|
||||
@ -44,10 +68,27 @@ public: //IDBManager
|
||||
Handle_t CreateHandle(DBHandleType type, void *ptr, IdentityToken_t *pToken);
|
||||
HandleError ReadHandle(Handle_t hndl, DBHandleType type, void **ptr);
|
||||
HandleError ReleaseHandle(Handle_t hndl, DBHandleType type, IdentityToken_t *token);
|
||||
public: //ITextListener_SMC
|
||||
void ReadSMC_ParseStart();
|
||||
SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes);
|
||||
SMCParseResult ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes);
|
||||
SMCParseResult ReadSMC_LeavingSection();
|
||||
void ReadSMC_ParseEnd(bool halted, bool failed);
|
||||
public:
|
||||
ConfDbInfo *GetDatabaseConf(const char *name);
|
||||
IDBDriver *FindOrLoadDriver(const char *name);
|
||||
IDBDriver *GetDefaultDriver();
|
||||
private:
|
||||
CVector<IDBDriver *> m_drivers;
|
||||
List<ConfDbInfo> m_confs;
|
||||
HandleType_t m_DriverType;
|
||||
HandleType_t m_DatabaseType;
|
||||
String m_DefDriver;
|
||||
BaseStringTable m_StrTab;
|
||||
char m_Filename[PLATFORM_MAX_PATH];
|
||||
unsigned int m_ParseLevel;
|
||||
unsigned int m_ParseState;
|
||||
IDBDriver *m_pDefault;
|
||||
};
|
||||
|
||||
extern DBManager g_DBMan;
|
||||
|
@ -796,6 +796,10 @@
|
||||
RelativePath="..\smn_core.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\smn_database.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\smn_datapacks.cpp"
|
||||
>
|
||||
|
860
core/smn_database.cpp
Normal file
860
core/smn_database.cpp
Normal file
@ -0,0 +1,860 @@
|
||||
#include "sm_globals.h"
|
||||
#include "HandleSys.h"
|
||||
#include "Database.h"
|
||||
#include "ExtensionSys.h"
|
||||
#include "PluginSys.h"
|
||||
|
||||
HandleType_t hQueryType;
|
||||
HandleType_t hStmtType;
|
||||
|
||||
class DatabaseHelpers :
|
||||
public SMGlobalClass,
|
||||
public IHandleTypeDispatch
|
||||
{
|
||||
public:
|
||||
virtual void OnSourceModAllInitialized()
|
||||
{
|
||||
HandleAccess acc;
|
||||
|
||||
/* Disable cloning */
|
||||
g_HandleSys.InitAccessDefaults(NULL, &acc);
|
||||
acc.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY;
|
||||
|
||||
TypeAccess tacc;
|
||||
|
||||
g_HandleSys.InitAccessDefaults(&tacc, NULL);
|
||||
tacc.ident = g_pCoreIdent;
|
||||
|
||||
hQueryType = g_HandleSys.CreateType("IQuery", this, 0, &tacc, &acc, g_pCoreIdent, NULL);
|
||||
hStmtType = g_HandleSys.CreateType("IPreparedQuery", this, hQueryType, &tacc, &acc, NULL, NULL);
|
||||
}
|
||||
|
||||
virtual void OnSourceModShutdown()
|
||||
{
|
||||
g_HandleSys.RemoveType(hStmtType, g_pCoreIdent);
|
||||
g_HandleSys.RemoveType(hQueryType, g_pCoreIdent);
|
||||
}
|
||||
|
||||
virtual void OnHandleDestroy(HandleType_t type, void *object)
|
||||
{
|
||||
if (type == hQueryType)
|
||||
{
|
||||
IQuery *query = (IQuery *)object;
|
||||
query->Destroy();
|
||||
} else if (type == hStmtType) {
|
||||
IPreparedQuery *query = (IPreparedQuery *)object;
|
||||
query->Destroy();
|
||||
}
|
||||
}
|
||||
} s_DatabaseNativeHelpers;
|
||||
|
||||
//is this safe for stmt handles? i think since it's single inheritance, it always will be.
|
||||
inline HandleError ReadQueryHndl(Handle_t hndl, IPluginContext *pContext, IQuery **query)
|
||||
{
|
||||
HandleSecurity sec;
|
||||
sec.pOwner = pContext->GetIdentity();
|
||||
sec.pIdentity = g_pCoreIdent;
|
||||
|
||||
return g_HandleSys.ReadHandle(hndl, hQueryType, &sec, (void **)query);
|
||||
}
|
||||
|
||||
inline HandleError ReadStmtHndl(Handle_t hndl, IPluginContext *pContext, IPreparedQuery **query)
|
||||
{
|
||||
HandleSecurity sec;
|
||||
sec.pOwner = pContext->GetIdentity();
|
||||
sec.pIdentity = g_pCoreIdent;
|
||||
|
||||
return g_HandleSys.ReadHandle(hndl, hStmtType, &sec, (void **)query);
|
||||
}
|
||||
|
||||
inline HandleError ReadDbOrStmtHndl(Handle_t hndl, IPluginContext *pContext, IDatabase **db, IPreparedQuery **query)
|
||||
{
|
||||
HandleError err;
|
||||
if ((err = g_DBMan.ReadHandle(hndl, DBHandle_Database, (void **)db)) == HandleError_Type)
|
||||
{
|
||||
*db = NULL;
|
||||
return ReadStmtHndl(hndl, pContext, query);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static cell_t SQL_Connect(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
char *conf, *err;
|
||||
|
||||
size_t maxlength = (size_t)params[4];
|
||||
bool persistent = params[2] ? true : false;
|
||||
pContext->LocalToString(params[1], &conf);
|
||||
pContext->LocalToString(params[3], &err);
|
||||
|
||||
IDBDriver *driver;
|
||||
IDatabase *db;
|
||||
if (!g_DBMan.Connect(conf, &driver, &db, persistent, err, maxlength))
|
||||
{
|
||||
return BAD_HANDLE;
|
||||
}
|
||||
|
||||
/* HACK! Add us to the dependency list */
|
||||
CExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity());
|
||||
if (pExt)
|
||||
{
|
||||
g_Extensions.BindChildPlugin(pExt, g_PluginSys.FindPluginByContext(pContext->GetContext()));
|
||||
}
|
||||
|
||||
return db->GetHandle();
|
||||
}
|
||||
|
||||
static cell_t SQL_ConnectEx(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IDBDriver *driver;
|
||||
if (params[1] == BAD_HANDLE)
|
||||
{
|
||||
if ((driver = g_DBMan.GetDefaultDriver()) == NULL)
|
||||
{
|
||||
return pContext->ThrowNativeError("Could not find any default driver");
|
||||
}
|
||||
} else {
|
||||
HandleError err;
|
||||
if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Driver, (void **)&driver))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid driver Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
}
|
||||
|
||||
char *host, *user, *pass, *database, *error;
|
||||
size_t maxlength = (size_t)params[7];
|
||||
bool persistent = params[8] ? true : false;
|
||||
unsigned int port = params[9];
|
||||
unsigned int maxTimeout = params[10];
|
||||
pContext->LocalToString(params[2], &host);
|
||||
pContext->LocalToString(params[3], &user);
|
||||
pContext->LocalToString(params[4], &pass);
|
||||
pContext->LocalToString(params[5], &database);
|
||||
pContext->LocalToString(params[6], &error);
|
||||
|
||||
DatabaseInfo info;
|
||||
info.database = database;
|
||||
info.driver = driver->GetIdentifier();
|
||||
info.host = host;
|
||||
info.maxTimeout = maxTimeout;
|
||||
info.pass = pass;
|
||||
info.port = port;
|
||||
info.user = user;
|
||||
|
||||
IDatabase *db = driver->Connect(&info, persistent, error, maxlength);
|
||||
|
||||
if (db)
|
||||
{
|
||||
/* HACK! Add us to the dependency list */
|
||||
CExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity());
|
||||
if (pExt)
|
||||
{
|
||||
g_Extensions.BindChildPlugin(pExt, g_PluginSys.FindPluginByContext(pContext->GetContext()));
|
||||
}
|
||||
|
||||
return db->GetHandle();
|
||||
}
|
||||
|
||||
return BAD_HANDLE;
|
||||
}
|
||||
|
||||
static cell_t SQL_GetDriverIdent(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IDBDriver *driver;
|
||||
if (params[1] == BAD_HANDLE)
|
||||
{
|
||||
if ((driver = g_DBMan.GetDefaultDriver()) == NULL)
|
||||
{
|
||||
return pContext->ThrowNativeError("Could not find any default driver");
|
||||
}
|
||||
} else {
|
||||
HandleError err;
|
||||
if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Driver, (void **)&driver))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid driver Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
}
|
||||
|
||||
pContext->StringToLocalUTF8(params[2], params[3], driver->GetIdentifier(), NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t SQL_GetDriver(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
char *name;
|
||||
pContext->LocalToString(params[1], &name);
|
||||
|
||||
IDBDriver *driver = NULL;
|
||||
if (name[0] == '\0')
|
||||
{
|
||||
driver = g_DBMan.GetDefaultDriver();
|
||||
} else {
|
||||
driver = g_DBMan.FindOrLoadDriver(name);
|
||||
}
|
||||
|
||||
return (driver != NULL) ? driver->GetHandle() : BAD_HANDLE;
|
||||
}
|
||||
|
||||
static cell_t SQL_GetDriverProduct(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IDBDriver *driver;
|
||||
if (params[1] == BAD_HANDLE)
|
||||
{
|
||||
if ((driver = g_DBMan.GetDefaultDriver()) == NULL)
|
||||
{
|
||||
return pContext->ThrowNativeError("Could not find any default driver");
|
||||
}
|
||||
} else {
|
||||
HandleError err;
|
||||
if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Driver, (void **)&driver))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid driver Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
}
|
||||
|
||||
pContext->StringToLocalUTF8(params[2], params[3], driver->GetProductName(), NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t SQL_GetAffectedRows(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IDatabase *db = NULL;
|
||||
IPreparedQuery *stmt = NULL;
|
||||
HandleError err;
|
||||
|
||||
if ((err = ReadDbOrStmtHndl(params[1], pContext, &db, &stmt)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid statement or db Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
if (db)
|
||||
{
|
||||
return db->GetAffectedRows();
|
||||
} else if (stmt) {
|
||||
return stmt->GetAffectedRows();
|
||||
}
|
||||
|
||||
return pContext->ThrowNativeError("Unknown error reading db/stmt handles");
|
||||
}
|
||||
|
||||
static cell_t SQL_GetInsertId(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IDatabase *db = NULL;
|
||||
IPreparedQuery *stmt = NULL;
|
||||
HandleError err;
|
||||
|
||||
if ((err = ReadDbOrStmtHndl(params[1], pContext, &db, &stmt)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid statement or db Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
if (db)
|
||||
{
|
||||
return db->GetInsertID();
|
||||
} else if (stmt) {
|
||||
return stmt->GetInsertID();
|
||||
}
|
||||
|
||||
return pContext->ThrowNativeError("Unknown error reading db/stmt handles");
|
||||
}
|
||||
|
||||
static cell_t SQL_GetError(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IDatabase *db = NULL;
|
||||
IPreparedQuery *stmt = NULL;
|
||||
HandleError err;
|
||||
|
||||
if ((err = ReadDbOrStmtHndl(params[1], pContext, &db, &stmt)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid statement or db Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
const char *error = "";
|
||||
if (db)
|
||||
{
|
||||
error = db->GetError();
|
||||
} else if (stmt) {
|
||||
error = stmt->GetError();
|
||||
}
|
||||
|
||||
if (error[0] == '\0')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
pContext->StringToLocalUTF8(params[2], params[3], error, NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t SQL_QuoteString(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IDatabase *db = NULL;
|
||||
HandleError err;
|
||||
|
||||
if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
char *input, *output;
|
||||
size_t maxlength = (size_t)params[4];
|
||||
pContext->LocalToString(params[2], &input);
|
||||
pContext->LocalToString(params[3], &output);
|
||||
|
||||
size_t written;
|
||||
bool s = db->QuoteString(input, output, maxlength, &written);
|
||||
|
||||
cell_t *addr;
|
||||
pContext->LocalToPhysAddr(params[5], &addr);
|
||||
*addr = (cell_t)written;
|
||||
|
||||
return s ? 1 : 0;
|
||||
}
|
||||
|
||||
static cell_t SQL_FastQuery(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IDatabase *db = NULL;
|
||||
HandleError err;
|
||||
|
||||
if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
char *query;
|
||||
pContext->LocalToString(params[2], &query);
|
||||
|
||||
return db->DoSimpleQuery(query) ? 1 : 0;
|
||||
}
|
||||
|
||||
static cell_t SQL_Query(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IDatabase *db = NULL;
|
||||
HandleError err;
|
||||
|
||||
if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
char *query;
|
||||
pContext->LocalToString(params[2], &query);
|
||||
|
||||
IQuery *qr = db->DoQuery(query);
|
||||
|
||||
if (!qr)
|
||||
{
|
||||
return BAD_HANDLE;
|
||||
}
|
||||
|
||||
Handle_t hndl = g_HandleSys.CreateHandle(hQueryType, qr, pContext->GetIdentity(), g_pCoreIdent, NULL);
|
||||
if (hndl == BAD_HANDLE)
|
||||
{
|
||||
qr->Destroy();
|
||||
return BAD_HANDLE;
|
||||
}
|
||||
|
||||
return hndl;
|
||||
}
|
||||
|
||||
static cell_t SQL_PrepareQuery(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IDatabase *db = NULL;
|
||||
HandleError err;
|
||||
|
||||
if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
char *query, *error;
|
||||
size_t maxlength = (size_t)params[4];
|
||||
pContext->LocalToString(params[2], &query);
|
||||
pContext->LocalToString(params[3], &error);
|
||||
|
||||
IPreparedQuery *qr = db->PrepareQuery(query, error, maxlength);
|
||||
|
||||
if (!qr)
|
||||
{
|
||||
return BAD_HANDLE;
|
||||
}
|
||||
|
||||
Handle_t hndl = g_HandleSys.CreateHandle(hStmtType, qr, pContext->GetIdentity(), g_pCoreIdent, NULL);
|
||||
if (hndl == BAD_HANDLE)
|
||||
{
|
||||
qr->Destroy();
|
||||
return BAD_HANDLE;
|
||||
}
|
||||
|
||||
return hndl;
|
||||
}
|
||||
|
||||
static cell_t SQL_FetchMoreResults(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IQuery *query;
|
||||
HandleError err;
|
||||
|
||||
if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
return query->FetchMoreResults() ? 1 : 0;
|
||||
}
|
||||
|
||||
static cell_t SQL_HasResultSet(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IQuery *query;
|
||||
HandleError err;
|
||||
|
||||
if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
return query->GetResultSet() != NULL ? true : false;
|
||||
}
|
||||
|
||||
static cell_t SQL_GetRowCount(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IQuery *query;
|
||||
HandleError err;
|
||||
|
||||
if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
IResultSet *rs = query->GetResultSet();
|
||||
if (!rs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return rs->GetRowCount();
|
||||
}
|
||||
|
||||
static cell_t SQL_GetFieldCount(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IQuery *query;
|
||||
HandleError err;
|
||||
|
||||
if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
IResultSet *rs = query->GetResultSet();
|
||||
if (!rs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return rs->GetFieldCount();
|
||||
}
|
||||
|
||||
static cell_t SQL_FieldNumToName(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IQuery *query;
|
||||
HandleError err;
|
||||
|
||||
if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
IResultSet *rs = query->GetResultSet();
|
||||
if (!rs)
|
||||
{
|
||||
return pContext->ThrowNativeError("No current result set");
|
||||
}
|
||||
|
||||
unsigned int field = params[2];
|
||||
|
||||
const char *fldname;
|
||||
if ((fldname = rs->FieldNumToName(field)) == NULL)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid field index %d", field);
|
||||
}
|
||||
|
||||
pContext->StringToLocalUTF8(params[3], params[4], fldname, NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t SQL_FieldNameToNum(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IQuery *query;
|
||||
HandleError err;
|
||||
|
||||
if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
IResultSet *rs = query->GetResultSet();
|
||||
if (!rs)
|
||||
{
|
||||
return pContext->ThrowNativeError("No current result set");
|
||||
}
|
||||
|
||||
char *field;
|
||||
pContext->LocalToString(params[2], &field);
|
||||
|
||||
cell_t *num;
|
||||
pContext->LocalToPhysAddr(params[3], &num);
|
||||
|
||||
return rs->FieldNameToNum(field, (unsigned int *)num) ? 1 : 0;
|
||||
}
|
||||
|
||||
static cell_t SQL_FetchRow(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IQuery *query;
|
||||
HandleError err;
|
||||
|
||||
if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
IResultSet *rs = query->GetResultSet();
|
||||
if (!rs)
|
||||
{
|
||||
return pContext->ThrowNativeError("No current result set");
|
||||
}
|
||||
|
||||
return (rs->FetchRow() != NULL) ? true : false;
|
||||
}
|
||||
|
||||
static cell_t SQL_MoreRows(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IQuery *query;
|
||||
HandleError err;
|
||||
|
||||
if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
IResultSet *rs = query->GetResultSet();
|
||||
if (!rs)
|
||||
{
|
||||
return pContext->ThrowNativeError("No current result set");
|
||||
}
|
||||
|
||||
return rs->MoreRows() ? 1 : 0;
|
||||
}
|
||||
|
||||
static cell_t SQL_Rewind(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IQuery *query;
|
||||
HandleError err;
|
||||
|
||||
if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
IResultSet *rs = query->GetResultSet();
|
||||
if (!rs)
|
||||
{
|
||||
return pContext->ThrowNativeError("No current result set");
|
||||
}
|
||||
|
||||
return rs->Rewind() ? 1 : 0;
|
||||
}
|
||||
|
||||
static cell_t SQL_FetchString(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IQuery *query;
|
||||
HandleError err;
|
||||
|
||||
if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
IResultSet *rs = query->GetResultSet();
|
||||
if (!rs)
|
||||
{
|
||||
return pContext->ThrowNativeError("No current result set");
|
||||
}
|
||||
|
||||
IResultRow *row = rs->CurrentRow();
|
||||
if (!row)
|
||||
{
|
||||
return pContext->ThrowNativeError("Current result set has no fetched rows");
|
||||
}
|
||||
|
||||
const char *str;
|
||||
size_t length;
|
||||
DBResult res = row->GetString(params[2], &str, &length);
|
||||
|
||||
if (res == DBVal_Error)
|
||||
{
|
||||
return pContext->ThrowNativeError("Error fetching data from field %d", params[2]);
|
||||
} else if (res == DBVal_TypeMismatch) {
|
||||
return pContext->ThrowNativeError("Could not fetch data in field %d as a string", params[2]);
|
||||
}
|
||||
|
||||
pContext->StringToLocalUTF8(params[3], params[4], str, &length);
|
||||
|
||||
cell_t *addr;
|
||||
pContext->LocalToPhysAddr(params[5], &addr);
|
||||
*addr = (cell_t)res;
|
||||
|
||||
return (cell_t)length;
|
||||
}
|
||||
|
||||
static cell_t SQL_FetchFloat(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IQuery *query;
|
||||
HandleError err;
|
||||
|
||||
if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
IResultSet *rs = query->GetResultSet();
|
||||
if (!rs)
|
||||
{
|
||||
return pContext->ThrowNativeError("No current result set");
|
||||
}
|
||||
|
||||
IResultRow *row = rs->CurrentRow();
|
||||
if (!row)
|
||||
{
|
||||
return pContext->ThrowNativeError("Current result set has no fetched rows");
|
||||
}
|
||||
|
||||
float f;
|
||||
DBResult res = row->GetFloat(params[2], &f);
|
||||
|
||||
if (res == DBVal_Error)
|
||||
{
|
||||
return pContext->ThrowNativeError("Error fetching data from field %d", params[2]);
|
||||
} else if (res == DBVal_TypeMismatch) {
|
||||
return pContext->ThrowNativeError("Could not fetch data in field %d as a float", params[2]);
|
||||
}
|
||||
|
||||
cell_t *addr;
|
||||
pContext->LocalToPhysAddr(params[5], &addr);
|
||||
*addr = (cell_t)res;
|
||||
|
||||
return sp_ftoc(f);
|
||||
}
|
||||
|
||||
static cell_t SQL_FetchInt(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IQuery *query;
|
||||
HandleError err;
|
||||
|
||||
if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
IResultSet *rs = query->GetResultSet();
|
||||
if (!rs)
|
||||
{
|
||||
return pContext->ThrowNativeError("No current result set");
|
||||
}
|
||||
|
||||
IResultRow *row = rs->CurrentRow();
|
||||
if (!row)
|
||||
{
|
||||
return pContext->ThrowNativeError("Current result set has no fetched rows");
|
||||
}
|
||||
|
||||
int iv;
|
||||
DBResult res = row->GetInt(params[2], &iv);
|
||||
|
||||
if (res == DBVal_Error)
|
||||
{
|
||||
return pContext->ThrowNativeError("Error fetching data from field %d", params[2]);
|
||||
} else if (res == DBVal_TypeMismatch) {
|
||||
return pContext->ThrowNativeError("Could not fetch data in field %d as an integer", params[2]);
|
||||
}
|
||||
|
||||
cell_t *addr;
|
||||
pContext->LocalToPhysAddr(params[5], &addr);
|
||||
*addr = (cell_t)res;
|
||||
|
||||
return iv;
|
||||
}
|
||||
|
||||
static cell_t SQL_IsFieldNull(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IQuery *query;
|
||||
HandleError err;
|
||||
|
||||
if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
IResultSet *rs = query->GetResultSet();
|
||||
if (!rs)
|
||||
{
|
||||
return pContext->ThrowNativeError("No current result set");
|
||||
}
|
||||
|
||||
IResultRow *row = rs->CurrentRow();
|
||||
if (!row)
|
||||
{
|
||||
return pContext->ThrowNativeError("Current result set has no fetched rows");
|
||||
}
|
||||
|
||||
if ((unsigned)params[2] >= rs->GetFieldCount())
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid field index %d", params[2]);
|
||||
}
|
||||
|
||||
return row->IsNull(params[2]) ? 1 : 0;
|
||||
}
|
||||
|
||||
static cell_t SQL_FetchSize(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IQuery *query;
|
||||
HandleError err;
|
||||
|
||||
if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
IResultSet *rs = query->GetResultSet();
|
||||
if (!rs)
|
||||
{
|
||||
return pContext->ThrowNativeError("No current result set");
|
||||
}
|
||||
|
||||
IResultRow *row = rs->CurrentRow();
|
||||
if (!row)
|
||||
{
|
||||
return pContext->ThrowNativeError("Current result set has no fetched rows");
|
||||
}
|
||||
|
||||
if ((unsigned)params[2] >= rs->GetFieldCount())
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid field index %d", params[2]);
|
||||
}
|
||||
|
||||
return row->GetDataSize(params[2]);
|
||||
}
|
||||
|
||||
static cell_t SQL_BindParamInt(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IPreparedQuery *stmt;
|
||||
HandleError err;
|
||||
|
||||
if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
if (!stmt->BindParamInt(params[2], params[3], params[4] ? true : false))
|
||||
{
|
||||
return pContext->ThrowNativeError("Could not bind parameter %d as an integer", params[2]);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t SQL_BindParamFloat(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IPreparedQuery *stmt;
|
||||
HandleError err;
|
||||
|
||||
if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
if (!stmt->BindParamFloat(params[2], sp_ctof(params[3])))
|
||||
{
|
||||
return pContext->ThrowNativeError("Could not bind parameter %d as a float", params[2]);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t SQL_BindParamString(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IPreparedQuery *stmt;
|
||||
HandleError err;
|
||||
|
||||
if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
char *str;
|
||||
pContext->LocalToString(params[3], &str);
|
||||
|
||||
if (!stmt->BindParamString(params[2], str, params[4] ? true : false))
|
||||
{
|
||||
return pContext->ThrowNativeError("Could not bind parameter %d as a string", params[2]);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static cell_t SQL_Execute(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
IPreparedQuery *stmt;
|
||||
HandleError err;
|
||||
|
||||
if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
|
||||
}
|
||||
|
||||
return stmt->Execute() ? 1 : 0;
|
||||
}
|
||||
|
||||
REGISTER_NATIVES(dbNatives)
|
||||
{
|
||||
{"SQL_BindParamInt", SQL_BindParamInt},
|
||||
{"SQL_BindParamFloat", SQL_BindParamFloat},
|
||||
{"SQL_BindParamString", SQL_BindParamString},
|
||||
{"SQL_Connect", SQL_Connect},
|
||||
{"SQL_ConnectEx", SQL_ConnectEx},
|
||||
{"SQL_Execute", SQL_Execute},
|
||||
{"SQL_FastQuery", SQL_FastQuery},
|
||||
{"SQL_FetchFloat", SQL_FetchFloat},
|
||||
{"SQL_FetchInt", SQL_FetchInt},
|
||||
{"SQL_FetchMoreResults", SQL_FetchMoreResults},
|
||||
{"SQL_FetchRow", SQL_FetchRow},
|
||||
{"SQL_FetchSize", SQL_FetchSize},
|
||||
{"SQL_FetchString", SQL_FetchString},
|
||||
{"SQL_FieldNameToNum", SQL_FieldNameToNum},
|
||||
{"SQL_FieldNumToName", SQL_FieldNumToName},
|
||||
{"SQL_GetAffectedRows", SQL_GetAffectedRows},
|
||||
{"SQL_GetDriver", SQL_GetDriver},
|
||||
{"SQL_GetDriverIdent", SQL_GetDriverIdent},
|
||||
{"SQL_GetDriverProduct", SQL_GetDriverProduct},
|
||||
{"SQL_GetError", SQL_GetError},
|
||||
{"SQL_GetFieldCount", SQL_GetFieldCount},
|
||||
{"SQL_GetInsertId", SQL_GetInsertId},
|
||||
{"SQL_GetRowCount", SQL_GetRowCount},
|
||||
{"SQL_HasResultSet", SQL_HasResultSet},
|
||||
{"SQL_IsFieldNull", SQL_IsFieldNull},
|
||||
{"SQL_MoreRows", SQL_MoreRows},
|
||||
{"SQL_Query", SQL_Query},
|
||||
{"SQL_QuoteString", SQL_QuoteString},
|
||||
{"SQL_PrepareQuery", SQL_PrepareQuery},
|
||||
{"SQL_Rewind", SQL_Rewind},
|
||||
{NULL, NULL},
|
||||
};
|
@ -70,7 +70,7 @@ CExtension::CExtension(const char *filename, char *error, size_t maxlength)
|
||||
m_PlId = g_pMMPlugins->Load(path, g_PLID, already, error, maxlength);
|
||||
}
|
||||
|
||||
m_pIdentToken = g_ShareSys.CreateIdentity(g_ExtType);
|
||||
m_pIdentToken = g_ShareSys.CreateIdentity(g_ExtType, this);
|
||||
|
||||
if (!m_pAPI->OnExtensionLoad(this, &g_ShareSys, error, maxlength, !g_SourceMod.IsMapLoading()))
|
||||
{
|
||||
@ -132,7 +132,11 @@ void CExtension::MarkAllLoaded()
|
||||
|
||||
void CExtension::AddPlugin(IPlugin *pPlugin)
|
||||
{
|
||||
m_Plugins.push_back(pPlugin);
|
||||
/* Unfortunately we have to do this :( */
|
||||
if (m_Plugins.find(pPlugin) != m_Plugins.end())
|
||||
{
|
||||
m_Plugins.push_back(pPlugin);
|
||||
}
|
||||
}
|
||||
|
||||
void CExtension::RemovePlugin(IPlugin *pPlugin)
|
||||
@ -866,3 +870,13 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmd, unsigned int argco
|
||||
g_RootMenu.DrawGenericOption("list", "List extensions");
|
||||
g_RootMenu.DrawGenericOption("unload", "Unload an extension");
|
||||
}
|
||||
|
||||
CExtension *CExtensionManager::GetExtensionFromIdent(IdentityToken_t *ptr)
|
||||
{
|
||||
if (ptr->type == g_ExtType)
|
||||
{
|
||||
return (CExtension *)(ptr->ptr);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -96,6 +96,8 @@ public:
|
||||
void MarkAllLoaded();
|
||||
void AddDependency(IExtension *pSource, const char *file, bool required, bool autoload);
|
||||
void TryAutoload();
|
||||
public:
|
||||
CExtension *GetExtensionFromIdent(IdentityToken_t *ptr);
|
||||
private:
|
||||
CExtension *FindByOrder(unsigned int num);
|
||||
private:
|
||||
|
@ -91,7 +91,7 @@ void CPlugin::InitIdentity()
|
||||
{
|
||||
if (!m_handle)
|
||||
{
|
||||
m_ident = g_ShareSys.CreateIdentity(g_PluginIdent);
|
||||
m_ident = g_ShareSys.CreateIdentity(g_PluginIdent, this);
|
||||
m_handle = g_HandleSys.CreateHandle(g_PluginType, this, g_PluginSys.GetIdentity(), g_PluginSys.GetIdentity(), NULL);
|
||||
m_ctx.base->SetIdentity(m_ident);
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ IdentityToken_t *ShareSystem::CreateCoreIdentity()
|
||||
m_CoreType = CreateIdentType("CORE");
|
||||
}
|
||||
|
||||
return CreateIdentity(m_CoreType);
|
||||
return CreateIdentity(m_CoreType, this);
|
||||
}
|
||||
|
||||
void ShareSystem::OnSourceModStartup(bool late)
|
||||
@ -96,7 +96,7 @@ void ShareSystem::OnHandleDestroy(HandleType_t type, void *object)
|
||||
/* THIS WILL NEVER BE CALLED FOR ANYTHING WITH THE IDENTITY TYPE */
|
||||
}
|
||||
|
||||
IdentityToken_t *ShareSystem::CreateIdentity(IdentityType_t type)
|
||||
IdentityToken_t *ShareSystem::CreateIdentity(IdentityType_t type, void *ptr)
|
||||
{
|
||||
if (!m_TypeRoot)
|
||||
{
|
||||
@ -110,6 +110,8 @@ IdentityToken_t *ShareSystem::CreateIdentity(IdentityType_t type)
|
||||
sec.pOwner = sec.pIdentity = GetIdentRoot();
|
||||
|
||||
pToken->ident = g_HandleSys.CreateHandleInt(type, NULL, &sec, NULL, NULL, true);
|
||||
pToken->ptr = ptr;
|
||||
pToken->type = type;
|
||||
|
||||
return pToken;
|
||||
}
|
||||
|
@ -28,6 +28,8 @@ namespace SourceMod
|
||||
struct IdentityToken_t
|
||||
{
|
||||
Handle_t ident;
|
||||
void *ptr;
|
||||
IdentityType_t type;
|
||||
};
|
||||
};
|
||||
|
||||
@ -53,7 +55,7 @@ public: //IShareSys
|
||||
void AddNatives(IExtension *myself, const sp_nativeinfo_t *natives);
|
||||
IdentityType_t CreateIdentType(const char *name);
|
||||
IdentityType_t FindIdentType(const char *name);
|
||||
IdentityToken_t *CreateIdentity(IdentityType_t type);
|
||||
IdentityToken_t *CreateIdentity(IdentityType_t type, void *ptr);
|
||||
void DestroyIdentType(IdentityType_t type);
|
||||
void DestroyIdentity(IdentityToken_t *identity);
|
||||
void AddDependency(IExtension *myself, const char *filename, bool require, bool autoload);
|
||||
|
445
plugins/include/dbi.inc
Normal file
445
plugins/include/dbi.inc
Normal file
@ -0,0 +1,445 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* ===============================================================
|
||||
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* ===============================================================
|
||||
*
|
||||
* This file is part of the SourceMod/SourcePawn SDK. This file may only be used
|
||||
* or modified under the Terms and Conditions of its License Agreement, which is found
|
||||
* in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins
|
||||
* may change at any time. To view the latest information, see:
|
||||
* http://www.sourcemod.net/license.php
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#if defined _dbi_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _dbi_included
|
||||
|
||||
/**
|
||||
* @handle Driver
|
||||
*
|
||||
* Contains information about an SQL driver.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @handle Database
|
||||
*
|
||||
* Contains information about a database connection.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @handle Query
|
||||
*
|
||||
* Contains information about an active query and its
|
||||
* result sets.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @handle Statement : Query
|
||||
*
|
||||
* Extends a Query Handle and can be used as a Query Handle.
|
||||
* Statement Handles are for prepared queries and contain
|
||||
* their own function for binding parameters. Statement
|
||||
* Handles can be used instead of database Handles in a few
|
||||
* select functions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Describes a database field fetch status.
|
||||
*/
|
||||
enum DBResult
|
||||
{
|
||||
DBVal_Error = 0, /**< Column number/field is invalid. */
|
||||
DBVal_TypeMismatch = 1, /**< You cannot retrieve this data with this type. */
|
||||
DBVal_Null = 2, /**< Field has no data (NULL) */
|
||||
DBVal_Data = 3, /**< Field has data */
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an SQL connection from a named configuration.
|
||||
*
|
||||
* @param confname Named configuration.
|
||||
* @param persistent True to re-use a previous persistent connection if
|
||||
* possible, false otherwise.
|
||||
* @param error Error buffer.
|
||||
* @param maxlength Maximum length of the error buffer.
|
||||
* @return A database connection Handle, or INVALID_HANDLE on failure.
|
||||
*/
|
||||
native Handle:SQL_Connect(const String:confname[], bool:persistent, String:error[], maxlength);
|
||||
|
||||
/**
|
||||
* Creates a default SQL connection.
|
||||
*
|
||||
* @param error Error buffer.
|
||||
* @param maxlength Maximum length of the error buffer.
|
||||
* @param persistent True to re-use a previous persistent connection
|
||||
* if possible, false otherwise.
|
||||
* @return A database connection Handle, or INVALID_HANDLE on failure.
|
||||
*/
|
||||
stock Handle:SQL_DefConnect(String:error[], maxlength, bool:persistent=true)
|
||||
{
|
||||
return SQL_Connect("default", persistent, error, maxlength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an SQL connection from specific parameters.
|
||||
*
|
||||
* @param driver Driver Handle, or INVALID_HANDLE for default.
|
||||
* @param host Host name.
|
||||
* @param user User name.
|
||||
* @param pass User password.
|
||||
* @param database Database name.
|
||||
* @param error Error buffer.
|
||||
* @param maxlength Maximum length of the error buffer.
|
||||
* @param persistent True to re-use a previous persistent connection
|
||||
* if possible, false otherwise.
|
||||
* @param port Optional port to specify.
|
||||
* @param maxTimeout Maximum timeout in seconds if applicable.
|
||||
* @return A database connection Handle, or INVALID_HANDLE on failure.
|
||||
* @error Invalid driver Handle other than INVALID_HANDLE.
|
||||
*/
|
||||
native Handle:SQL_ConnectEx(Handle:driver,
|
||||
const String:host[],
|
||||
const String:user[],
|
||||
const String:pass[],
|
||||
const String:database[],
|
||||
String:error[],
|
||||
maxlength,
|
||||
bool:persistent=true,
|
||||
port=0,
|
||||
maxTimeout=0);
|
||||
|
||||
/**
|
||||
* Returns a driver Handle from a name string.
|
||||
*
|
||||
* If the driver is not found, SourceMod will attempt
|
||||
* to load an extension named dbi.<name>.ext.[dll|so].
|
||||
*
|
||||
* @param name Driver identification string, or an empty
|
||||
* string to return the default driver.
|
||||
* @return Driver Handle, or INVALID_HANDLE on failure.
|
||||
*/
|
||||
native Handle:SQL_GetDriver(const String:name[]="");
|
||||
|
||||
/**
|
||||
* Retrieves a driver's identification string.
|
||||
*
|
||||
* @param driver Driver Handle, or INVALID_HANDLE for the default driver.
|
||||
* @param ident Identification string buffer.
|
||||
* @param maxlength Maximum length of the buffer.
|
||||
* @noreturn
|
||||
* @error Invalid Handle other than INVALID_HANDLE.
|
||||
*/
|
||||
native SQL_GetDriverIdent(Handle:driver, String:ident[], maxlength);
|
||||
|
||||
/**
|
||||
* Retrieves a driver's product string.
|
||||
*
|
||||
* @param driver Driver Handle, or INVALID_HANDLE for the default driver.
|
||||
* @param product Product string buffer.
|
||||
* @param maxlength Maximum length of the buffer.
|
||||
* @noreturn
|
||||
* @error Invalid Handle other than INVALID_HANDLE.
|
||||
*/
|
||||
native SQL_GetDriverProduct(Handle:driver, String:product[], maxlength);
|
||||
|
||||
/**
|
||||
* Returns the number of affected rows from the last query.
|
||||
*
|
||||
* @param hndl A database OR statement Handle.
|
||||
* @return Number of rows affected by the last query.
|
||||
* @error Invalid database or statement Handle.
|
||||
*/
|
||||
native SQL_GetAffectedRows(Handle:hndl);
|
||||
|
||||
/**
|
||||
* Returns the last query's insertion id.
|
||||
*
|
||||
* @param hndl A database OR statement Handle.
|
||||
* @return Last query's insertion id.
|
||||
* @error Invalid database or statement Handle.
|
||||
*/
|
||||
native SQL_GetInsertId(Handle:hndl);
|
||||
|
||||
/**
|
||||
* Returns the error reported by the last query.
|
||||
*
|
||||
* @param hndl A database OR statement Handle.
|
||||
* @param error Error buffer.
|
||||
* @param maxlength Maximum length of the buffer.
|
||||
* @return True if there was an error, false otherwise.
|
||||
* @error Invalid database or statement Handle.
|
||||
*/
|
||||
native bool:SQL_GetError(Handle:hndl, String:error[], maxlength);
|
||||
|
||||
/**
|
||||
* Quotes a database string for literal insertion. This is not needed
|
||||
* for binding strings in prepared statements.
|
||||
*
|
||||
* @param hndl A database Handle.
|
||||
* @param string String to quote.
|
||||
* @param buffer Buffer to store quoted string in.
|
||||
* @param maxlength Maximum length of the buffer.
|
||||
* @param written Optionally returns the number of bytes written.
|
||||
* @return True on success, false if buffer is not big enough.
|
||||
* The buffer must be at least 2*strlen(string)+1.
|
||||
* @error Invalid database or statement Handle.
|
||||
*/
|
||||
native bool:SQL_QuoteString(Handle:database, const String:string[], String:buffer[], maxlength, &written=0);
|
||||
|
||||
/**
|
||||
* Executes a query and ignores the result set.
|
||||
*
|
||||
* @param database A database Handle.
|
||||
* @param query Query string.
|
||||
* @return True if query succeeded, false otherwise. Use
|
||||
* SQL_GetError to find the last error.
|
||||
* @error Invalid database Handle.
|
||||
*/
|
||||
native bool:SQL_FastQuery(Handle:database, const String:query[]);
|
||||
|
||||
/**
|
||||
* Executes a simple query and returns a new query Handle for
|
||||
* receiving the results.
|
||||
*
|
||||
* @param database A database Handle.
|
||||
* @param query Query string.
|
||||
* @return A new Query Handle on success, INVALID_HANDLE
|
||||
* otherwise. The Handle must be freed with CloseHandle().
|
||||
* @error Invalid database Handle.
|
||||
*/
|
||||
native Handle:SQL_Query(Handle:database, const String:query[]);
|
||||
|
||||
/**
|
||||
* Creates a new prepared statement query. Prepared statements can
|
||||
* be executed any number of times. They can also have placeholder
|
||||
* parameters, similar to variables, which can be bound safely and
|
||||
* securely (for example, you do not need to quote bound strings).
|
||||
*
|
||||
* Statement handles will work in any function that accepts a Query handle.
|
||||
*
|
||||
* @param database A database Handle.
|
||||
* @param query Query string.
|
||||
* @param error Error buffer.
|
||||
* @param maxlength Maximum size of the error buffer.
|
||||
* @return A new statement Handle on success, INVALID_HANDLE
|
||||
* otherwise. The Handle must be freed with CloseHandle().
|
||||
* @error Invalid database Handle.
|
||||
*/
|
||||
native Handle:SQL_PrepareQuery(Handle:database, const String:query[], String:error[], maxlength);
|
||||
|
||||
/**
|
||||
* Advances to the next set of results.
|
||||
*
|
||||
* In some SQL implementations, multiple result sets can exist on one query.
|
||||
* This is possible in MySQL with simple queries when executing a CALL
|
||||
* query. If this is the case, all result sets must be processed before
|
||||
* another query is made.
|
||||
*
|
||||
* @param query A query Handle.
|
||||
* @return True if there was another result set, false otherwise.
|
||||
* @error Invalid query Handle.
|
||||
*/
|
||||
native bool:SQL_FetchMoreResults(Handle:query);
|
||||
|
||||
/**
|
||||
* Returns whether or not a result set exists. This will
|
||||
* return true even if 0 results were returned, but false
|
||||
* on queries like UPDATE, INSERT, or DELETE.
|
||||
*
|
||||
* @param query A query (or statement) Handle.
|
||||
* @return True if there is a result set, false otherwise.
|
||||
* @error Invalid query Handle.
|
||||
*/
|
||||
native bool:SQL_HasResultSet(Handle:query);
|
||||
|
||||
/**
|
||||
* Retrieves the number of rows in the last result set.
|
||||
*
|
||||
* @param query A query (or statement) Handle.
|
||||
* @error Invalid query Handle.
|
||||
*/
|
||||
native SQL_GetRowCount(Handle:query);
|
||||
|
||||
/**
|
||||
* Retrieves the name of a field by index.
|
||||
*
|
||||
* @param query A query (or statement) Handle.
|
||||
* @param field Field number (starting from 0).
|
||||
* @param name Name buffer.
|
||||
* @param maxlength Maximum length of the name buffer.
|
||||
* @noreturn
|
||||
* @error Invalid query Handle, invalid field index, or
|
||||
* no current result set.
|
||||
*/
|
||||
native SQL_FieldNumToName(Handle:query, field, String:name[], maxlength);
|
||||
|
||||
/**
|
||||
* Retrieves a field index by name.
|
||||
*
|
||||
* @param query A query (or statement) Handle.
|
||||
* @param name Name of the field (case sensitive).
|
||||
* @param field Variable to store field index in.
|
||||
* @return True if found, false if not found.
|
||||
* @error Invalid query Handle or no current result set.
|
||||
*/
|
||||
native bool:SQL_FieldNameToNum(Handle:query, const String:name[], &field);
|
||||
|
||||
/**
|
||||
* Fetches a row from the current result set. This must be
|
||||
* successfully called before any results are fetched.
|
||||
*
|
||||
* If this function fails, SQL_MoreResults() can be used to
|
||||
* tell if there was an error or the result set is finished.
|
||||
*
|
||||
* @param query A query (or statement) Handle.
|
||||
* @return True if a row was fetched, false otherwise.
|
||||
* @error Invalid query Handle.
|
||||
*/
|
||||
native bool:SQL_FetchRow(Handle:query);
|
||||
|
||||
/**
|
||||
* Returns if there are more rows.
|
||||
*
|
||||
* @param query A query (or statement) Handle.
|
||||
* @return True if there are more rows, false otherwise.
|
||||
* @error Invalid query Handle.
|
||||
*/
|
||||
native bool:SQL_MoreRows(Handle:query);
|
||||
|
||||
/**
|
||||
* Rewinds a result set back to the first result.
|
||||
*
|
||||
* @param query A query (or statement) Handle.
|
||||
* @return True on success, false otherwise.
|
||||
* @error Invalid query Handle or no current result set.
|
||||
*/
|
||||
native bool:SQL_Rewind(Handle:query);
|
||||
|
||||
/**
|
||||
* Fetches a string from a field in the current row of a result set.
|
||||
* If the result is NULL, an empty string will be returned. A NULL
|
||||
* check can be done with the result parameter, or SQL_IsFieldNull().
|
||||
*
|
||||
* @param query A query (or statement) Handle.
|
||||
* @param field The field index (starting from 0).
|
||||
* @param buffer String buffer.
|
||||
* @param maxlength Maximum size of the string buffer.
|
||||
* @param result Optional variable to store the status of the return value.
|
||||
* @return Number of bytes written.
|
||||
* @error Invalid query Handle or field index, invalid
|
||||
* type conversion requested from the database,
|
||||
* or no current result set.
|
||||
*/
|
||||
native SQL_FetchString(Handle:query, field, String:buffer[], maxlength, &DBResult:result=DBVal_Error);
|
||||
|
||||
/**
|
||||
* Fetches a float from a field in the current row of a result set.
|
||||
* If the result is NULL, a value of 0.0 will be returned. A NULL
|
||||
* check can be done with the result parameter, or SQL_IsFieldNull().
|
||||
*
|
||||
* @param query A query (or statement) Handle.
|
||||
* @param field The field index (starting from 0).
|
||||
* @param result Optional variable to store the status of the return value.
|
||||
* @return A float value.
|
||||
* @error Invalid query Handle or field index, invalid
|
||||
* type conversion requested from the database,
|
||||
* or no current result set.
|
||||
*/
|
||||
native Float:SQL_FetchFloat(Handle:query, field, &DBResult:result=DBVal_Error);
|
||||
|
||||
/**
|
||||
* Fetches an integer from a field in the current row of a result set.
|
||||
* If the result is NULL, a value of 0 will be returned. A NULL
|
||||
* check can be done with the result parameter, or SQL_IsFieldNull().
|
||||
*
|
||||
* @param query A query (or statement) Handle.
|
||||
* @param field The field index (starting from 0).
|
||||
* @param result Optional variable to store the status of the return value.
|
||||
* @return An integer value.
|
||||
* @error Invalid query Handle or field index, invalid
|
||||
* type conversion requested from the database,
|
||||
* or no current result set.
|
||||
*/
|
||||
native SQL_FetchInt(Handle:query, field, &DBResult:result=DBVal_Error);
|
||||
|
||||
/**
|
||||
* Returns whether a field's data in the current row of a result set is
|
||||
* NULL or not. NULL is an SQL type which means "no data."
|
||||
*
|
||||
* @param query A query (or statement) Handle.
|
||||
* @param field The field index (starting from 0).
|
||||
* @return True if data is NULL, false otherwise.
|
||||
* @error Invalid query Handle or field index, or no
|
||||
* current result set.
|
||||
*/
|
||||
native bool:SQL_IsFieldNull(Handle:query, field);
|
||||
|
||||
/**
|
||||
* Returns the length of a field's data in the current row of a result
|
||||
* set. This only needs to be called for strings to determine how many
|
||||
* bytes to use. Note that the return value does not include the null
|
||||
* terminator.
|
||||
*
|
||||
* @param query A query (or statement) Handle.
|
||||
* @param field The field index (starting from 0).
|
||||
* @return Number of bytes for the field's data size.
|
||||
* @error Invalid query Handle or field index or no
|
||||
* current result set.
|
||||
*/
|
||||
native SQL_FetchSize(Handle:query, field);
|
||||
|
||||
/**
|
||||
* Binds a parameter in a prepared statement to a given integer value.
|
||||
*
|
||||
* @param statement A statement (prepared query) Handle.
|
||||
* @param param The parameter index (starting from 0).
|
||||
* @param number The number to bind.
|
||||
* @param signed True to bind the number as signed, false to
|
||||
* bind it as unsigned.
|
||||
* @noreturn
|
||||
* @error Invalid statement Handle or parameter index, or
|
||||
* SQL error.
|
||||
*/
|
||||
native SQL_BindParamInt(Handle:statement, param, number, bool:signed=true);
|
||||
|
||||
/**
|
||||
* Binds a parameter in a prepared statement to a given float value.
|
||||
*
|
||||
* @param statement A statement (prepared query) Handle.
|
||||
* @param param The parameter index (starting from 0).
|
||||
* @param float The float number to bind.
|
||||
* @noreturn
|
||||
* @error Invalid statement Handle or parameter index, or
|
||||
* SQL error.
|
||||
*/
|
||||
native SQL_BindParamFloat(Handle:statement, param, Float:value);
|
||||
|
||||
/**
|
||||
* Binds a parameter in a prepared statement to a given string value.
|
||||
*
|
||||
* @param statement A statement (prepared query) Handle.
|
||||
* @param param The parameter index (starting from 0).
|
||||
* @param value The string to bind.
|
||||
* @param copy Whether or not SourceMod should copy the value
|
||||
* locally if necessary. If the string contents
|
||||
* won't change before calling SQL_Execute(), this
|
||||
* can be set to false for optimization.
|
||||
* @noreturn
|
||||
* @error Invalid statement Handle or parameter index, or
|
||||
* SQL error.
|
||||
*/
|
||||
native SQL_BindParamString(Handle:statement, param, const String:value[], bool:copy);
|
||||
|
||||
/**
|
||||
* Executes a prepared statement. All parameters must be bound beforehand.
|
||||
*
|
||||
* @param statement A statement (prepared query) Handle.
|
||||
* @return True on success, false on failure.
|
||||
* @error Invalid statement Handle.
|
||||
*/
|
||||
native bool:SQL_Execute(Handle:statement);
|
||||
|
@ -44,6 +44,7 @@ struct Plugin
|
||||
#include <events>
|
||||
#include <functions>
|
||||
#include <timers>
|
||||
#include <dbi>
|
||||
|
||||
enum DialogType
|
||||
{
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#define SMINTERFACE_DBI_NAME "IDBI"
|
||||
#define SMINTERFACE_DBI_VERSION 1
|
||||
#define SMINTERFACE_DBI_VERSION 2
|
||||
|
||||
namespace SourceMod
|
||||
{
|
||||
@ -561,7 +561,8 @@ namespace SourceMod
|
||||
virtual Handle_t GetHandle() =0;
|
||||
|
||||
/**
|
||||
* @brief Returns the driver's controlling identity.
|
||||
* @brief Returns the driver's controlling identity (must be the same
|
||||
* as from IExtension::GetIdentity).
|
||||
*
|
||||
* @return An IdentityToken_t identity.
|
||||
*/
|
||||
@ -601,7 +602,8 @@ namespace SourceMod
|
||||
virtual void RemoveDriver(IDBDriver *pDriver) =0;
|
||||
|
||||
/**
|
||||
* @brief Searches for database info by name.
|
||||
* @brief Searches for database info by name. Both the return pointer
|
||||
* and all pointers contained therein should be considered volatile.
|
||||
*
|
||||
* @param name Named database info.
|
||||
* @return DatabaseInfo pointer.
|
||||
@ -648,7 +650,8 @@ namespace SourceMod
|
||||
* @brief Creates a Handle_t of the IDBDriver type.
|
||||
*
|
||||
* @param type A DBHandleType value.
|
||||
* @param ptr A pointer corrresponding to a DBHandleType object.
|
||||
* @param ptr A pointer corrresponding to a DBHandleType
|
||||
* object.
|
||||
* @param token Identity pointer of the owning identity.
|
||||
* @return A new Handle_t handle, or 0 on failure.
|
||||
*/
|
||||
@ -673,6 +676,22 @@ namespace SourceMod
|
||||
* @return HandleError value.
|
||||
*/
|
||||
virtual HandleError ReleaseHandle(Handle_t hndl, DBHandleType type, IdentityToken_t *token) =0;
|
||||
|
||||
/**
|
||||
* @brief Given a driver name, attempts to find it. If it is not found, SourceMod
|
||||
* will attempt to load it.
|
||||
*
|
||||
* @param name Driver identifier name.
|
||||
* @return IDBDriver pointer on success, NULL otherwise.
|
||||
*/
|
||||
virtual IDBDriver *FindOrLoadDriver(const char *driver) =0;
|
||||
|
||||
/**
|
||||
* @brief Returns the default driver, or NULL if none is set.
|
||||
*
|
||||
* @return IDBDriver pointer on success, NULL otherwise.
|
||||
*/
|
||||
virtual IDBDriver *GetDefaultDriver() =0;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -137,13 +137,14 @@ namespace SourceMod
|
||||
virtual IdentityType_t FindIdentType(const char *name) =0;
|
||||
|
||||
/**
|
||||
* @brief Creates a new identity token. This token is guaranteed to be unique
|
||||
* amongst all other open identities.
|
||||
* @brief Creates a new identity token. This token is guaranteed to be
|
||||
* unique amongst all other open identities.
|
||||
*
|
||||
* @param type Identity type.
|
||||
* @return A new IdentityToken_t identifier.
|
||||
* @param ptr Private data pointer (cannot be NULL).
|
||||
* @return A new IdentityToken_t pointer, or NULL on failure.
|
||||
*/
|
||||
virtual IdentityToken_t *CreateIdentity(IdentityType_t type) =0;
|
||||
virtual IdentityToken_t *CreateIdentity(IdentityType_t type, void *ptr) =0;
|
||||
|
||||
/**
|
||||
* @brief Destroys an identity type. Note that this will delete any identities
|
||||
@ -161,7 +162,6 @@ namespace SourceMod
|
||||
*/
|
||||
virtual void DestroyIdentity(IdentityToken_t *identity) =0;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Requires an extension. This tells SourceMod that without this extension,
|
||||
* your extension should not be loaded. The name should not include the ".dll" or
|
||||
|
Loading…
Reference in New Issue
Block a user