-initial import of database natives + config
authorDavid Anderson <dvander@alliedmods.net>
Fri Jun 01 02:30:29 2007 +0000 (2007-06-01)
changeset 868bdbf922e246f
parent 867 02f309e10552
child 869 caa5587e708a
-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
configs/databases.cfg
core/Database.cpp
core/Database.h
core/msvc8/sourcemod_mm.vcproj
core/smn_database.cpp
core/systems/ExtensionSys.cpp
core/systems/ExtensionSys.h
core/systems/PluginSys.cpp
core/systems/ShareSys.cpp
core/systems/ShareSys.h
plugins/include/dbi.inc
plugins/include/sourcemod.inc
public/IDBDriver.h
public/IShareSys.h
     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