posted new IDBDriver API - no natives are implemented yet, MySQL extension coming very shortly
authorDavid Anderson <dvander@alliedmods.net>
Tue May 29 08:32:12 2007 +0000 (2007-05-29)
changeset 858b783a611f604
parent 857 11471aa66e06
child 859 556b6529b8ab
posted new IDBDriver API - no natives are implemented yet, MySQL extension coming very shortly
core/Database.cpp
core/Database.h
public/IDBDriver.h
     1.1 --- a/core/Database.cpp	Tue May 29 08:30:13 2007 +0000
     1.2 +++ b/core/Database.cpp	Tue May 29 08:32:12 2007 +0000
     1.3 @@ -28,7 +28,22 @@
     1.4  	
     1.5  	m_DriverType = g_HandleSys.CreateType("IDriver", this, 0, NULL, &sec, g_pCoreIdent, NULL);
     1.6  	m_DatabaseType = g_HandleSys.CreateType("IDatabase", this, 0, NULL, NULL, g_pCoreIdent, NULL);
     1.7 -	m_QueryType = g_HandleSys.CreateType("IQuery", this, 0, NULL, NULL, g_pCoreIdent, NULL);
     1.8 +}
     1.9 +
    1.10 +void DBManager::OnSourceModShutdown()
    1.11 +{
    1.12 +	g_HandleSys.RemoveType(m_DatabaseType, g_pCoreIdent);
    1.13 +	g_HandleSys.RemoveType(m_DriverType, g_pCoreIdent);
    1.14 +}
    1.15 +
    1.16 +unsigned int DBManager::GetInterfaceVersion()
    1.17 +{
    1.18 +	return SMINTERFACE_DBI_VERSION;
    1.19 +}
    1.20 +
    1.21 +const char *DBManager::GetInterfaceName()
    1.22 +{
    1.23 +	return SMINTERFACE_DBI_NAME;
    1.24  }
    1.25  
    1.26  void DBManager::OnHandleDestroy(HandleType_t type, void *object)
    1.27 @@ -39,124 +54,24 @@
    1.28  		return;
    1.29  	}
    1.30  
    1.31 -	if (g_HandleSys.TypeCheck(type, m_QueryType))
    1.32 +	if (g_HandleSys.TypeCheck(type, m_DatabaseType))
    1.33  	{
    1.34 -		IQuery *pQuery = (IQuery *)object;
    1.35 -		pQuery->Release();
    1.36 -	} else if (g_HandleSys.TypeCheck(type, m_DatabaseType)) {
    1.37  		IDatabase *pdb = (IDatabase *)object;
    1.38  		pdb->Close();
    1.39  	}
    1.40  }
    1.41  
    1.42 -void DBManager::AddDriver(IDBDriver *pDriver, IdentityToken_t *ident)
    1.43 -{
    1.44 -	if (!pDriver)
    1.45 -	{
    1.46 -		return;
    1.47 -	}
    1.48 -
    1.49 -	if (m_drivers.size() >= HANDLESYS_MAX_SUBTYPES)
    1.50 -	{
    1.51 -		return;
    1.52 -	}
    1.53 -
    1.54 -	db_driver *driver = new db_driver;
    1.55 -
    1.56 -	driver->driver = pDriver;
    1.57 -	driver->ident = ident;
    1.58 -
    1.59 -	HandleSecurity sec;
    1.60 -
    1.61 -	sec.pIdentity = ident;
    1.62 -	sec.pOwner = g_pCoreIdent;
    1.63 -	driver->hDriver = g_HandleSys.CreateHandleEx(m_DriverType, driver, &sec, NULL, NULL);
    1.64 -
    1.65 -	driver->htDatabase = g_HandleSys.CreateType(NULL, this, m_DatabaseType, NULL, NULL, g_pCoreIdent, NULL);
    1.66 -	driver->htQuery = g_HandleSys.CreateType(NULL, this, m_QueryType, NULL, NULL, g_pCoreIdent, NULL);
    1.67 -	
    1.68 -	m_drivers.push_back(driver);
    1.69 -}
    1.70 -
    1.71 -void DBManager::RemoveDriver(IDBDriver *pDriver)
    1.72 -{
    1.73 -	CVector<db_driver *>::iterator iter;
    1.74 -	for (iter = m_drivers.begin();
    1.75 -		 iter != m_drivers.end();
    1.76 -		 iter++)
    1.77 -	{
    1.78 -		if ((*iter)->driver == pDriver)
    1.79 -		{
    1.80 -			db_driver *driver = (*iter);
    1.81 -			HandleSecurity sec;
    1.82 -
    1.83 -			sec.pIdentity = driver->ident;
    1.84 -			sec.pOwner = g_pCoreIdent;
    1.85 -			g_HandleSys.RemoveType(driver->htQuery, driver->ident);
    1.86 -			g_HandleSys.RemoveType(driver->htDatabase, driver->ident);
    1.87 -			g_HandleSys.FreeHandle(driver->hDriver, &sec);
    1.88 -
    1.89 -			delete driver;
    1.90 -			m_drivers.erase(iter);
    1.91 -
    1.92 -			return;
    1.93 -		}
    1.94 -	}
    1.95 -}
    1.96 -
    1.97 -const char *DBManager::GetInterfaceName()
    1.98 -{
    1.99 -	return SMINTERFACE_DBI_NAME;
   1.100 -}
   1.101 -
   1.102 -unsigned int DBManager::GetInterfaceVersion()
   1.103 -{
   1.104 -	return SMINTERFACE_DBI_VERSION;
   1.105 -}
   1.106 -
   1.107 -unsigned int DBManager::GetDriverCount()
   1.108 -{
   1.109 -	return (unsigned int)m_drivers.size();
   1.110 -}
   1.111 -
   1.112 -IDBDriver *DBManager::GetDriver(unsigned int index, IdentityToken_t **pToken)
   1.113 -{
   1.114 -	if (index >= GetDriverCount())
   1.115 -	{
   1.116 -		return NULL;
   1.117 -	}
   1.118 -
   1.119 -	if (pToken)
   1.120 -	{
   1.121 -		*pToken = m_drivers[index]->ident;
   1.122 -	}
   1.123 -
   1.124 -	return m_drivers[index]->driver;
   1.125 -}
   1.126 -
   1.127 -const DatabaseInfo *DBManager::FindDatabaseConf(const char *name)
   1.128 -{
   1.129 -	/* :TODO: implement */
   1.130 -	return NULL;
   1.131 -}
   1.132 -
   1.133 -bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent)
   1.134 +bool DBManager::Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength)
   1.135  {
   1.136  	const DatabaseInfo *pInfo = FindDatabaseConf(name);
   1.137  
   1.138 -	unsigned int count = GetDriverCount();
   1.139 -	for (unsigned int i=0; i<count; i++)
   1.140 +	for (size_t i=0; i<m_drivers.size(); i++)
   1.141  	{
   1.142 -		IDBDriver *driver = GetDriver(i);
   1.143 -		if (strcmp(driver->GetIdentifier(), pInfo->driver) == 0)
   1.144 +		if (strcasecmp(pInfo->driver, m_drivers[i]->GetIdentifier()) == 0)
   1.145  		{
   1.146 -			*pdr = driver;
   1.147 -			if (persistent)
   1.148 -			{
   1.149 -				*pdb = driver->PConnect(pInfo);
   1.150 -			} else {
   1.151 -				*pdb = driver->Connect(pInfo);
   1.152 -			}
   1.153 +			*pdr = m_drivers[i];
   1.154 +			*pdb = m_drivers[i]->Connect(pInfo, persistent, error, maxlength);
   1.155 +			return (*pdb == NULL);
   1.156  		}
   1.157  	}
   1.158  
   1.159 @@ -165,3 +80,81 @@
   1.160  
   1.161  	return false;
   1.162  }
   1.163 +
   1.164 +void DBManager::AddDriver(IDBDriver *pDriver)
   1.165 +{
   1.166 +	 m_drivers.push_back(pDriver);
   1.167 +}
   1.168 +
   1.169 +void DBManager::RemoveDriver(IDBDriver *pDriver)
   1.170 +{
   1.171 +	for (size_t i=0; i<m_drivers.size(); i++)
   1.172 +	{
   1.173 +		if (m_drivers[i] == pDriver)
   1.174 +		{
   1.175 +			m_drivers.erase(m_drivers.iterAt(i));
   1.176 +			return;
   1.177 +		}
   1.178 +	}
   1.179 +}
   1.180 +
   1.181 +Handle_t DBManager::CreateHandle(DBHandleType dtype, void *ptr, IdentityToken_t *pToken)
   1.182 +{
   1.183 +	HandleType_t type = 0;
   1.184 +
   1.185 +	if (dtype == DBHandle_Driver)
   1.186 +	{
   1.187 +		type = m_DriverType;
   1.188 +	} else if (dtype == DBHandle_Database) {
   1.189 +		type = m_DatabaseType;
   1.190 +	} else {
   1.191 +		return BAD_HANDLE;
   1.192 +	}
   1.193 +
   1.194 +	return g_HandleSys.CreateHandle(type, ptr, pToken, g_pCoreIdent, NULL);
   1.195 +}
   1.196 +
   1.197 +HandleError DBManager::ReadHandle(Handle_t hndl, DBHandleType dtype, void **ptr)
   1.198 +{
   1.199 +	HandleType_t type = 0;
   1.200 +
   1.201 +	if (dtype == DBHandle_Driver)
   1.202 +	{
   1.203 +		type = m_DriverType;
   1.204 +	} else if (dtype == DBHandle_Database) {
   1.205 +		type = m_DatabaseType;
   1.206 +	} else {
   1.207 +		return HandleError_Type;
   1.208 +	}
   1.209 +
   1.210 +	HandleSecurity sec(NULL, g_pCoreIdent);
   1.211 +
   1.212 +	return g_HandleSys.ReadHandle(hndl, dtype, &sec, ptr);
   1.213 +}
   1.214 +
   1.215 +HandleError DBManager::ReleaseHandle(Handle_t hndl, DBHandleType type, IdentityToken_t *token)
   1.216 +{
   1.217 +	HandleSecurity sec(token, g_pCoreIdent);
   1.218 +	return g_HandleSys.FreeHandle(hndl, &sec);
   1.219 +}
   1.220 +
   1.221 +unsigned int DBManager::GetDriverCount()
   1.222 +{
   1.223 +	return (unsigned int)m_drivers.size();
   1.224 +}
   1.225 +
   1.226 +IDBDriver *DBManager::GetDriver(unsigned int index)
   1.227 +{
   1.228 +	if (index >= m_drivers.size())
   1.229 +	{
   1.230 +		return NULL;
   1.231 +	}
   1.232 +
   1.233 +	return m_drivers[index];
   1.234 +}
   1.235 +
   1.236 +const DatabaseInfo *DBManager::FindDatabaseConf(const char *name)
   1.237 +{
   1.238 +	/* :TODO: */
   1.239 +	return NULL;
   1.240 +}
     2.1 --- a/core/Database.h	Tue May 29 08:30:13 2007 +0000
     2.2 +++ b/core/Database.h	Tue May 29 08:32:12 2007 +0000
     2.3 @@ -16,46 +16,38 @@
     2.4  #define _INCLUDE_DATABASE_MANAGER_H_
     2.5  
     2.6  #include <IDBDriver.h>
     2.7 -#include <IHandleSys.h>
     2.8  #include "sm_globals.h"
     2.9  #include <sh_vector.h>
    2.10  
    2.11  using namespace SourceHook;
    2.12  
    2.13 -struct db_driver
    2.14 -{
    2.15 -	IDBDriver *driver;
    2.16 -	IdentityToken_t *ident;
    2.17 -	HandleType_t htDatabase;
    2.18 -	HandleType_t htQuery;
    2.19 -	Handle_t hDriver;
    2.20 -};
    2.21 -
    2.22  class DBManager : 
    2.23  	public IDBManager,
    2.24  	public SMGlobalClass,
    2.25  	public IHandleTypeDispatch
    2.26  {
    2.27 +public:
    2.28  	const char *GetInterfaceName();
    2.29  	unsigned int GetInterfaceVersion();
    2.30  public: //SMGlobalClass
    2.31  	void OnSourceModAllInitialized();
    2.32 +	void OnSourceModShutdown();
    2.33  public: //IHandleTypeDispatch
    2.34  	void OnHandleDestroy(HandleType_t type, void *object);
    2.35  public: //IDBManager
    2.36 -	void AddDriver(IDBDriver *pDriver, IdentityToken_t *ident);
    2.37 +	void AddDriver(IDBDriver *pDrivera);
    2.38  	void RemoveDriver(IDBDriver *pDriver);
    2.39  	const DatabaseInfo *FindDatabaseConf(const char *name);
    2.40 -	bool Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent);
    2.41 +	bool Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent, char *error, size_t maxlength);
    2.42  	unsigned int GetDriverCount();
    2.43 -	IDBDriver *GetDriver(unsigned int index, IdentityToken_t **pToken=NULL);
    2.44 -public:
    2.45 -	db_driver *GetDriverInfo(unsigned int index);
    2.46 +	IDBDriver *GetDriver(unsigned int index);
    2.47 +	Handle_t CreateHandle(DBHandleType type, void *ptr, IdentityToken_t *pToken);
    2.48 +	HandleError ReadHandle(Handle_t hndl, DBHandleType type, void **ptr);
    2.49 +	HandleError ReleaseHandle(Handle_t hndl, DBHandleType type, IdentityToken_t *token);
    2.50  private:
    2.51 -	CVector<db_driver *> m_drivers;
    2.52 +	CVector<IDBDriver *> m_drivers;
    2.53  	HandleType_t m_DriverType;
    2.54  	HandleType_t m_DatabaseType;
    2.55 -	HandleType_t m_QueryType;
    2.56  };
    2.57  
    2.58  extern DBManager g_DBMan;
     3.1 --- a/public/IDBDriver.h	Tue May 29 08:30:13 2007 +0000
     3.2 +++ b/public/IDBDriver.h	Tue May 29 08:32:12 2007 +0000
     3.3 @@ -20,6 +20,7 @@
     3.4  #define _INCLUDE_SOURCEMOD_INTERFACE_DBDRIVER_H_
     3.5  
     3.6  #include <IShareSys.h>
     3.7 +#include <IHandleSys.h>
     3.8  #include <string.h>
     3.9  
    3.10  #define SMINTERFACE_DBI_NAME		"IDBI"
    3.11 @@ -39,7 +40,26 @@
    3.12  	};
    3.13  
    3.14  	/**
    3.15 +	 * @brief Describes a primitive database type.
    3.16 +	 */
    3.17 +	enum DBType
    3.18 +	{
    3.19 +		DBType_Unknown = 0,		/**< Type could not be inferred */
    3.20 +		DBType_String,			/**< NULL-terminated string (variable length) */
    3.21 +		DBType_Blob,			/**< Raw binary data (variable length) */
    3.22 +		DBType_Integer,			/**< 4-byte signed integer */
    3.23 +		DBType_Float,			/**< 4-byte floating point  */
    3.24 +	};
    3.25 +
    3.26 +	/**
    3.27  	 * @brief Represents a one database result row.
    3.28 +	 *
    3.29 +	 * Note that type mismatches will only occur when type safety is being
    3.30 +	 * enforced.  So far this is only the case for prepared statements in 
    3.31 +	 * MySQL and SQLite.
    3.32 +	 *
    3.33 +	 * Also, it is worth noting that retrieving as raw data will never cause a
    3.34 +	 * type mismatch.
    3.35  	 */
    3.36  	class IResultRow
    3.37  	{
    3.38 @@ -47,14 +67,33 @@
    3.39  		/**
    3.40  		 * @brief Retrieves a database field result as a string.
    3.41  		 *
    3.42 -		 * For NULL values, the resulting string pointer will be non-NULL,
    3.43 -		 * but empty.
    3.44 +		 * For NULL values, the resulting string pointer will be non-NULL but 
    3.45 +		 * empty.  The pointer returned will become invalid after  advancing to
    3.46 +		 * the next row.
    3.47  		 *
    3.48  		 * @param columnId		Column to use, starting from 0.
    3.49  		 * @param pString		Pointer to store a pointer to the string.
    3.50 +		 * @param length		Optional pointer to store the string length.
    3.51  		 * @return				A DBResult return code.
    3.52  		 */
    3.53 -		virtual DBResult GetString(unsigned int columnId, const char **pString) =0;
    3.54 +		virtual DBResult GetString(unsigned int columnId, const char **pString, size_t *length) =0;
    3.55 +
    3.56 +		/**
    3.57 +		 * @brief Retrieves a database field result as a string, using a 
    3.58 +		 * user-supplied buffer.  If the field is NULL, an empty string
    3.59 +		 * will be copied.
    3.60 +		 *
    3.61 +		 * @param columnId		Column to use, starting from 0.
    3.62 +		 * @param buffer		Buffer to store string in.
    3.63 +		 * @param maxlength		Maximum length of the buffer.
    3.64 +		 * @param written		Optional pointer to store the number of bytes 
    3.65 +		 *						written, excluding the null terminator.
    3.66 +		 * @return				A DBResult return code.
    3.67 +		 */
    3.68 +		virtual DBResult CopyString(unsigned int columnId, 
    3.69 +									char *buffer, 
    3.70 +									size_t maxlength, 
    3.71 +									size_t *written) =0;
    3.72  		
    3.73  		/**
    3.74  		 * @brief Retrieves a database field result as a float.
    3.75 @@ -82,19 +121,51 @@
    3.76  		 * @brief Returns whether or not a field is NULL.
    3.77  		 *
    3.78  		 * @param columnId		Column to use, starting from 0.
    3.79 -		 * @return				A DBResult return code.
    3.80 +		 * @return				True if field is NULL, false otherwise.
    3.81  		 */
    3.82 -		virtual DBResult CheckField(unsigned int columnId) =0;
    3.83 +		virtual bool IsNull(unsigned int columnId) =0;
    3.84  
    3.85  		/**
    3.86 -		 * @brief Retrieves field data as a raw bitstream.
    3.87 +		 * @brief Returns the size of a field (text/raw/blob) in bytes.
    3.88 +		 * For strings, this returned size will not include the null
    3.89 +		 * terminator.
    3.90 +		 * 
    3.91 +		 * When used on fields that are not of variable length,
    3.92 +		 * the size returned will be the number of bytes required
    3.93 +		 * to store the internal data.  Note that the data size 
    3.94 +		 * will correspond to the ACTUAL data type, not the 
    3.95 +		 * COLUMN type.
    3.96  		 *
    3.97  		 * @param columnId		Column to use, starting from 0.
    3.98 -		 * @param pData			Pointer to store the raw bit stream.
    3.99 +		 * @return				Number of bytes required to store
   3.100 +		 *						the data, or 0 on failure.
   3.101 +		 */
   3.102 +		virtual size_t GetDataSize(unsigned int columnId) =0;
   3.103 +
   3.104 +		/**
   3.105 +		 * @brief Retrieves field data as a raw bitstream.  The pointer returned
   3.106 +		 * will become invalid after advancing to the next row.
   3.107 +		 *
   3.108 +		 * @param columnId		Column to use, starting from 0.
   3.109 +		 * @param pData			Pointer to store the raw bit stream.  If the 
   3.110 +		 *						data is NULL, a NULL pointer will be returned.
   3.111  		 * @param length		Pointer to store the data length.
   3.112  		 * @return				A DBResult return code.
   3.113  		 */
   3.114 -		virtual DBResult GetRaw(unsigned int columnId, void **pData, size_t *length) =0;
   3.115 +		virtual DBResult GetBlob(unsigned int columnId, const void **pData, size_t *length) =0;
   3.116 +
   3.117 +		/**
   3.118 +		 * @brief Copies field data as a raw bitstream.
   3.119 +		 *
   3.120 +		 * @param columnId		Column to use, starting from 0.
   3.121 +		 * @param buffer		Pointer to copy the data to.  If the data is
   3.122 +		 *						NULL, no data will be copied.
   3.123 +		 * @param maxlength		Maximum length of the buffer.
   3.124 +		 * @param written		Optional pointer to store the number of bytes 
   3.125 +		 *						written.
   3.126 +		 * @return				A DBResult return code.
   3.127 +		 */
   3.128 +		virtual DBResult CopyBlob(unsigned int columnId, void *buffer, size_t maxlength, size_t *written) =0;
   3.129  	};
   3.130  
   3.131  	/**
   3.132 @@ -123,7 +194,7 @@
   3.133  		 * @param columnId		Column to use, starting from 0.
   3.134  		 * @return				Pointer to column name, or NULL if not found.
   3.135  		 */
   3.136 -		virtual const char *ColNumToName(unsigned int columnId) =0;
   3.137 +		virtual const char *FieldNumToName(unsigned int columnId) =0;
   3.138  
   3.139  		/**
   3.140  		 * @brief Converts a column name to a column id.
   3.141 @@ -134,7 +205,7 @@
   3.142  		 *						undefined.
   3.143  		 * @return				True on success, false if not found.
   3.144  		 */
   3.145 -		virtual bool ColNumToName(const char *name, unsigned int *columnId) =0;
   3.146 +		virtual bool FieldNameToNum(const char *name, unsigned int *columnId) =0;
   3.147  
   3.148  		/**
   3.149  		 * @brief Returns if there is still data in the result set.
   3.150 @@ -142,7 +213,7 @@
   3.151  		 * @return				False if there is more data to be read, 
   3.152  		 *						true, otherwise.
   3.153  		 */
   3.154 -		virtual bool IsFinished() =0;
   3.155 +		virtual bool MoreRows() =0;
   3.156  
   3.157  		/**
   3.158  		 * @brief Returns a pointer to the current row and advances
   3.159 @@ -159,17 +230,150 @@
   3.160  		 * @return				True on success, false otherwise.
   3.161  		 */
   3.162  		virtual bool Rewind() =0;
   3.163 +
   3.164 +		/**
   3.165 +		 * @brief Returns a field's type as it should be interpreted
   3.166 +		 * by the user.
   3.167 +		 *
   3.168 +		 * @param field			Field number (starting from 0).
   3.169 +		 * @return				A DBType value.
   3.170 +		 */
   3.171 +		virtual DBType GetFieldType(unsigned int field) =0;
   3.172 +
   3.173 +		/**
   3.174 +		 * @brief Returns a field's type as it will be interpreted
   3.175 +		 * by the GetDataSize() function.  For example, MySQL
   3.176 +		 * for non-prepared queries will store all results as
   3.177 +		 * strings internally.
   3.178 +		 *
   3.179 +		 * @param field			Field number (starting from 0).
   3.180 +		 * @return				A DBType value.
   3.181 +		 */
   3.182 +		virtual DBType GetFieldDataType(unsigned int field) =0;
   3.183  	};
   3.184  
   3.185 -	class IDatabase;
   3.186 +	class IDBDriver;
   3.187  
   3.188 -	/**
   3.189 -	 * @brief Encapsulates one database query.
   3.190 -	 */
   3.191  	class IQuery
   3.192  	{
   3.193  	public:
   3.194  		/**
   3.195 +		 * @brief Returns a pointer to the current result set, if any.  
   3.196 +		 *
   3.197 +		 * @return				An IResultSet pointer on success,
   3.198 +		 *						NULL if no result set exists.
   3.199 +		 */
   3.200 +		virtual IResultSet *GetResultSet() =0;
   3.201 +
   3.202 +		/**
   3.203 +		 * @brief Advances to the next result set if one exists.  This
   3.204 +		 * is for checking for MORE result sets, and should not be used
   3.205 +		 * on the first result set.
   3.206 +		 *
   3.207 +		 * Multiple results only happen in certain cases, such as CALLing
   3.208 +		 * stored procedure that have a SELECTs, where MySQL will return 
   3.209 +		 * both the CALL status and one or more SELECT result sets.  If
   3.210 +		 * you do not process these results, they will be automatically
   3.211 +		 * processed for you.  However, the behaviour of creating a new
   3.212 +		 * query from the same connection while results are left 
   3.213 +		 * unprocessed is undefined, and may result in a dropped 
   3.214 +		 * connection.  Therefore, process all extra results or destroy the
   3.215 +		 * IQuery pointer before starting a new query.
   3.216 +		 *
   3.217 +		 * Again, this only happens in very specific cases, so there is
   3.218 +		 * no need to call this for normal queries.
   3.219 +		 *
   3.220 +		 * After calling this function, GetResultSet() must be called
   3.221 +		 * again to return the result set.  The previous result set
   3.222 +		 * is automatically destroyed and will be unusable.
   3.223 +		 *
   3.224 +		 * @return				True if another result set is
   3.225 +		 *						available, false otherwise.
   3.226 +		 */
   3.227 +		virtual bool FetchMoreResults() =0;
   3.228 +
   3.229 +		/**
   3.230 +		 * @brief Frees resources created by this query.
   3.231 +		 */
   3.232 +		virtual void Destroy() =0;
   3.233 +	};
   3.234 +
   3.235 +	class IPreparedQuery : public IQuery
   3.236 +	{
   3.237 +	public:
   3.238 +		/** 
   3.239 +		 * @brief Binds an integer parameter.
   3.240 +		 *
   3.241 +		 * @param param			Parameter index, starting from 0.
   3.242 +		 * @param num			Number to bind as a value.
   3.243 +		 * @param signd			True to write as signed, false to write as 
   3.244 +		 *						unsigned.
   3.245 +		 * @return				True on success, false otherwise.
   3.246 +		 */
   3.247 +		virtual bool BindParamInt(unsigned int param, int num, bool signd=true) =0;
   3.248 +
   3.249 +		/**
   3.250 +		 * @brief Binds a float parameter.
   3.251 +		 *
   3.252 +		 * @param param			Parameter index, starting from 0.
   3.253 +		 * @param f				Float to bind as a value.
   3.254 +		 * @return				True on success, false otherwise.
   3.255 +		 */
   3.256 +		virtual bool BindParamFloat(unsigned int param, float f) =0;
   3.257 +
   3.258 +		/**
   3.259 +		 * @brief Binds an SQL NULL type as a parameter.
   3.260 +		 *
   3.261 +		 * @param param			Parameter index, starting from 0.
   3.262 +		 * @return				True on success, false otherwise.
   3.263 +		 */
   3.264 +		virtual bool BindParamNull(unsigned int param) =0;
   3.265 +
   3.266 +		/**
   3.267 +		 * @brief Binds a string as a parameter.
   3.268 +		 *
   3.269 +		 * @param param			Parameter index, starting from 0.
   3.270 +		 * @param text			Pointer to a null-terminated string.
   3.271 +		 * @param copy			If true, the pointer is assumed to be
   3.272 +		 *						volatile and a temporary copy may be
   3.273 +		 *						made for safety.
   3.274 +		 * @return				True on success, false otherwise.
   3.275 +		 */
   3.276 +		virtual bool BindParamString(unsigned int param, const char *text, bool copy) =0;
   3.277 +
   3.278 +		/**
   3.279 +		 * @brief Binds a blob of raw data as a parameter.
   3.280 +		 *
   3.281 +		 * @param param			Parameter index, starting from 0.
   3.282 +		 * @param data			Pointer to a blob of memory.
   3.283 +		 * @param length		Number of bytes to copy.
   3.284 +		 * @param copy			If true, the pointer is assumed to be
   3.285 +		 *						volatile and a temporary copy may be
   3.286 +		 *						made for safety.
   3.287 +		 * @return				True on success, false otherwise.
   3.288 +		 */
   3.289 +		virtual bool BindParamBlob(unsigned int param, 
   3.290 +									const void *data, 
   3.291 +									size_t length, 
   3.292 +									bool copy) =0;
   3.293 +
   3.294 +		/**
   3.295 +		 * @brief Executes the query with the currently bound parameters.
   3.296 +
   3.297 +		 * @return				True on success, false otherwise.
   3.298 +		 */
   3.299 +		virtual bool Execute() =0;
   3.300 +
   3.301 +		/**
   3.302 +		 * @brief Returns the last error message from this statement.
   3.303 +		 *
   3.304 +		 * @param errCode		Optional pointer to store the driver-specific
   3.305 +		 *						error code.
   3.306 +		 * @return				Error message string.
   3.307 +		 */
   3.308 +		virtual const char *GetError(int *errCode=NULL) =0;
   3.309 +
   3.310 +		/**
   3.311  		 * @brief Number of rows affected by the last execute.
   3.312  		 *
   3.313  		 * @return				Number of rows affected by the last execute.
   3.314 @@ -177,45 +381,13 @@
   3.315  		virtual unsigned int GetAffectedRows() =0;
   3.316  
   3.317  		/**
   3.318 -		 * @brief Retrieves the last insert ID of this query, if any.
   3.319 +		 * @brief Retrieves the last insert ID on this database connection.
   3.320  		 *
   3.321  		 * @return				Row insertion ID of the last execute, if any.
   3.322  		 */
   3.323  		virtual unsigned int GetInsertID() =0;
   3.324 -
   3.325 -		/**
   3.326 -		 * @brief Returns the full query string.
   3.327 -		 *
   3.328 -		 * @return				String containing the original query.
   3.329 -		 */
   3.330 -		virtual const char *GetQueryString() =0;
   3.331 -
   3.332 -		/**
   3.333 -		 * @brief Returns the result set from the last Execute call.
   3.334 -		 * 
   3.335 -		 * @return				IResultSet from the last Execute call. 
   3.336 -		 *						Pointer will be NULL if there was no previous
   3.337 -		 *						call, the last call failed, or the last call
   3.338 -		 *						had no result set and Execute() was called with
   3.339 -		 *						retEmptySet=false.
   3.340 -		 */
   3.341 -		virtual IResultSet *GetResultSet() =0;
   3.342 -
   3.343 -		/**
   3.344 -		 * @brief Returns the IDatabase object which created this pointer.
   3.345 -		 *
   3.346 -		 * @return				IDatabase object which created this pointer.
   3.347 -		 */
   3.348 -		virtual IDatabase *GetDatabase() =0;
   3.349 -
   3.350 -		/** 
   3.351 -		 * @brief Releases the resources associated with this query.
   3.352 -		 */
   3.353 -		virtual void Release() =0;
   3.354  	};
   3.355  
   3.356 -	class IDBDriver;
   3.357 -
   3.358  	/**
   3.359  	 * @brief Encapsulates a database connection.
   3.360  	 */
   3.361 @@ -224,11 +396,18 @@
   3.362  	public:
   3.363  		/**
   3.364  		 * @brief Disconnects the database and frees its associated memory.
   3.365 -		 * If this pointer was received via IDBDriver::PConnect(), Close()
   3.366 -		 * must be called once for each successful PConnect() call which 
   3.367 -		 * resulted in this pointer.
   3.368 +		 * Note that the actual object will not be freed until all open 
   3.369 +		 * references have been closed.
   3.370 +		 *
   3.371 +		 * It is guaranteed that an IDatabase pointer won't be destroyed until
   3.372 +		 * all open IQuery or IPreparedQuery pointers are closed.
   3.373 +		 *
   3.374 +		 * @param				Only pass true if being called from an 
   3.375 +		 *						IHandleTypeDispatch destructor.
   3.376 +		 * @return				True if object was destroyed, false if 
   3.377 +		 *						references are remaining.
   3.378  		 */
   3.379 -		virtual void Close() =0;
   3.380 +		virtual bool Close(bool fromHndlSys=false) =0;
   3.381  
   3.382  		/**
   3.383  		 * @brief Error code and string returned by the last operation on this
   3.384 @@ -237,18 +416,41 @@
   3.385  		 * @param errorCode		Optional pointer to retrieve an error code.
   3.386  		 * @return				Error string pointer (empty if none).
   3.387  		 */
   3.388 -		virtual const char *GetLastError(int *errorCode=NULL) =0;
   3.389 +		virtual const char *GetError(int *errorCode=NULL) =0;
   3.390 +
   3.391 +		/**
   3.392 +		 * @brief Prepares and executes a query in one step, and discards
   3.393 +		 * any return data.
   3.394 +		 *
   3.395 +		 * @param query			Query string.
   3.396 +		 * @return				True on success, false otherwise.
   3.397 +		 */
   3.398 +		virtual bool DoSimpleQuery(const char *query) =0;
   3.399  
   3.400  		/**
   3.401  		 * @brief Prepares and executes a query in one step, and returns
   3.402 -		 * the resulting IQuery pointer.
   3.403 +		 * the resultant data set.
   3.404 +		 *
   3.405 +		 * Note: If a query contains more than one result set, each
   3.406 +		 * result set must be processed before a new query is started.
   3.407  		 *
   3.408 -		 * @param fmt			String format to parse.
   3.409 -		 * @param ...			Format parameters.
   3.410 -		 * @return				An IQuery pointer which must be freed, or
   3.411 -		 *						NULL if the query failed.
   3.412 +		 * @param query			Query string.
   3.413 +		 * @return				IQuery pointer on success, NULL otherwise.
   3.414  		 */
   3.415 -		virtual IQuery *DoQuery(const char *fmt, ...) =0;
   3.416 +		virtual IQuery *DoQuery(const char *query) =0;
   3.417 +
   3.418 +		/** 
   3.419 +		 * @brief Prepares a query statement for multiple executions and/or
   3.420 +		 * binding marked parameters (? in MySQL/sqLite, $n in PostgreSQL).
   3.421 +		 *
   3.422 +		 * @param query			Query string.
   3.423 +		 * @param error			Error buffer.
   3.424 +		 * @param maxlength		Maximum length of the error buffer.
   3.425 +		 * @param errCode		Optional pointer to store a driver-specific error code.
   3.426 +		 * @return				IPreparedQuery pointer on success, NULL
   3.427 +		 *						otherwise.
   3.428 +		 */
   3.429 +		virtual IPreparedQuery *PrepareQuery(const char *query, char *error, size_t maxlength, int *errCode=NULL) =0;
   3.430  
   3.431  		/**
   3.432  		 * Quotes a string for insertion into a query.
   3.433 @@ -264,11 +466,25 @@
   3.434  		virtual bool QuoteString(const char *str, char buffer[], size_t maxlen, size_t *newSize) =0;
   3.435  
   3.436  		/**
   3.437 -		 * @brief Returns the parent driver.
   3.438 +		 * @brief Number of rows affected by the last execute.
   3.439 +		 *
   3.440 +		 * @return				Number of rows affected by the last execute.
   3.441 +		 */
   3.442 +		virtual unsigned int GetAffectedRows() =0;
   3.443 +
   3.444 +		/**
   3.445 +		 * @brief Retrieves the last insert ID on this database connection.
   3.446  		 *
   3.447 -		 * @return				IDBDriver pointer that created this object.
   3.448 +		 * @return				Row insertion ID of the last execute, if any.
   3.449  		 */
   3.450 -		virtual IDBDriver *GetDriver() =0;
   3.451 +		virtual unsigned int GetInsertID() =0;
   3.452 +
   3.453 +		/**
   3.454 +		 * @brief Returns an IDatabase Handle to this IDatabase.
   3.455 +		 *
   3.456 +		 * @return				Handle_t of type IDatabase.
   3.457 +		 */
   3.458 +		virtual Handle_t GetHandle() =0;
   3.459  	};
   3.460  
   3.461  	/** 
   3.462 @@ -307,35 +523,50 @@
   3.463  		 * @brief Initiates a database connection.
   3.464  		 * 
   3.465  		 * @param info			Database connection info pointer.
   3.466 +		 * @param persistent	If true, a previous persistent connection will
   3.467 +		 *						be re-used if possible.
   3.468 +		 * @param error			Buffer to store error message.
   3.469 +		 * @param maxlength		Maximum size of the error buffer.
   3.470  		 * @return				A new IDatabase pointer, or NULL on failure.
   3.471  		 */
   3.472 -		virtual IDatabase *Connect(const DatabaseInfo *info) =0;
   3.473 -
   3.474 -		/**
   3.475 -		 * @brief Initiates a database connection.  If a connection to the given database
   3.476 -		 * already exists, this will re-use the old connection handle.
   3.477 -		 * 
   3.478 -		 * @param info			Database connection info pointer.
   3.479 -		 * @return				A new IDatabase pointer, or NULL on failure.
   3.480 -		 */
   3.481 -		virtual IDatabase *PConnect(const DatabaseInfo *info) =0;
   3.482 +		virtual IDatabase *Connect(const DatabaseInfo *info, bool persistent, char *error, size_t maxlength) =0;
   3.483  
   3.484  		/**
   3.485  		 * @brief Returns a case insensitive database identifier string.
   3.486 +		 *
   3.487 +		 * @return				String containing an identifier.
   3.488  		 */
   3.489  		virtual const char *GetIdentifier() =0;
   3.490  
   3.491  		/**
   3.492  		 * @brief Returns a case sensitive implementation name.
   3.493 +		 *
   3.494 +		 * @return				String containing an implementation name.
   3.495  		 */
   3.496  		virtual const char *GetProductName() =0;
   3.497  
   3.498  		/**
   3.499 -		 * @brief Returns the last connection error.
   3.500 +		 * @brief Retrieves a Handle_t handle of the IDBDriver type.
   3.501 +		 *
   3.502 +		 * @return				A Handle_t handle.
   3.503 +		 */
   3.504 +		virtual Handle_t GetHandle() =0;
   3.505 +
   3.506 +		/**
   3.507 +		 * @brief Returns the driver's controlling identity.
   3.508  		 *
   3.509 -		 * @param errCode		Optional pointer to store a platform-specific error code.
   3.510 +		 * @return				An IdentityToken_t identity.
   3.511  		 */
   3.512 -		virtual const char *GetLastError(int *errCode=NULL) =0;
   3.513 +		virtual IdentityToken_t *GetIdentity() =0;
   3.514 +	};
   3.515 +
   3.516 +	/**
   3.517 +	 * @brief Database-related Handle types.
   3.518 +	 */
   3.519 +	enum DBHandleType
   3.520 +	{
   3.521 +		DBHandle_Driver = 0,		/**< Driver Handle */
   3.522 +		DBHandle_Database = 1,		/**< Database Handle */
   3.523  	};
   3.524  
   3.525  	/**
   3.526 @@ -352,7 +583,7 @@
   3.527  		 *
   3.528  		 * @param pDriver		Database driver.
   3.529  		 */
   3.530 -		virtual void AddDriver(IDBDriver *pDriver, IdentityToken_t *pToken) =0;
   3.531 +		virtual void AddDriver(IDBDriver *pDriver) =0;
   3.532  
   3.533  		/**
   3.534  		 * @brief Removes a driver from the DBI system.
   3.535 @@ -379,9 +610,16 @@
   3.536  		 *						If connection fails, NULL will be stored.
   3.537  		 * @param persistent	If true, the dbmanager will attempt to PConnect
   3.538  		 *						instead of connect.
   3.539 +		 * @param error			Error buffer to store a driver's error message.
   3.540 +		 * @param maxlength		Maximum length of the error buffer.
   3.541  		 * @return				True on success, false otherwise.
   3.542  		 */
   3.543 -		virtual bool Connect(const char *name, IDBDriver **pdr, IDatabase **pdb, bool persistent) =0;
   3.544 +		virtual bool Connect(const char *name, 
   3.545 +							IDBDriver **pdr, 
   3.546 +							IDatabase **pdb, 
   3.547 +							bool persistent, 
   3.548 +							char *error, 
   3.549 +							size_t maxlength) =0;
   3.550  
   3.551  		/**
   3.552  		 * @brief Returns the number of drivers loaded.
   3.553 @@ -394,10 +632,39 @@
   3.554  		 * @brief Returns a driver by index.
   3.555  		 *
   3.556  		 * @param index			Driver index, starting from 0.
   3.557 -		 * @param pToken		Optional pointer to store the driver's identity token.
   3.558  		 * @return				IDBDriver pointer for the given index.
   3.559  		 */
   3.560 -		virtual IDBDriver *GetDriver(unsigned int index, IdentityToken_t **pToken=NULL) =0;
   3.561 +		virtual IDBDriver *GetDriver(unsigned int index) =0;
   3.562 +
   3.563 +		/**
   3.564 +		 * @brief Creates a Handle_t of the IDBDriver type.
   3.565 +		 *
   3.566 +		 * @param type			A DBHandleType value.
   3.567 +		 * @param ptr			A pointer corrresponding to a DBHandleType object.
   3.568 +		 * @param token			Identity pointer of the owning identity.
   3.569 +		 * @return				A new Handle_t handle, or 0 on failure.
   3.570 +		 */
   3.571 +		virtual Handle_t CreateHandle(DBHandleType type, void *ptr, IdentityToken_t *pToken) =0;
   3.572 +
   3.573 +		/**
   3.574 +		 * @brief Reads an IDBDriver pointer from an IDBDriver handle.
   3.575 +		 *
   3.576 +		 * @param hndl			Handle_t handle to read.
   3.577 +		 * @param type			A DBHandleType value.
   3.578 +		 * @param ptr			Pointer to store the object pointer.
   3.579 +		 * @return				HandleError value.
   3.580 +		 */
   3.581 +		virtual HandleError ReadHandle(Handle_t hndl, DBHandleType type, void **ptr) =0;
   3.582 +
   3.583 +		/**
   3.584 +		 * @brief Releases an IDBDriver handle.
   3.585 +		 *
   3.586 +		 * @param hndl			Handle_t handle to release.
   3.587 +		 * @param type			A DBHandleType value.
   3.588 +		 * @param token			Identity pointer of the owning identity.
   3.589 +		 * @return				HandleError value.
   3.590 +		 */
   3.591 +		virtual HandleError ReleaseHandle(Handle_t hndl, DBHandleType type, IdentityToken_t *token) =0;
   3.592  	};
   3.593  }
   3.594