1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/configs/databases.cfg Fri Jun 01 02:30:29 2007 +0000
1.3 @@ -0,0 +1,15 @@
1.4 +"Databases"
1.5 +{
1.6 + "driver_default" "mysql"
1.7 +
1.8 + "default"
1.9 + {
1.10 + "driver" "default"
1.11 + "host" "localhost"
1.12 + "database" "sourcemod"
1.13 + "user" "root"
1.14 + "pass" ""
1.15 + //"timeout" "0"
1.16 + //"port" "0"
1.17 + }
1.18 +}
2.1 --- a/core/Database.cpp Thu May 31 21:35:33 2007 +0000
2.2 +++ b/core/Database.cpp Fri Jun 01 02:30:29 2007 +0000
2.3 @@ -16,9 +16,23 @@
2.4 #include "HandleSys.h"
2.5 #include "ShareSys.h"
2.6 #include "sourcemod.h"
2.7 +#include "sm_stringutil.h"
2.8 +#include "TextParsers.h"
2.9 +#include "Logger.h"
2.10 +#include "ExtensionSys.h"
2.11 +#include <stdlib.h>
2.12 +
2.13 +#define DBPARSE_LEVEL_NONE 0
2.14 +#define DBPARSE_LEVEL_MAIN 1
2.15 +#define DBPARSE_LEVEL_DATABASE 2
2.16
2.17 DBManager g_DBMan;
2.18
2.19 +DBManager::DBManager()
2.20 +: m_StrTab(512), m_ParseLevel(0), m_ParseState(0), m_pDefault(NULL)
2.21 +{
2.22 +}
2.23 +
2.24 void DBManager::OnSourceModAllInitialized()
2.25 {
2.26 HandleAccess sec;
2.27 @@ -31,6 +45,23 @@
2.28 m_DatabaseType = g_HandleSys.CreateType("IDatabase", this, 0, NULL, NULL, g_pCoreIdent, NULL);
2.29
2.30 g_ShareSys.AddInterface(NULL, this);
2.31 +
2.32 + g_SourceMod.BuildPath(Path_SM, m_Filename, sizeof(m_Filename), "configs/databases.cfg");
2.33 +}
2.34 +
2.35 +void DBManager::OnSourceModLevelChange(const char *mapName)
2.36 +{
2.37 + SMCParseError err;
2.38 + unsigned int line = 0;
2.39 + if ((err = g_TextParser.ParseFile_SMC(m_Filename, this, &line, NULL)) != SMCParse_Okay)
2.40 + {
2.41 + g_Logger.LogError("[SM] Detected parse error(s) in file \"%s\"", m_Filename);
2.42 + if (err != SMCParse_Custom)
2.43 + {
2.44 + const char *txt = g_TextParser.GetSMCErrorString(err);
2.45 + g_Logger.LogError("[SM] Line %d: %s", line, txt);
2.46 + }
2.47 + }
2.48 }
2.49
2.50 void DBManager::OnSourceModShutdown()
2.51 @@ -64,23 +95,173 @@
2.52 }
2.53 }
2.54
2.55 -bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength)
2.56 +void DBManager::ReadSMC_ParseStart()
2.57 {
2.58 - const DatabaseInfo *pInfo = FindDatabaseConf(name);
2.59 + m_confs.clear();
2.60 + m_ParseLevel = 0;
2.61 + m_ParseState = DBPARSE_LEVEL_NONE;
2.62 + m_StrTab.Reset();
2.63 + m_DefDriver.clear();
2.64 +}
2.65
2.66 - for (size_t i=0; i<m_drivers.size(); i++)
2.67 +ConfDbInfo s_CurInfo;
2.68 +SMCParseResult DBManager::ReadSMC_NewSection(const char *name, bool opt_quotes)
2.69 +{
2.70 + if (m_ParseLevel)
2.71 + {
2.72 + m_ParseLevel++;
2.73 + return SMCParse_Continue;
2.74 + }
2.75 +
2.76 + if (m_ParseState == DBPARSE_LEVEL_NONE)
2.77 {
2.78 - if (strcasecmp(pInfo->driver, m_drivers[i]->GetIdentifier()) == 0)
2.79 + if (strcmp(name, "Databases") == 0)
2.80 {
2.81 - *pdr = m_drivers[i];
2.82 - *pdb = m_drivers[i]->Connect(pInfo, persistent, error, maxlength);
2.83 - return (*pdb == NULL);
2.84 + m_ParseState = DBPARSE_LEVEL_MAIN;
2.85 + } else {
2.86 + m_ParseLevel++;
2.87 + }
2.88 + } else if (m_ParseState == DBPARSE_LEVEL_MAIN) {
2.89 + s_CurInfo = ConfDbInfo();
2.90 + s_CurInfo.database = m_StrTab.AddString(name);
2.91 + m_ParseState = DBPARSE_LEVEL_DATABASE;
2.92 + } else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
2.93 + m_ParseLevel++;
2.94 + }
2.95 +
2.96 + return SMCParse_Continue;
2.97 +}
2.98 +
2.99 +SMCParseResult DBManager::ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes)
2.100 +{
2.101 + if (m_ParseLevel)
2.102 + {
2.103 + return SMCParse_Continue;
2.104 + }
2.105 +
2.106 + if (m_ParseState == DBPARSE_LEVEL_MAIN)
2.107 + {
2.108 + if (strcmp(key, "driver_default") == 0)
2.109 + {
2.110 + m_DefDriver.assign(value);
2.111 + }
2.112 + } else if (m_ParseState == DBPARSE_LEVEL_DATABASE) {
2.113 + if (strcmp(key, "driver") == 0)
2.114 + {
2.115 + if (strcmp(value, "default") != 0)
2.116 + {
2.117 + s_CurInfo.driver = m_StrTab.AddString(value);
2.118 + }
2.119 + } else if (strcmp(key, "database") == 0) {
2.120 + s_CurInfo.database = m_StrTab.AddString(value);
2.121 + } else if (strcmp(key, "host") == 0) {
2.122 + s_CurInfo.host = m_StrTab.AddString(value);
2.123 + } else if (strcmp(key, "user") == 0) {
2.124 + s_CurInfo.user = m_StrTab.AddString(value);
2.125 + } else if (strcmp(key, "pass") == 0) {
2.126 + s_CurInfo.pass = m_StrTab.AddString(value);
2.127 + } else if (strcmp(key, "timeout") == 0) {
2.128 + s_CurInfo.info.maxTimeout = atoi(value);
2.129 + } else if (strcmp(key, "port") == 0) {
2.130 + s_CurInfo.info.port = atoi(value);
2.131 }
2.132 }
2.133
2.134 - *pdr = NULL;
2.135 + return SMCParse_Continue;
2.136 +}
2.137 +
2.138 +#define ASSIGN_VAR(var) \
2.139 + if (s_CurInfo.var == -1) { \
2.140 + s_CurInfo.info.var = ""; \
2.141 + } else { \
2.142 + s_CurInfo.info.var = m_StrTab.GetString(s_CurInfo.var); \
2.143 + }
2.144 +
2.145 +SMCParseResult DBManager::ReadSMC_LeavingSection()
2.146 +{
2.147 + if (m_ParseLevel)
2.148 + {
2.149 + m_ParseLevel--;
2.150 + return SMCParse_Continue;
2.151 + }
2.152 +
2.153 + if (m_ParseState == DBPARSE_LEVEL_DATABASE)
2.154 + {
2.155 + /* Set all of the info members to either a blank string
2.156 + * or the string pointer from the string table.
2.157 + */
2.158 + ASSIGN_VAR(driver);
2.159 + ASSIGN_VAR(database);
2.160 + ASSIGN_VAR(host);
2.161 + ASSIGN_VAR(user);
2.162 + ASSIGN_VAR(pass);
2.163 +
2.164 + /* Save it.. */
2.165 + m_confs.push_back(s_CurInfo);
2.166 +
2.167 + /* Go up one level */
2.168 + m_ParseState = DBPARSE_LEVEL_MAIN;
2.169 + } else if (m_ParseState == DBPARSE_LEVEL_MAIN) {
2.170 + m_ParseState = DBPARSE_LEVEL_NONE;
2.171 + return SMCParse_Halt;
2.172 + }
2.173 +
2.174 + return SMCParse_Continue;
2.175 +}
2.176 +#undef ASSIGN_VAR
2.177 +
2.178 +void DBManager::ReadSMC_ParseEnd(bool halted, bool failed)
2.179 +{
2.180 +}
2.181 +
2.182 +bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength)
2.183 +{
2.184 + ConfDbInfo *pInfo = GetDatabaseConf(name);
2.185 +
2.186 + if (!pInfo)
2.187 + {
2.188 + if (pdr)
2.189 + {
2.190 + *pdr = NULL;
2.191 + }
2.192 + *pdb = NULL;
2.193 + UTIL_Format(error, maxlength, "Configuration \"%s\" not found", name);
2.194 + return false;
2.195 + }
2.196 +
2.197 + if (!pInfo->realDriver)
2.198 + {
2.199 + /* Try to assign a real driver pointer */
2.200 + if (pInfo->info.driver[0] == '\0')
2.201 + {
2.202 + if (!m_pDefault && m_DefDriver.size() > 0)
2.203 + {
2.204 + m_pDefault = FindOrLoadDriver(m_DefDriver.c_str());
2.205 + }
2.206 + pInfo->realDriver = m_pDefault;
2.207 + } else {
2.208 + pInfo->realDriver = FindOrLoadDriver(pInfo->info.driver);
2.209 + }
2.210 + }
2.211 +
2.212 + if (pInfo->realDriver)
2.213 + {
2.214 + if (pdr)
2.215 + {
2.216 + *pdr = pInfo->realDriver;
2.217 + }
2.218 + *pdb = pInfo->realDriver->Connect(&pInfo->info, persistent, error, maxlength);
2.219 + return (*pdb != NULL);
2.220 + }
2.221 +
2.222 + if (pdr)
2.223 + {
2.224 + *pdr = NULL;
2.225 + }
2.226 *pdb = NULL;
2.227
2.228 + UTIL_Format(error, maxlength, "Driver \"%s\" not found", pInfo->driver);
2.229 +
2.230 return false;
2.231 }
2.232
2.233 @@ -99,6 +280,27 @@
2.234 return;
2.235 }
2.236 }
2.237 +
2.238 + /* Make sure NOTHING references this! */
2.239 + List<ConfDbInfo>::iterator iter;
2.240 + for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
2.241 + {
2.242 + ConfDbInfo &db = (*iter);
2.243 + if (db.realDriver == pDriver)
2.244 + {
2.245 + db.realDriver = NULL;
2.246 + }
2.247 + }
2.248 +}
2.249 +
2.250 +IDBDriver *DBManager::GetDefaultDriver()
2.251 +{
2.252 + if (!m_pDefault && m_DefDriver.size() > 0)
2.253 + {
2.254 + m_pDefault = FindOrLoadDriver(m_DefDriver.c_str());
2.255 + }
2.256 +
2.257 + return m_pDefault;
2.258 }
2.259
2.260 Handle_t DBManager::CreateHandle(DBHandleType dtype, void *ptr, IdentityToken_t *pToken)
2.261 @@ -158,6 +360,58 @@
2.262
2.263 const DatabaseInfo *DBManager::FindDatabaseConf(const char *name)
2.264 {
2.265 - /* :TODO: */
2.266 + ConfDbInfo *info = GetDatabaseConf(name);
2.267 + if (!info)
2.268 + {
2.269 + return NULL;
2.270 + }
2.271 +
2.272 + return &info->info;
2.273 +}
2.274 +
2.275 +ConfDbInfo *DBManager::GetDatabaseConf(const char *name)
2.276 +{
2.277 + List<ConfDbInfo>::iterator iter;
2.278 +
2.279 + for (iter=m_confs.begin(); iter!=m_confs.end(); iter++)
2.280 + {
2.281 + ConfDbInfo &conf = (*iter);
2.282 + if (strcmp(m_StrTab.GetString(conf.name), name) == 0)
2.283 + {
2.284 + return &conf;
2.285 + }
2.286 + }
2.287 +
2.288 return NULL;
2.289 }
2.290 +
2.291 +IDBDriver *DBManager::FindOrLoadDriver(const char *name)
2.292 +{
2.293 + size_t last_size = m_drivers.size();
2.294 + for (size_t i=0; i<last_size; i++)
2.295 + {
2.296 + if (strcmp(m_drivers[i]->GetIdentifier(), name) == 0)
2.297 + {
2.298 + return m_drivers[i];
2.299 + }
2.300 + }
2.301 +
2.302 + char filename[PLATFORM_MAX_PATH];
2.303 + UTIL_Format(filename, sizeof(filename), "dbi.%s", name);
2.304 +
2.305 + IExtension *pExt = g_Extensions.LoadAutoExtension(filename);
2.306 + if (!pExt || !pExt->IsLoaded() || m_drivers.size() <= last_size)
2.307 + {
2.308 + return NULL;
2.309 + }
2.310 +
2.311 + /* last_size is now gauranteed to be a valid index.
2.312 + * The identifier must match the name.
2.313 + */
2.314 + if (strcmp(m_drivers[last_size]->GetIdentifier(), name) == 0)
2.315 + {
2.316 + return m_drivers[last_size];
2.317 + }
2.318 +
2.319 + return NULL;
2.320 +}
3.1 --- a/core/Database.h Thu May 31 21:35:33 2007 +0000
3.2 +++ b/core/Database.h Fri Jun 01 02:30:29 2007 +0000
3.3 @@ -18,19 +18,43 @@
3.4 #include <IDBDriver.h>
3.5 #include "sm_globals.h"
3.6 #include <sh_vector.h>
3.7 +#include <sh_string.h>
3.8 +#include <sh_list.h>
3.9 +#include <ITextParsers.h>
3.10 +#include "sm_memtable.h"
3.11
3.12 using namespace SourceHook;
3.13
3.14 +struct ConfDbInfo
3.15 +{
3.16 + ConfDbInfo() : name(-1), driver(-1), host(-1), user(-1), pass(-1),
3.17 + database(-1), realDriver(NULL)
3.18 + {
3.19 + }
3.20 + int name;
3.21 + int driver;
3.22 + int host;
3.23 + int user;
3.24 + int pass;
3.25 + int database;
3.26 + IDBDriver *realDriver;
3.27 + DatabaseInfo info;
3.28 +};
3.29 +
3.30 class DBManager :
3.31 public IDBManager,
3.32 public SMGlobalClass,
3.33 - public IHandleTypeDispatch
3.34 + public IHandleTypeDispatch,
3.35 + public ITextListener_SMC
3.36 {
3.37 public:
3.38 + DBManager();
3.39 +public:
3.40 const char *GetInterfaceName();
3.41 unsigned int GetInterfaceVersion();
3.42 public: //SMGlobalClass
3.43 void OnSourceModAllInitialized();
3.44 + void OnSourceModLevelChange(const char *mapName);
3.45 void OnSourceModShutdown();
3.46 public: //IHandleTypeDispatch
3.47 void OnHandleDestroy(HandleType_t type, void *object);
3.48 @@ -44,10 +68,27 @@
3.49 Handle_t CreateHandle(DBHandleType type, void *ptr, IdentityToken_t *pToken);
3.50 HandleError ReadHandle(Handle_t hndl, DBHandleType type, void **ptr);
3.51 HandleError ReleaseHandle(Handle_t hndl, DBHandleType type, IdentityToken_t *token);
3.52 +public: //ITextListener_SMC
3.53 + void ReadSMC_ParseStart();
3.54 + SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes);
3.55 + SMCParseResult ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes);
3.56 + SMCParseResult ReadSMC_LeavingSection();
3.57 + void ReadSMC_ParseEnd(bool halted, bool failed);
3.58 +public:
3.59 + ConfDbInfo *GetDatabaseConf(const char *name);
3.60 + IDBDriver *FindOrLoadDriver(const char *name);
3.61 + IDBDriver *GetDefaultDriver();
3.62 private:
3.63 CVector<IDBDriver *> m_drivers;
3.64 + List<ConfDbInfo> m_confs;
3.65 HandleType_t m_DriverType;
3.66 HandleType_t m_DatabaseType;
3.67 + String m_DefDriver;
3.68 + BaseStringTable m_StrTab;
3.69 + char m_Filename[PLATFORM_MAX_PATH];
3.70 + unsigned int m_ParseLevel;
3.71 + unsigned int m_ParseState;
3.72 + IDBDriver *m_pDefault;
3.73 };
3.74
3.75 extern DBManager g_DBMan;
4.1 --- a/core/msvc8/sourcemod_mm.vcproj Thu May 31 21:35:33 2007 +0000
4.2 +++ b/core/msvc8/sourcemod_mm.vcproj Fri Jun 01 02:30:29 2007 +0000
4.3 @@ -797,6 +797,10 @@
4.4 >
4.5 </File>
4.6 <File
4.7 + RelativePath="..\smn_database.cpp"
4.8 + >
4.9 + </File>
4.10 + <File
4.11 RelativePath="..\smn_datapacks.cpp"
4.12 >
4.13 </File>
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/core/smn_database.cpp Fri Jun 01 02:30:29 2007 +0000
5.3 @@ -0,0 +1,860 @@
5.4 +#include "sm_globals.h"
5.5 +#include "HandleSys.h"
5.6 +#include "Database.h"
5.7 +#include "ExtensionSys.h"
5.8 +#include "PluginSys.h"
5.9 +
5.10 +HandleType_t hQueryType;
5.11 +HandleType_t hStmtType;
5.12 +
5.13 +class DatabaseHelpers :
5.14 + public SMGlobalClass,
5.15 + public IHandleTypeDispatch
5.16 +{
5.17 +public:
5.18 + virtual void OnSourceModAllInitialized()
5.19 + {
5.20 + HandleAccess acc;
5.21 +
5.22 + /* Disable cloning */
5.23 + g_HandleSys.InitAccessDefaults(NULL, &acc);
5.24 + acc.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY;
5.25 +
5.26 + TypeAccess tacc;
5.27 +
5.28 + g_HandleSys.InitAccessDefaults(&tacc, NULL);
5.29 + tacc.ident = g_pCoreIdent;
5.30 +
5.31 + hQueryType = g_HandleSys.CreateType("IQuery", this, 0, &tacc, &acc, g_pCoreIdent, NULL);
5.32 + hStmtType = g_HandleSys.CreateType("IPreparedQuery", this, hQueryType, &tacc, &acc, NULL, NULL);
5.33 + }
5.34 +
5.35 + virtual void OnSourceModShutdown()
5.36 + {
5.37 + g_HandleSys.RemoveType(hStmtType, g_pCoreIdent);
5.38 + g_HandleSys.RemoveType(hQueryType, g_pCoreIdent);
5.39 + }
5.40 +
5.41 + virtual void OnHandleDestroy(HandleType_t type, void *object)
5.42 + {
5.43 + if (type == hQueryType)
5.44 + {
5.45 + IQuery *query = (IQuery *)object;
5.46 + query->Destroy();
5.47 + } else if (type == hStmtType) {
5.48 + IPreparedQuery *query = (IPreparedQuery *)object;
5.49 + query->Destroy();
5.50 + }
5.51 + }
5.52 +} s_DatabaseNativeHelpers;
5.53 +
5.54 +//is this safe for stmt handles? i think since it's single inheritance, it always will be.
5.55 +inline HandleError ReadQueryHndl(Handle_t hndl, IPluginContext *pContext, IQuery **query)
5.56 +{
5.57 + HandleSecurity sec;
5.58 + sec.pOwner = pContext->GetIdentity();
5.59 + sec.pIdentity = g_pCoreIdent;
5.60 +
5.61 + return g_HandleSys.ReadHandle(hndl, hQueryType, &sec, (void **)query);
5.62 +}
5.63 +
5.64 +inline HandleError ReadStmtHndl(Handle_t hndl, IPluginContext *pContext, IPreparedQuery **query)
5.65 +{
5.66 + HandleSecurity sec;
5.67 + sec.pOwner = pContext->GetIdentity();
5.68 + sec.pIdentity = g_pCoreIdent;
5.69 +
5.70 + return g_HandleSys.ReadHandle(hndl, hStmtType, &sec, (void **)query);
5.71 +}
5.72 +
5.73 +inline HandleError ReadDbOrStmtHndl(Handle_t hndl, IPluginContext *pContext, IDatabase **db, IPreparedQuery **query)
5.74 +{
5.75 + HandleError err;
5.76 + if ((err = g_DBMan.ReadHandle(hndl, DBHandle_Database, (void **)db)) == HandleError_Type)
5.77 + {
5.78 + *db = NULL;
5.79 + return ReadStmtHndl(hndl, pContext, query);
5.80 + }
5.81 + return err;
5.82 +}
5.83 +
5.84 +static cell_t SQL_Connect(IPluginContext *pContext, const cell_t *params)
5.85 +{
5.86 + char *conf, *err;
5.87 +
5.88 + size_t maxlength = (size_t)params[4];
5.89 + bool persistent = params[2] ? true : false;
5.90 + pContext->LocalToString(params[1], &conf);
5.91 + pContext->LocalToString(params[3], &err);
5.92 +
5.93 + IDBDriver *driver;
5.94 + IDatabase *db;
5.95 + if (!g_DBMan.Connect(conf, &driver, &db, persistent, err, maxlength))
5.96 + {
5.97 + return BAD_HANDLE;
5.98 + }
5.99 +
5.100 + /* HACK! Add us to the dependency list */
5.101 + CExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity());
5.102 + if (pExt)
5.103 + {
5.104 + g_Extensions.BindChildPlugin(pExt, g_PluginSys.FindPluginByContext(pContext->GetContext()));
5.105 + }
5.106 +
5.107 + return db->GetHandle();
5.108 +}
5.109 +
5.110 +static cell_t SQL_ConnectEx(IPluginContext *pContext, const cell_t *params)
5.111 +{
5.112 + IDBDriver *driver;
5.113 + if (params[1] == BAD_HANDLE)
5.114 + {
5.115 + if ((driver = g_DBMan.GetDefaultDriver()) == NULL)
5.116 + {
5.117 + return pContext->ThrowNativeError("Could not find any default driver");
5.118 + }
5.119 + } else {
5.120 + HandleError err;
5.121 + if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Driver, (void **)&driver))
5.122 + != HandleError_None)
5.123 + {
5.124 + return pContext->ThrowNativeError("Invalid driver Handle %x (error: %d)", params[1], err);
5.125 + }
5.126 + }
5.127 +
5.128 + char *host, *user, *pass, *database, *error;
5.129 + size_t maxlength = (size_t)params[7];
5.130 + bool persistent = params[8] ? true : false;
5.131 + unsigned int port = params[9];
5.132 + unsigned int maxTimeout = params[10];
5.133 + pContext->LocalToString(params[2], &host);
5.134 + pContext->LocalToString(params[3], &user);
5.135 + pContext->LocalToString(params[4], &pass);
5.136 + pContext->LocalToString(params[5], &database);
5.137 + pContext->LocalToString(params[6], &error);
5.138 +
5.139 + DatabaseInfo info;
5.140 + info.database = database;
5.141 + info.driver = driver->GetIdentifier();
5.142 + info.host = host;
5.143 + info.maxTimeout = maxTimeout;
5.144 + info.pass = pass;
5.145 + info.port = port;
5.146 + info.user = user;
5.147 +
5.148 + IDatabase *db = driver->Connect(&info, persistent, error, maxlength);
5.149 +
5.150 + if (db)
5.151 + {
5.152 + /* HACK! Add us to the dependency list */
5.153 + CExtension *pExt = g_Extensions.GetExtensionFromIdent(driver->GetIdentity());
5.154 + if (pExt)
5.155 + {
5.156 + g_Extensions.BindChildPlugin(pExt, g_PluginSys.FindPluginByContext(pContext->GetContext()));
5.157 + }
5.158 +
5.159 + return db->GetHandle();
5.160 + }
5.161 +
5.162 + return BAD_HANDLE;
5.163 +}
5.164 +
5.165 +static cell_t SQL_GetDriverIdent(IPluginContext *pContext, const cell_t *params)
5.166 +{
5.167 + IDBDriver *driver;
5.168 + if (params[1] == BAD_HANDLE)
5.169 + {
5.170 + if ((driver = g_DBMan.GetDefaultDriver()) == NULL)
5.171 + {
5.172 + return pContext->ThrowNativeError("Could not find any default driver");
5.173 + }
5.174 + } else {
5.175 + HandleError err;
5.176 + if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Driver, (void **)&driver))
5.177 + != HandleError_None)
5.178 + {
5.179 + return pContext->ThrowNativeError("Invalid driver Handle %x (error: %d)", params[1], err);
5.180 + }
5.181 + }
5.182 +
5.183 + pContext->StringToLocalUTF8(params[2], params[3], driver->GetIdentifier(), NULL);
5.184 +
5.185 + return 1;
5.186 +}
5.187 +
5.188 +static cell_t SQL_GetDriver(IPluginContext *pContext, const cell_t *params)
5.189 +{
5.190 + char *name;
5.191 + pContext->LocalToString(params[1], &name);
5.192 +
5.193 + IDBDriver *driver = NULL;
5.194 + if (name[0] == '\0')
5.195 + {
5.196 + driver = g_DBMan.GetDefaultDriver();
5.197 + } else {
5.198 + driver = g_DBMan.FindOrLoadDriver(name);
5.199 + }
5.200 +
5.201 + return (driver != NULL) ? driver->GetHandle() : BAD_HANDLE;
5.202 +}
5.203 +
5.204 +static cell_t SQL_GetDriverProduct(IPluginContext *pContext, const cell_t *params)
5.205 +{
5.206 + IDBDriver *driver;
5.207 + if (params[1] == BAD_HANDLE)
5.208 + {
5.209 + if ((driver = g_DBMan.GetDefaultDriver()) == NULL)
5.210 + {
5.211 + return pContext->ThrowNativeError("Could not find any default driver");
5.212 + }
5.213 + } else {
5.214 + HandleError err;
5.215 + if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Driver, (void **)&driver))
5.216 + != HandleError_None)
5.217 + {
5.218 + return pContext->ThrowNativeError("Invalid driver Handle %x (error: %d)", params[1], err);
5.219 + }
5.220 + }
5.221 +
5.222 + pContext->StringToLocalUTF8(params[2], params[3], driver->GetProductName(), NULL);
5.223 +
5.224 + return 1;
5.225 +}
5.226 +
5.227 +static cell_t SQL_GetAffectedRows(IPluginContext *pContext, const cell_t *params)
5.228 +{
5.229 + IDatabase *db = NULL;
5.230 + IPreparedQuery *stmt = NULL;
5.231 + HandleError err;
5.232 +
5.233 + if ((err = ReadDbOrStmtHndl(params[1], pContext, &db, &stmt)) != HandleError_None)
5.234 + {
5.235 + return pContext->ThrowNativeError("Invalid statement or db Handle %x (error: %d)", params[1], err);
5.236 + }
5.237 +
5.238 + if (db)
5.239 + {
5.240 + return db->GetAffectedRows();
5.241 + } else if (stmt) {
5.242 + return stmt->GetAffectedRows();
5.243 + }
5.244 +
5.245 + return pContext->ThrowNativeError("Unknown error reading db/stmt handles");
5.246 +}
5.247 +
5.248 +static cell_t SQL_GetInsertId(IPluginContext *pContext, const cell_t *params)
5.249 +{
5.250 + IDatabase *db = NULL;
5.251 + IPreparedQuery *stmt = NULL;
5.252 + HandleError err;
5.253 +
5.254 + if ((err = ReadDbOrStmtHndl(params[1], pContext, &db, &stmt)) != HandleError_None)
5.255 + {
5.256 + return pContext->ThrowNativeError("Invalid statement or db Handle %x (error: %d)", params[1], err);
5.257 + }
5.258 +
5.259 + if (db)
5.260 + {
5.261 + return db->GetInsertID();
5.262 + } else if (stmt) {
5.263 + return stmt->GetInsertID();
5.264 + }
5.265 +
5.266 + return pContext->ThrowNativeError("Unknown error reading db/stmt handles");
5.267 +}
5.268 +
5.269 +static cell_t SQL_GetError(IPluginContext *pContext, const cell_t *params)
5.270 +{
5.271 + IDatabase *db = NULL;
5.272 + IPreparedQuery *stmt = NULL;
5.273 + HandleError err;
5.274 +
5.275 + if ((err = ReadDbOrStmtHndl(params[1], pContext, &db, &stmt)) != HandleError_None)
5.276 + {
5.277 + return pContext->ThrowNativeError("Invalid statement or db Handle %x (error: %d)", params[1], err);
5.278 + }
5.279 +
5.280 + const char *error = "";
5.281 + if (db)
5.282 + {
5.283 + error = db->GetError();
5.284 + } else if (stmt) {
5.285 + error = stmt->GetError();
5.286 + }
5.287 +
5.288 + if (error[0] == '\0')
5.289 + {
5.290 + return false;
5.291 + }
5.292 +
5.293 + pContext->StringToLocalUTF8(params[2], params[3], error, NULL);
5.294 +
5.295 + return 1;
5.296 +}
5.297 +
5.298 +static cell_t SQL_QuoteString(IPluginContext *pContext, const cell_t *params)
5.299 +{
5.300 + IDatabase *db = NULL;
5.301 + HandleError err;
5.302 +
5.303 + if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
5.304 + != HandleError_None)
5.305 + {
5.306 + return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
5.307 + }
5.308 +
5.309 + char *input, *output;
5.310 + size_t maxlength = (size_t)params[4];
5.311 + pContext->LocalToString(params[2], &input);
5.312 + pContext->LocalToString(params[3], &output);
5.313 +
5.314 + size_t written;
5.315 + bool s = db->QuoteString(input, output, maxlength, &written);
5.316 +
5.317 + cell_t *addr;
5.318 + pContext->LocalToPhysAddr(params[5], &addr);
5.319 + *addr = (cell_t)written;
5.320 +
5.321 + return s ? 1 : 0;
5.322 +}
5.323 +
5.324 +static cell_t SQL_FastQuery(IPluginContext *pContext, const cell_t *params)
5.325 +{
5.326 + IDatabase *db = NULL;
5.327 + HandleError err;
5.328 +
5.329 + if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
5.330 + != HandleError_None)
5.331 + {
5.332 + return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
5.333 + }
5.334 +
5.335 + char *query;
5.336 + pContext->LocalToString(params[2], &query);
5.337 +
5.338 + return db->DoSimpleQuery(query) ? 1 : 0;
5.339 +}
5.340 +
5.341 +static cell_t SQL_Query(IPluginContext *pContext, const cell_t *params)
5.342 +{
5.343 + IDatabase *db = NULL;
5.344 + HandleError err;
5.345 +
5.346 + if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
5.347 + != HandleError_None)
5.348 + {
5.349 + return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
5.350 + }
5.351 +
5.352 + char *query;
5.353 + pContext->LocalToString(params[2], &query);
5.354 +
5.355 + IQuery *qr = db->DoQuery(query);
5.356 +
5.357 + if (!qr)
5.358 + {
5.359 + return BAD_HANDLE;
5.360 + }
5.361 +
5.362 + Handle_t hndl = g_HandleSys.CreateHandle(hQueryType, qr, pContext->GetIdentity(), g_pCoreIdent, NULL);
5.363 + if (hndl == BAD_HANDLE)
5.364 + {
5.365 + qr->Destroy();
5.366 + return BAD_HANDLE;
5.367 + }
5.368 +
5.369 + return hndl;
5.370 +}
5.371 +
5.372 +static cell_t SQL_PrepareQuery(IPluginContext *pContext, const cell_t *params)
5.373 +{
5.374 + IDatabase *db = NULL;
5.375 + HandleError err;
5.376 +
5.377 + if ((err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db))
5.378 + != HandleError_None)
5.379 + {
5.380 + return pContext->ThrowNativeError("Invalid database Handle %x (error: %d)", params[1], err);
5.381 + }
5.382 +
5.383 + char *query, *error;
5.384 + size_t maxlength = (size_t)params[4];
5.385 + pContext->LocalToString(params[2], &query);
5.386 + pContext->LocalToString(params[3], &error);
5.387 +
5.388 + IPreparedQuery *qr = db->PrepareQuery(query, error, maxlength);
5.389 +
5.390 + if (!qr)
5.391 + {
5.392 + return BAD_HANDLE;
5.393 + }
5.394 +
5.395 + Handle_t hndl = g_HandleSys.CreateHandle(hStmtType, qr, pContext->GetIdentity(), g_pCoreIdent, NULL);
5.396 + if (hndl == BAD_HANDLE)
5.397 + {
5.398 + qr->Destroy();
5.399 + return BAD_HANDLE;
5.400 + }
5.401 +
5.402 + return hndl;
5.403 +}
5.404 +
5.405 +static cell_t SQL_FetchMoreResults(IPluginContext *pContext, const cell_t *params)
5.406 +{
5.407 + IQuery *query;
5.408 + HandleError err;
5.409 +
5.410 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
5.411 + {
5.412 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
5.413 + }
5.414 +
5.415 + return query->FetchMoreResults() ? 1 : 0;
5.416 +}
5.417 +
5.418 +static cell_t SQL_HasResultSet(IPluginContext *pContext, const cell_t *params)
5.419 +{
5.420 + IQuery *query;
5.421 + HandleError err;
5.422 +
5.423 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
5.424 + {
5.425 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
5.426 + }
5.427 +
5.428 + return query->GetResultSet() != NULL ? true : false;
5.429 +}
5.430 +
5.431 +static cell_t SQL_GetRowCount(IPluginContext *pContext, const cell_t *params)
5.432 +{
5.433 + IQuery *query;
5.434 + HandleError err;
5.435 +
5.436 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
5.437 + {
5.438 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
5.439 + }
5.440 +
5.441 + IResultSet *rs = query->GetResultSet();
5.442 + if (!rs)
5.443 + {
5.444 + return 0;
5.445 + }
5.446 +
5.447 + return rs->GetRowCount();
5.448 +}
5.449 +
5.450 +static cell_t SQL_GetFieldCount(IPluginContext *pContext, const cell_t *params)
5.451 +{
5.452 + IQuery *query;
5.453 + HandleError err;
5.454 +
5.455 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
5.456 + {
5.457 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
5.458 + }
5.459 +
5.460 + IResultSet *rs = query->GetResultSet();
5.461 + if (!rs)
5.462 + {
5.463 + return 0;
5.464 + }
5.465 +
5.466 + return rs->GetFieldCount();
5.467 +}
5.468 +
5.469 +static cell_t SQL_FieldNumToName(IPluginContext *pContext, const cell_t *params)
5.470 +{
5.471 + IQuery *query;
5.472 + HandleError err;
5.473 +
5.474 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
5.475 + {
5.476 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
5.477 + }
5.478 +
5.479 + IResultSet *rs = query->GetResultSet();
5.480 + if (!rs)
5.481 + {
5.482 + return pContext->ThrowNativeError("No current result set");
5.483 + }
5.484 +
5.485 + unsigned int field = params[2];
5.486 +
5.487 + const char *fldname;
5.488 + if ((fldname = rs->FieldNumToName(field)) == NULL)
5.489 + {
5.490 + return pContext->ThrowNativeError("Invalid field index %d", field);
5.491 + }
5.492 +
5.493 + pContext->StringToLocalUTF8(params[3], params[4], fldname, NULL);
5.494 +
5.495 + return 1;
5.496 +}
5.497 +
5.498 +static cell_t SQL_FieldNameToNum(IPluginContext *pContext, const cell_t *params)
5.499 +{
5.500 + IQuery *query;
5.501 + HandleError err;
5.502 +
5.503 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
5.504 + {
5.505 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
5.506 + }
5.507 +
5.508 + IResultSet *rs = query->GetResultSet();
5.509 + if (!rs)
5.510 + {
5.511 + return pContext->ThrowNativeError("No current result set");
5.512 + }
5.513 +
5.514 + char *field;
5.515 + pContext->LocalToString(params[2], &field);
5.516 +
5.517 + cell_t *num;
5.518 + pContext->LocalToPhysAddr(params[3], &num);
5.519 +
5.520 + return rs->FieldNameToNum(field, (unsigned int *)num) ? 1 : 0;
5.521 +}
5.522 +
5.523 +static cell_t SQL_FetchRow(IPluginContext *pContext, const cell_t *params)
5.524 +{
5.525 + IQuery *query;
5.526 + HandleError err;
5.527 +
5.528 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
5.529 + {
5.530 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
5.531 + }
5.532 +
5.533 + IResultSet *rs = query->GetResultSet();
5.534 + if (!rs)
5.535 + {
5.536 + return pContext->ThrowNativeError("No current result set");
5.537 + }
5.538 +
5.539 + return (rs->FetchRow() != NULL) ? true : false;
5.540 +}
5.541 +
5.542 +static cell_t SQL_MoreRows(IPluginContext *pContext, const cell_t *params)
5.543 +{
5.544 + IQuery *query;
5.545 + HandleError err;
5.546 +
5.547 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
5.548 + {
5.549 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
5.550 + }
5.551 +
5.552 + IResultSet *rs = query->GetResultSet();
5.553 + if (!rs)
5.554 + {
5.555 + return pContext->ThrowNativeError("No current result set");
5.556 + }
5.557 +
5.558 + return rs->MoreRows() ? 1 : 0;
5.559 +}
5.560 +
5.561 +static cell_t SQL_Rewind(IPluginContext *pContext, const cell_t *params)
5.562 +{
5.563 + IQuery *query;
5.564 + HandleError err;
5.565 +
5.566 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
5.567 + {
5.568 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
5.569 + }
5.570 +
5.571 + IResultSet *rs = query->GetResultSet();
5.572 + if (!rs)
5.573 + {
5.574 + return pContext->ThrowNativeError("No current result set");
5.575 + }
5.576 +
5.577 + return rs->Rewind() ? 1 : 0;
5.578 +}
5.579 +
5.580 +static cell_t SQL_FetchString(IPluginContext *pContext, const cell_t *params)
5.581 +{
5.582 + IQuery *query;
5.583 + HandleError err;
5.584 +
5.585 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
5.586 + {
5.587 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
5.588 + }
5.589 +
5.590 + IResultSet *rs = query->GetResultSet();
5.591 + if (!rs)
5.592 + {
5.593 + return pContext->ThrowNativeError("No current result set");
5.594 + }
5.595 +
5.596 + IResultRow *row = rs->CurrentRow();
5.597 + if (!row)
5.598 + {
5.599 + return pContext->ThrowNativeError("Current result set has no fetched rows");
5.600 + }
5.601 +
5.602 + const char *str;
5.603 + size_t length;
5.604 + DBResult res = row->GetString(params[2], &str, &length);
5.605 +
5.606 + if (res == DBVal_Error)
5.607 + {
5.608 + return pContext->ThrowNativeError("Error fetching data from field %d", params[2]);
5.609 + } else if (res == DBVal_TypeMismatch) {
5.610 + return pContext->ThrowNativeError("Could not fetch data in field %d as a string", params[2]);
5.611 + }
5.612 +
5.613 + pContext->StringToLocalUTF8(params[3], params[4], str, &length);
5.614 +
5.615 + cell_t *addr;
5.616 + pContext->LocalToPhysAddr(params[5], &addr);
5.617 + *addr = (cell_t)res;
5.618 +
5.619 + return (cell_t)length;
5.620 +}
5.621 +
5.622 +static cell_t SQL_FetchFloat(IPluginContext *pContext, const cell_t *params)
5.623 +{
5.624 + IQuery *query;
5.625 + HandleError err;
5.626 +
5.627 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
5.628 + {
5.629 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
5.630 + }
5.631 +
5.632 + IResultSet *rs = query->GetResultSet();
5.633 + if (!rs)
5.634 + {
5.635 + return pContext->ThrowNativeError("No current result set");
5.636 + }
5.637 +
5.638 + IResultRow *row = rs->CurrentRow();
5.639 + if (!row)
5.640 + {
5.641 + return pContext->ThrowNativeError("Current result set has no fetched rows");
5.642 + }
5.643 +
5.644 + float f;
5.645 + DBResult res = row->GetFloat(params[2], &f);
5.646 +
5.647 + if (res == DBVal_Error)
5.648 + {
5.649 + return pContext->ThrowNativeError("Error fetching data from field %d", params[2]);
5.650 + } else if (res == DBVal_TypeMismatch) {
5.651 + return pContext->ThrowNativeError("Could not fetch data in field %d as a float", params[2]);
5.652 + }
5.653 +
5.654 + cell_t *addr;
5.655 + pContext->LocalToPhysAddr(params[5], &addr);
5.656 + *addr = (cell_t)res;
5.657 +
5.658 + return sp_ftoc(f);
5.659 +}
5.660 +
5.661 +static cell_t SQL_FetchInt(IPluginContext *pContext, const cell_t *params)
5.662 +{
5.663 + IQuery *query;
5.664 + HandleError err;
5.665 +
5.666 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
5.667 + {
5.668 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
5.669 + }
5.670 +
5.671 + IResultSet *rs = query->GetResultSet();
5.672 + if (!rs)
5.673 + {
5.674 + return pContext->ThrowNativeError("No current result set");
5.675 + }
5.676 +
5.677 + IResultRow *row = rs->CurrentRow();
5.678 + if (!row)
5.679 + {
5.680 + return pContext->ThrowNativeError("Current result set has no fetched rows");
5.681 + }
5.682 +
5.683 + int iv;
5.684 + DBResult res = row->GetInt(params[2], &iv);
5.685 +
5.686 + if (res == DBVal_Error)
5.687 + {
5.688 + return pContext->ThrowNativeError("Error fetching data from field %d", params[2]);
5.689 + } else if (res == DBVal_TypeMismatch) {
5.690 + return pContext->ThrowNativeError("Could not fetch data in field %d as an integer", params[2]);
5.691 + }
5.692 +
5.693 + cell_t *addr;
5.694 + pContext->LocalToPhysAddr(params[5], &addr);
5.695 + *addr = (cell_t)res;
5.696 +
5.697 + return iv;
5.698 +}
5.699 +
5.700 +static cell_t SQL_IsFieldNull(IPluginContext *pContext, const cell_t *params)
5.701 +{
5.702 + IQuery *query;
5.703 + HandleError err;
5.704 +
5.705 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
5.706 + {
5.707 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
5.708 + }
5.709 +
5.710 + IResultSet *rs = query->GetResultSet();
5.711 + if (!rs)
5.712 + {
5.713 + return pContext->ThrowNativeError("No current result set");
5.714 + }
5.715 +
5.716 + IResultRow *row = rs->CurrentRow();
5.717 + if (!row)
5.718 + {
5.719 + return pContext->ThrowNativeError("Current result set has no fetched rows");
5.720 + }
5.721 +
5.722 + if ((unsigned)params[2] >= rs->GetFieldCount())
5.723 + {
5.724 + return pContext->ThrowNativeError("Invalid field index %d", params[2]);
5.725 + }
5.726 +
5.727 + return row->IsNull(params[2]) ? 1 : 0;
5.728 +}
5.729 +
5.730 +static cell_t SQL_FetchSize(IPluginContext *pContext, const cell_t *params)
5.731 +{
5.732 + IQuery *query;
5.733 + HandleError err;
5.734 +
5.735 + if ((err = ReadQueryHndl(params[1], pContext, &query)) != HandleError_None)
5.736 + {
5.737 + return pContext->ThrowNativeError("Invalid query Handle %x (error: %d)", params[1], err);
5.738 + }
5.739 +
5.740 + IResultSet *rs = query->GetResultSet();
5.741 + if (!rs)
5.742 + {
5.743 + return pContext->ThrowNativeError("No current result set");
5.744 + }
5.745 +
5.746 + IResultRow *row = rs->CurrentRow();
5.747 + if (!row)
5.748 + {
5.749 + return pContext->ThrowNativeError("Current result set has no fetched rows");
5.750 + }
5.751 +
5.752 + if ((unsigned)params[2] >= rs->GetFieldCount())
5.753 + {
5.754 + return pContext->ThrowNativeError("Invalid field index %d", params[2]);
5.755 + }
5.756 +
5.757 + return row->GetDataSize(params[2]);
5.758 +}
5.759 +
5.760 +static cell_t SQL_BindParamInt(IPluginContext *pContext, const cell_t *params)
5.761 +{
5.762 + IPreparedQuery *stmt;
5.763 + HandleError err;
5.764 +
5.765 + if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
5.766 + {
5.767 + return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
5.768 + }
5.769 +
5.770 + if (!stmt->BindParamInt(params[2], params[3], params[4] ? true : false))
5.771 + {
5.772 + return pContext->ThrowNativeError("Could not bind parameter %d as an integer", params[2]);
5.773 + }
5.774 +
5.775 + return 1;
5.776 +}
5.777 +
5.778 +static cell_t SQL_BindParamFloat(IPluginContext *pContext, const cell_t *params)
5.779 +{
5.780 + IPreparedQuery *stmt;
5.781 + HandleError err;
5.782 +
5.783 + if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
5.784 + {
5.785 + return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
5.786 + }
5.787 +
5.788 + if (!stmt->BindParamFloat(params[2], sp_ctof(params[3])))
5.789 + {
5.790 + return pContext->ThrowNativeError("Could not bind parameter %d as a float", params[2]);
5.791 + }
5.792 +
5.793 + return 1;
5.794 +}
5.795 +
5.796 +static cell_t SQL_BindParamString(IPluginContext *pContext, const cell_t *params)
5.797 +{
5.798 + IPreparedQuery *stmt;
5.799 + HandleError err;
5.800 +
5.801 + if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
5.802 + {
5.803 + return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
5.804 + }
5.805 +
5.806 + char *str;
5.807 + pContext->LocalToString(params[3], &str);
5.808 +
5.809 + if (!stmt->BindParamString(params[2], str, params[4] ? true : false))
5.810 + {
5.811 + return pContext->ThrowNativeError("Could not bind parameter %d as a string", params[2]);
5.812 + }
5.813 +
5.814 + return 1;
5.815 +}
5.816 +
5.817 +static cell_t SQL_Execute(IPluginContext *pContext, const cell_t *params)
5.818 +{
5.819 + IPreparedQuery *stmt;
5.820 + HandleError err;
5.821 +
5.822 + if ((err = ReadStmtHndl(params[1], pContext, &stmt)) != HandleError_None)
5.823 + {
5.824 + return pContext->ThrowNativeError("Invalid statement Handle %x (error: %d)", params[1], err);
5.825 + }
5.826 +
5.827 + return stmt->Execute() ? 1 : 0;
5.828 +}
5.829 +
5.830 +REGISTER_NATIVES(dbNatives)
5.831 +{
5.832 + {"SQL_BindParamInt", SQL_BindParamInt},
5.833 + {"SQL_BindParamFloat", SQL_BindParamFloat},
5.834 + {"SQL_BindParamString", SQL_BindParamString},
5.835 + {"SQL_Connect", SQL_Connect},
5.836 + {"SQL_ConnectEx", SQL_ConnectEx},
5.837 + {"SQL_Execute", SQL_Execute},
5.838 + {"SQL_FastQuery", SQL_FastQuery},
5.839 + {"SQL_FetchFloat", SQL_FetchFloat},
5.840 + {"SQL_FetchInt", SQL_FetchInt},
5.841 + {"SQL_FetchMoreResults", SQL_FetchMoreResults},
5.842 + {"SQL_FetchRow", SQL_FetchRow},
5.843 + {"SQL_FetchSize", SQL_FetchSize},
5.844 + {"SQL_FetchString", SQL_FetchString},
5.845 + {"SQL_FieldNameToNum", SQL_FieldNameToNum},
5.846 + {"SQL_FieldNumToName", SQL_FieldNumToName},
5.847 + {"SQL_GetAffectedRows", SQL_GetAffectedRows},
5.848 + {"SQL_GetDriver", SQL_GetDriver},
5.849 + {"SQL_GetDriverIdent", SQL_GetDriverIdent},
5.850 + {"SQL_GetDriverProduct", SQL_GetDriverProduct},
5.851 + {"SQL_GetError", SQL_GetError},
5.852 + {"SQL_GetFieldCount", SQL_GetFieldCount},
5.853 + {"SQL_GetInsertId", SQL_GetInsertId},
5.854 + {"SQL_GetRowCount", SQL_GetRowCount},
5.855 + {"SQL_HasResultSet", SQL_HasResultSet},
5.856 + {"SQL_IsFieldNull", SQL_IsFieldNull},
5.857 + {"SQL_MoreRows", SQL_MoreRows},
5.858 + {"SQL_Query", SQL_Query},
5.859 + {"SQL_QuoteString", SQL_QuoteString},
5.860 + {"SQL_PrepareQuery", SQL_PrepareQuery},
5.861 + {"SQL_Rewind", SQL_Rewind},
5.862 + {NULL, NULL},
5.863 +};
6.1 --- a/core/systems/ExtensionSys.cpp Thu May 31 21:35:33 2007 +0000
6.2 +++ b/core/systems/ExtensionSys.cpp Fri Jun 01 02:30:29 2007 +0000
6.3 @@ -70,7 +70,7 @@
6.4 m_PlId = g_pMMPlugins->Load(path, g_PLID, already, error, maxlength);
6.5 }
6.6
6.7 - m_pIdentToken = g_ShareSys.CreateIdentity(g_ExtType);
6.8 + m_pIdentToken = g_ShareSys.CreateIdentity(g_ExtType, this);
6.9
6.10 if (!m_pAPI->OnExtensionLoad(this, &g_ShareSys, error, maxlength, !g_SourceMod.IsMapLoading()))
6.11 {
6.12 @@ -132,7 +132,11 @@
6.13
6.14 void CExtension::AddPlugin(IPlugin *pPlugin)
6.15 {
6.16 - m_Plugins.push_back(pPlugin);
6.17 + /* Unfortunately we have to do this :( */
6.18 + if (m_Plugins.find(pPlugin) != m_Plugins.end())
6.19 + {
6.20 + m_Plugins.push_back(pPlugin);
6.21 + }
6.22 }
6.23
6.24 void CExtension::RemovePlugin(IPlugin *pPlugin)
6.25 @@ -866,3 +870,13 @@
6.26 g_RootMenu.DrawGenericOption("list", "List extensions");
6.27 g_RootMenu.DrawGenericOption("unload", "Unload an extension");
6.28 }
6.29 +
6.30 +CExtension *CExtensionManager::GetExtensionFromIdent(IdentityToken_t *ptr)
6.31 +{
6.32 + if (ptr->type == g_ExtType)
6.33 + {
6.34 + return (CExtension *)(ptr->ptr);
6.35 + }
6.36 +
6.37 + return NULL;
6.38 +}
7.1 --- a/core/systems/ExtensionSys.h Thu May 31 21:35:33 2007 +0000
7.2 +++ b/core/systems/ExtensionSys.h Fri Jun 01 02:30:29 2007 +0000
7.3 @@ -96,6 +96,8 @@
7.4 void MarkAllLoaded();
7.5 void AddDependency(IExtension *pSource, const char *file, bool required, bool autoload);
7.6 void TryAutoload();
7.7 +public:
7.8 + CExtension *GetExtensionFromIdent(IdentityToken_t *ptr);
7.9 private:
7.10 CExtension *FindByOrder(unsigned int num);
7.11 private:
8.1 --- a/core/systems/PluginSys.cpp Thu May 31 21:35:33 2007 +0000
8.2 +++ b/core/systems/PluginSys.cpp Fri Jun 01 02:30:29 2007 +0000
8.3 @@ -91,7 +91,7 @@
8.4 {
8.5 if (!m_handle)
8.6 {
8.7 - m_ident = g_ShareSys.CreateIdentity(g_PluginIdent);
8.8 + m_ident = g_ShareSys.CreateIdentity(g_PluginIdent, this);
8.9 m_handle = g_HandleSys.CreateHandle(g_PluginType, this, g_PluginSys.GetIdentity(), g_PluginSys.GetIdentity(), NULL);
8.10 m_ctx.base->SetIdentity(m_ident);
8.11 }
9.1 --- a/core/systems/ShareSys.cpp Thu May 31 21:35:33 2007 +0000
9.2 +++ b/core/systems/ShareSys.cpp Fri Jun 01 02:30:29 2007 +0000
9.3 @@ -34,7 +34,7 @@
9.4 m_CoreType = CreateIdentType("CORE");
9.5 }
9.6
9.7 - return CreateIdentity(m_CoreType);
9.8 + return CreateIdentity(m_CoreType, this);
9.9 }
9.10
9.11 void ShareSystem::OnSourceModStartup(bool late)
9.12 @@ -96,7 +96,7 @@
9.13 /* THIS WILL NEVER BE CALLED FOR ANYTHING WITH THE IDENTITY TYPE */
9.14 }
9.15
9.16 -IdentityToken_t *ShareSystem::CreateIdentity(IdentityType_t type)
9.17 +IdentityToken_t *ShareSystem::CreateIdentity(IdentityType_t type, void *ptr)
9.18 {
9.19 if (!m_TypeRoot)
9.20 {
9.21 @@ -110,6 +110,8 @@
9.22 sec.pOwner = sec.pIdentity = GetIdentRoot();
9.23
9.24 pToken->ident = g_HandleSys.CreateHandleInt(type, NULL, &sec, NULL, NULL, true);
9.25 + pToken->ptr = ptr;
9.26 + pToken->type = type;
9.27
9.28 return pToken;
9.29 }
10.1 --- a/core/systems/ShareSys.h Thu May 31 21:35:33 2007 +0000
10.2 +++ b/core/systems/ShareSys.h Fri Jun 01 02:30:29 2007 +0000
10.3 @@ -28,6 +28,8 @@
10.4 struct IdentityToken_t
10.5 {
10.6 Handle_t ident;
10.7 + void *ptr;
10.8 + IdentityType_t type;
10.9 };
10.10 };
10.11
10.12 @@ -53,7 +55,7 @@
10.13 void AddNatives(IExtension *myself, const sp_nativeinfo_t *natives);
10.14 IdentityType_t CreateIdentType(const char *name);
10.15 IdentityType_t FindIdentType(const char *name);
10.16 - IdentityToken_t *CreateIdentity(IdentityType_t type);
10.17 + IdentityToken_t *CreateIdentity(IdentityType_t type, void *ptr);
10.18 void DestroyIdentType(IdentityType_t type);
10.19 void DestroyIdentity(IdentityToken_t *identity);
10.20 void AddDependency(IExtension *myself, const char *filename, bool require, bool autoload);
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
11.2 +++ b/plugins/include/dbi.inc Fri Jun 01 02:30:29 2007 +0000
11.3 @@ -0,0 +1,445 @@
11.4 +/**
11.5 + * vim: set ts=4 :
11.6 + * ===============================================================
11.7 + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
11.8 + * ===============================================================
11.9 + *
11.10 + * This file is part of the SourceMod/SourcePawn SDK. This file may only be used
11.11 + * or modified under the Terms and Conditions of its License Agreement, which is found
11.12 + * in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins
11.13 + * may change at any time. To view the latest information, see:
11.14 + * http://www.sourcemod.net/license.php
11.15 + *
11.16 + * Version: $Id$
11.17 + */
11.18 +
11.19 +#if defined _dbi_included
11.20 + #endinput
11.21 +#endif
11.22 +#define _dbi_included
11.23 +
11.24 +/**
11.25 + * @handle Driver
11.26 + *
11.27 + * Contains information about an SQL driver.
11.28 + */
11.29 +
11.30 +/**
11.31 + * @handle Database
11.32 + *
11.33 + * Contains information about a database connection.
11.34 + */
11.35 +
11.36 +/**
11.37 + * @handle Query
11.38 + *
11.39 + * Contains information about an active query and its
11.40 + * result sets.
11.41 + */
11.42 +
11.43 +/**
11.44 + * @handle Statement : Query
11.45 + *
11.46 + * Extends a Query Handle and can be used as a Query Handle.
11.47 + * Statement Handles are for prepared queries and contain
11.48 + * their own function for binding parameters. Statement
11.49 + * Handles can be used instead of database Handles in a few
11.50 + * select functions.
11.51 + */
11.52 +
11.53 +/**
11.54 + * Describes a database field fetch status.
11.55 + */
11.56 +enum DBResult
11.57 +{
11.58 + DBVal_Error = 0, /**< Column number/field is invalid. */
11.59 + DBVal_TypeMismatch = 1, /**< You cannot retrieve this data with this type. */
11.60 + DBVal_Null = 2, /**< Field has no data (NULL) */
11.61 + DBVal_Data = 3, /**< Field has data */
11.62 +}
11.63 +
11.64 +/**
11.65 + * Creates an SQL connection from a named configuration.
11.66 + *
11.67 + * @param confname Named configuration.
11.68 + * @param persistent True to re-use a previous persistent connection if
11.69 + * possible, false otherwise.
11.70 + * @param error Error buffer.
11.71 + * @param maxlength Maximum length of the error buffer.
11.72 + * @return A database connection Handle, or INVALID_HANDLE on failure.
11.73 + */
11.74 +native Handle:SQL_Connect(const String:confname[], bool:persistent, String:error[], maxlength);
11.75 +
11.76 +/**
11.77 + * Creates a default SQL connection.
11.78 + *
11.79 + * @param error Error buffer.
11.80 + * @param maxlength Maximum length of the error buffer.
11.81 + * @param persistent True to re-use a previous persistent connection
11.82 + * if possible, false otherwise.
11.83 + * @return A database connection Handle, or INVALID_HANDLE on failure.
11.84 + */
11.85 +stock Handle:SQL_DefConnect(String:error[], maxlength, bool:persistent=true)
11.86 +{
11.87 + return SQL_Connect("default", persistent, error, maxlength);
11.88 +}
11.89 +
11.90 +/**
11.91 + * Creates an SQL connection from specific parameters.
11.92 + *
11.93 + * @param driver Driver Handle, or INVALID_HANDLE for default.
11.94 + * @param host Host name.
11.95 + * @param user User name.
11.96 + * @param pass User password.
11.97 + * @param database Database name.
11.98 + * @param error Error buffer.
11.99 + * @param maxlength Maximum length of the error buffer.
11.100 + * @param persistent True to re-use a previous persistent connection
11.101 + * if possible, false otherwise.
11.102 + * @param port Optional port to specify.
11.103 + * @param maxTimeout Maximum timeout in seconds if applicable.
11.104 + * @return A database connection Handle, or INVALID_HANDLE on failure.
11.105 + * @error Invalid driver Handle other than INVALID_HANDLE.
11.106 + */
11.107 +native Handle:SQL_ConnectEx(Handle:driver,
11.108 + const String:host[],
11.109 + const String:user[],
11.110 + const String:pass[],
11.111 + const String:database[],
11.112 + String:error[],
11.113 + maxlength,
11.114 + bool:persistent=true,
11.115 + port=0,
11.116 + maxTimeout=0);
11.117 +
11.118 +/**
11.119 + * Returns a driver Handle from a name string.
11.120 + *
11.121 + * If the driver is not found, SourceMod will attempt
11.122 + * to load an extension named dbi.<name>.ext.[dll|so].
11.123 + *
11.124 + * @param name Driver identification string, or an empty
11.125 + * string to return the default driver.
11.126 + * @return Driver Handle, or INVALID_HANDLE on failure.
11.127 + */
11.128 +native Handle:SQL_GetDriver(const String:name[]="");
11.129 +
11.130 +/**
11.131 + * Retrieves a driver's identification string.
11.132 + *
11.133 + * @param driver Driver Handle, or INVALID_HANDLE for the default driver.
11.134 + * @param ident Identification string buffer.
11.135 + * @param maxlength Maximum length of the buffer.
11.136 + * @noreturn
11.137 + * @error Invalid Handle other than INVALID_HANDLE.
11.138 + */
11.139 +native SQL_GetDriverIdent(Handle:driver, String:ident[], maxlength);
11.140 +
11.141 +/**
11.142 + * Retrieves a driver's product string.
11.143 + *
11.144 + * @param driver Driver Handle, or INVALID_HANDLE for the default driver.
11.145 + * @param product Product string buffer.
11.146 + * @param maxlength Maximum length of the buffer.
11.147 + * @noreturn
11.148 + * @error Invalid Handle other than INVALID_HANDLE.
11.149 + */
11.150 +native SQL_GetDriverProduct(Handle:driver, String:product[], maxlength);
11.151 +
11.152 +/**
11.153 + * Returns the number of affected rows from the last query.
11.154 + *
11.155 + * @param hndl A database OR statement Handle.
11.156 + * @return Number of rows affected by the last query.
11.157 + * @error Invalid database or statement Handle.
11.158 + */
11.159 +native SQL_GetAffectedRows(Handle:hndl);
11.160 +
11.161 +/**
11.162 + * Returns the last query's insertion id.
11.163 + *
11.164 + * @param hndl A database OR statement Handle.
11.165 + * @return Last query's insertion id.
11.166 + * @error Invalid database or statement Handle.
11.167 + */
11.168 +native SQL_GetInsertId(Handle:hndl);
11.169 +
11.170 +/**
11.171 + * Returns the error reported by the last query.
11.172 + *
11.173 + * @param hndl A database OR statement Handle.
11.174 + * @param error Error buffer.
11.175 + * @param maxlength Maximum length of the buffer.
11.176 + * @return True if there was an error, false otherwise.
11.177 + * @error Invalid database or statement Handle.
11.178 + */
11.179 +native bool:SQL_GetError(Handle:hndl, String:error[], maxlength);
11.180 +
11.181 +/**
11.182 + * Quotes a database string for literal insertion. This is not needed
11.183 + * for binding strings in prepared statements.
11.184 + *
11.185 + * @param hndl A database Handle.
11.186 + * @param string String to quote.
11.187 + * @param buffer Buffer to store quoted string in.
11.188 + * @param maxlength Maximum length of the buffer.
11.189 + * @param written Optionally returns the number of bytes written.
11.190 + * @return True on success, false if buffer is not big enough.
11.191 + * The buffer must be at least 2*strlen(string)+1.
11.192 + * @error Invalid database or statement Handle.
11.193 + */
11.194 +native bool:SQL_QuoteString(Handle:database, const String:string[], String:buffer[], maxlength, &written=0);
11.195 +
11.196 +/**
11.197 + * Executes a query and ignores the result set.
11.198 + *
11.199 + * @param database A database Handle.
11.200 + * @param query Query string.
11.201 + * @return True if query succeeded, false otherwise. Use
11.202 + * SQL_GetError to find the last error.
11.203 + * @error Invalid database Handle.
11.204 + */
11.205 +native bool:SQL_FastQuery(Handle:database, const String:query[]);
11.206 +
11.207 +/**
11.208 + * Executes a simple query and returns a new query Handle for
11.209 + * receiving the results.
11.210 + *
11.211 + * @param database A database Handle.
11.212 + * @param query Query string.
11.213 + * @return A new Query Handle on success, INVALID_HANDLE
11.214 + * otherwise. The Handle must be freed with CloseHandle().
11.215 + * @error Invalid database Handle.
11.216 + */
11.217 +native Handle:SQL_Query(Handle:database, const String:query[]);
11.218 +
11.219 +/**
11.220 + * Creates a new prepared statement query. Prepared statements can
11.221 + * be executed any number of times. They can also have placeholder
11.222 + * parameters, similar to variables, which can be bound safely and
11.223 + * securely (for example, you do not need to quote bound strings).
11.224 + *
11.225 + * Statement handles will work in any function that accepts a Query handle.
11.226 + *
11.227 + * @param database A database Handle.
11.228 + * @param query Query string.
11.229 + * @param error Error buffer.
11.230 + * @param maxlength Maximum size of the error buffer.
11.231 + * @return A new statement Handle on success, INVALID_HANDLE
11.232 + * otherwise. The Handle must be freed with CloseHandle().
11.233 + * @error Invalid database Handle.
11.234 + */
11.235 +native Handle:SQL_PrepareQuery(Handle:database, const String:query[], String:error[], maxlength);
11.236 +
11.237 +/**
11.238 + * Advances to the next set of results.
11.239 + *
11.240 + * In some SQL implementations, multiple result sets can exist on one query.
11.241 + * This is possible in MySQL with simple queries when executing a CALL
11.242 + * query. If this is the case, all result sets must be processed before
11.243 + * another query is made.
11.244 + *
11.245 + * @param query A query Handle.
11.246 + * @return True if there was another result set, false otherwise.
11.247 + * @error Invalid query Handle.
11.248 + */
11.249 +native bool:SQL_FetchMoreResults(Handle:query);
11.250 +
11.251 +/**
11.252 + * Returns whether or not a result set exists. This will
11.253 + * return true even if 0 results were returned, but false
11.254 + * on queries like UPDATE, INSERT, or DELETE.
11.255 + *
11.256 + * @param query A query (or statement) Handle.
11.257 + * @return True if there is a result set, false otherwise.
11.258 + * @error Invalid query Handle.
11.259 + */
11.260 +native bool:SQL_HasResultSet(Handle:query);
11.261 +
11.262 +/**
11.263 + * Retrieves the number of rows in the last result set.
11.264 + *
11.265 + * @param query A query (or statement) Handle.
11.266 + * @error Invalid query Handle.
11.267 + */
11.268 +native SQL_GetRowCount(Handle:query);
11.269 +
11.270 +/**
11.271 + * Retrieves the name of a field by index.
11.272 + *
11.273 + * @param query A query (or statement) Handle.
11.274 + * @param field Field number (starting from 0).
11.275 + * @param name Name buffer.
11.276 + * @param maxlength Maximum length of the name buffer.
11.277 + * @noreturn
11.278 + * @error Invalid query Handle, invalid field index, or
11.279 + * no current result set.
11.280 + */
11.281 +native SQL_FieldNumToName(Handle:query, field, String:name[], maxlength);
11.282 +
11.283 +/**
11.284 + * Retrieves a field index by name.
11.285 + *
11.286 + * @param query A query (or statement) Handle.
11.287 + * @param name Name of the field (case sensitive).
11.288 + * @param field Variable to store field index in.
11.289 + * @return True if found, false if not found.
11.290 + * @error Invalid query Handle or no current result set.
11.291 + */
11.292 +native bool:SQL_FieldNameToNum(Handle:query, const String:name[], &field);
11.293 +
11.294 +/**
11.295 + * Fetches a row from the current result set. This must be
11.296 + * successfully called before any results are fetched.
11.297 + *
11.298 + * If this function fails, SQL_MoreResults() can be used to
11.299 + * tell if there was an error or the result set is finished.
11.300 + *
11.301 + * @param query A query (or statement) Handle.
11.302 + * @return True if a row was fetched, false otherwise.
11.303 + * @error Invalid query Handle.
11.304 + */
11.305 +native bool:SQL_FetchRow(Handle:query);
11.306 +
11.307 +/**
11.308 + * Returns if there are more rows.
11.309 + *
11.310 + * @param query A query (or statement) Handle.
11.311 + * @return True if there are more rows, false otherwise.
11.312 + * @error Invalid query Handle.
11.313 + */
11.314 +native bool:SQL_MoreRows(Handle:query);
11.315 +
11.316 +/**
11.317 + * Rewinds a result set back to the first result.
11.318 + *
11.319 + * @param query A query (or statement) Handle.
11.320 + * @return True on success, false otherwise.
11.321 + * @error Invalid query Handle or no current result set.
11.322 + */
11.323 +native bool:SQL_Rewind(Handle:query);
11.324 +
11.325 +/**
11.326 + * Fetches a string from a field in the current row of a result set.
11.327 + * If the result is NULL, an empty string will be returned. A NULL
11.328 + * check can be done with the result parameter, or SQL_IsFieldNull().
11.329 + *
11.330 + * @param query A query (or statement) Handle.
11.331 + * @param field The field index (starting from 0).
11.332 + * @param buffer String buffer.
11.333 + * @param maxlength Maximum size of the string buffer.
11.334 + * @param result Optional variable to store the status of the return value.
11.335 + * @return Number of bytes written.
11.336 + * @error Invalid query Handle or field index, invalid
11.337 + * type conversion requested from the database,
11.338 + * or no current result set.
11.339 + */
11.340 +native SQL_FetchString(Handle:query, field, String:buffer[], maxlength, &DBResult:result=DBVal_Error);
11.341 +
11.342 +/**
11.343 + * Fetches a float from a field in the current row of a result set.
11.344 + * If the result is NULL, a value of 0.0 will be returned. A NULL
11.345 + * check can be done with the result parameter, or SQL_IsFieldNull().
11.346 + *
11.347 + * @param query A query (or statement) Handle.
11.348 + * @param field The field index (starting from 0).
11.349 + * @param result Optional variable to store the status of the return value.
11.350 + * @return A float value.
11.351 + * @error Invalid query Handle or field index, invalid
11.352 + * type conversion requested from the database,
11.353 + * or no current result set.
11.354 + */
11.355 +native Float:SQL_FetchFloat(Handle:query, field, &DBResult:result=DBVal_Error);
11.356 +
11.357 +/**
11.358 + * Fetches an integer from a field in the current row of a result set.
11.359 + * If the result is NULL, a value of 0 will be returned. A NULL
11.360 + * check can be done with the result parameter, or SQL_IsFieldNull().
11.361 + *
11.362 + * @param query A query (or statement) Handle.
11.363 + * @param field The field index (starting from 0).
11.364 + * @param result Optional variable to store the status of the return value.
11.365 + * @return An integer value.
11.366 + * @error Invalid query Handle or field index, invalid
11.367 + * type conversion requested from the database,
11.368 + * or no current result set.
11.369 + */
11.370 +native SQL_FetchInt(Handle:query, field, &DBResult:result=DBVal_Error);
11.371 +
11.372 +/**
11.373 + * Returns whether a field's data in the current row of a result set is
11.374 + * NULL or not. NULL is an SQL type which means "no data."
11.375 + *
11.376 + * @param query A query (or statement) Handle.
11.377 + * @param field The field index (starting from 0).
11.378 + * @return True if data is NULL, false otherwise.
11.379 + * @error Invalid query Handle or field index, or no
11.380 + * current result set.
11.381 + */
11.382 +native bool:SQL_IsFieldNull(Handle:query, field);
11.383 +
11.384 +/**
11.385 + * Returns the length of a field's data in the current row of a result
11.386 + * set. This only needs to be called for strings to determine how many
11.387 + * bytes to use. Note that the return value does not include the null
11.388 + * terminator.
11.389 + *
11.390 + * @param query A query (or statement) Handle.
11.391 + * @param field The field index (starting from 0).
11.392 + * @return Number of bytes for the field's data size.
11.393 + * @error Invalid query Handle or field index or no
11.394 + * current result set.
11.395 + */
11.396 +native SQL_FetchSize(Handle:query, field);
11.397 +
11.398 +/**
11.399 + * Binds a parameter in a prepared statement to a given integer value.
11.400 + *
11.401 + * @param statement A statement (prepared query) Handle.
11.402 + * @param param The parameter index (starting from 0).
11.403 + * @param number The number to bind.
11.404 + * @param signed True to bind the number as signed, false to
11.405 + * bind it as unsigned.
11.406 + * @noreturn
11.407 + * @error Invalid statement Handle or parameter index, or
11.408 + * SQL error.
11.409 + */
11.410 +native SQL_BindParamInt(Handle:statement, param, number, bool:signed=true);
11.411 +
11.412 +/**
11.413 + * Binds a parameter in a prepared statement to a given float value.
11.414 + *
11.415 + * @param statement A statement (prepared query) Handle.
11.416 + * @param param The parameter index (starting from 0).
11.417 + * @param float The float number to bind.
11.418 + * @noreturn
11.419 + * @error Invalid statement Handle or parameter index, or
11.420 + * SQL error.
11.421 + */
11.422 +native SQL_BindParamFloat(Handle:statement, param, Float:value);
11.423 +
11.424 +/**
11.425 + * Binds a parameter in a prepared statement to a given string value.
11.426 + *
11.427 + * @param statement A statement (prepared query) Handle.
11.428 + * @param param The parameter index (starting from 0).
11.429 + * @param value The string to bind.
11.430 + * @param copy Whether or not SourceMod should copy the value
11.431 + * locally if necessary. If the string contents
11.432 + * won't change before calling SQL_Execute(), this
11.433 + * can be set to false for optimization.
11.434 + * @noreturn
11.435 + * @error Invalid statement Handle or parameter index, or
11.436 + * SQL error.
11.437 + */
11.438 +native SQL_BindParamString(Handle:statement, param, const String:value[], bool:copy);
11.439 +
11.440 +/**
11.441 + * Executes a prepared statement. All parameters must be bound beforehand.
11.442 + *
11.443 + * @param statement A statement (prepared query) Handle.
11.444 + * @return True on success, false on failure.
11.445 + * @error Invalid statement Handle.
11.446 + */
11.447 +native bool:SQL_Execute(Handle:statement);
11.448 +
12.1 --- a/plugins/include/sourcemod.inc Thu May 31 21:35:33 2007 +0000
12.2 +++ b/plugins/include/sourcemod.inc Fri Jun 01 02:30:29 2007 +0000
12.3 @@ -44,6 +44,7 @@
12.4 #include <events>
12.5 #include <functions>
12.6 #include <timers>
12.7 +#include <dbi>
12.8
12.9 enum DialogType
12.10 {
13.1 --- a/public/IDBDriver.h Thu May 31 21:35:33 2007 +0000
13.2 +++ b/public/IDBDriver.h Fri Jun 01 02:30:29 2007 +0000
13.3 @@ -24,7 +24,7 @@
13.4 #include <string.h>
13.5
13.6 #define SMINTERFACE_DBI_NAME "IDBI"
13.7 -#define SMINTERFACE_DBI_VERSION 1
13.8 +#define SMINTERFACE_DBI_VERSION 2
13.9
13.10 namespace SourceMod
13.11 {
13.12 @@ -561,7 +561,8 @@
13.13 virtual Handle_t GetHandle() =0;
13.14
13.15 /**
13.16 - * @brief Returns the driver's controlling identity.
13.17 + * @brief Returns the driver's controlling identity (must be the same
13.18 + * as from IExtension::GetIdentity).
13.19 *
13.20 * @return An IdentityToken_t identity.
13.21 */
13.22 @@ -601,7 +602,8 @@
13.23 virtual void RemoveDriver(IDBDriver *pDriver) =0;
13.24
13.25 /**
13.26 - * @brief Searches for database info by name.
13.27 + * @brief Searches for database info by name. Both the return pointer
13.28 + * and all pointers contained therein should be considered volatile.
13.29 *
13.30 * @param name Named database info.
13.31 * @return DatabaseInfo pointer.
13.32 @@ -648,7 +650,8 @@
13.33 * @brief Creates a Handle_t of the IDBDriver type.
13.34 *
13.35 * @param type A DBHandleType value.
13.36 - * @param ptr A pointer corrresponding to a DBHandleType object.
13.37 + * @param ptr A pointer corrresponding to a DBHandleType
13.38 + * object.
13.39 * @param token Identity pointer of the owning identity.
13.40 * @return A new Handle_t handle, or 0 on failure.
13.41 */
13.42 @@ -673,6 +676,22 @@
13.43 * @return HandleError value.
13.44 */
13.45 virtual HandleError ReleaseHandle(Handle_t hndl, DBHandleType type, IdentityToken_t *token) =0;
13.46 +
13.47 + /**
13.48 + * @brief Given a driver name, attempts to find it. If it is not found, SourceMod
13.49 + * will attempt to load it.
13.50 + *
13.51 + * @param name Driver identifier name.
13.52 + * @return IDBDriver pointer on success, NULL otherwise.
13.53 + */
13.54 + virtual IDBDriver *FindOrLoadDriver(const char *driver) =0;
13.55 +
13.56 + /**
13.57 + * @brief Returns the default driver, or NULL if none is set.
13.58 + *
13.59 + * @return IDBDriver pointer on success, NULL otherwise.
13.60 + */
13.61 + virtual IDBDriver *GetDefaultDriver() =0;
13.62 };
13.63 }
13.64
14.1 --- a/public/IShareSys.h Thu May 31 21:35:33 2007 +0000
14.2 +++ b/public/IShareSys.h Fri Jun 01 02:30:29 2007 +0000
14.3 @@ -137,13 +137,14 @@
14.4 virtual IdentityType_t FindIdentType(const char *name) =0;
14.5
14.6 /**
14.7 - * @brief Creates a new identity token. This token is guaranteed to be unique
14.8 - * amongst all other open identities.
14.9 + * @brief Creates a new identity token. This token is guaranteed to be
14.10 + * unique amongst all other open identities.
14.11 *
14.12 * @param type Identity type.
14.13 - * @return A new IdentityToken_t identifier.
14.14 + * @param ptr Private data pointer (cannot be NULL).
14.15 + * @return A new IdentityToken_t pointer, or NULL on failure.
14.16 */
14.17 - virtual IdentityToken_t *CreateIdentity(IdentityType_t type) =0;
14.18 + virtual IdentityToken_t *CreateIdentity(IdentityType_t type, void *ptr) =0;
14.19
14.20 /**
14.21 * @brief Destroys an identity type. Note that this will delete any identities
14.22 @@ -161,7 +162,6 @@
14.23 */
14.24 virtual void DestroyIdentity(IdentityToken_t *identity) =0;
14.25
14.26 -
14.27 /**
14.28 * @brief Requires an extension. This tells SourceMod that without this extension,
14.29 * your extension should not be loaded. The name should not include the ".dll" or