1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2025-02-21 20:27:13 +01:00

Partial and untested revision of the MySQL module.

This commit is contained in:
Sandu Liviu Catalin 2016-06-28 01:15:31 +03:00
parent fdc73d3ee8
commit 03237f9c15
18 changed files with 1599 additions and 1747 deletions

View File

@ -448,8 +448,8 @@
<Unit filename="../modules/mysql/Connection.hpp" /> <Unit filename="../modules/mysql/Connection.hpp" />
<Unit filename="../modules/mysql/Handle/Connection.cpp" /> <Unit filename="../modules/mysql/Handle/Connection.cpp" />
<Unit filename="../modules/mysql/Handle/Connection.hpp" /> <Unit filename="../modules/mysql/Handle/Connection.hpp" />
<Unit filename="../modules/mysql/Handle/Result.cpp" /> <Unit filename="../modules/mysql/Handle/ResultSet.cpp" />
<Unit filename="../modules/mysql/Handle/Result.hpp" /> <Unit filename="../modules/mysql/Handle/ResultSet.hpp" />
<Unit filename="../modules/mysql/Handle/Statement.cpp" /> <Unit filename="../modules/mysql/Handle/Statement.cpp" />
<Unit filename="../modules/mysql/Handle/Statement.hpp" /> <Unit filename="../modules/mysql/Handle/Statement.hpp" />
<Unit filename="../modules/mysql/Module.cpp" /> <Unit filename="../modules/mysql/Module.cpp" />
@ -461,6 +461,8 @@
<Unit filename="../modules/mysql/Statement.hpp" /> <Unit filename="../modules/mysql/Statement.hpp" />
<Unit filename="../modules/mysql/Transaction.cpp" /> <Unit filename="../modules/mysql/Transaction.cpp" />
<Unit filename="../modules/mysql/Transaction.hpp" /> <Unit filename="../modules/mysql/Transaction.hpp" />
<Unit filename="../modules/mysql/Wrapper/CharsetInfo.cpp" />
<Unit filename="../modules/mysql/Wrapper/CharsetInfo.hpp" />
<Unit filename="../shared/Base/Buffer.cpp" /> <Unit filename="../shared/Base/Buffer.cpp" />
<Unit filename="../shared/Base/Buffer.hpp" /> <Unit filename="../shared/Base/Buffer.hpp" />
<Unit filename="../shared/Base/Module.cpp" /> <Unit filename="../shared/Base/Module.cpp" />

View File

@ -8,8 +8,8 @@
<Project filename="ModXML.cbp" /> <Project filename="ModXML.cbp" />
<Project filename="ModJSON.cbp" /> <Project filename="ModJSON.cbp" />
<Project filename="ModSQLite.cbp" /> <Project filename="ModSQLite.cbp" />
<Project filename="ModMMDB.cbp" />
<Project filename="ModMySQL.cbp" /> <Project filename="ModMySQL.cbp" />
<Project filename="ModMMDB.cbp" />
<Project filename="ModMongoose.cbp" /> <Project filename="ModMongoose.cbp" />
<Project filename="ModSample.cbp" /> <Project filename="ModSample.cbp" />
</Workspace> </Workspace>

View File

@ -202,4 +202,48 @@ Connection Account::Connect() const
return Connection(*this); return Connection(*this);
} }
// ================================================================================================
void Register_Account(Table & sqlns)
{
sqlns.Bind(_SC("Account")
, Class< Account >(sqlns.GetVM(), _SC("SqMySQLAccount"))
// Constructors
.Ctor< const Account & >()
.Ctor< CSStr, CSStr >()
.Ctor< CSStr, CSStr, CSStr >()
.Ctor< CSStr, CSStr, CSStr, CSStr >()
.Ctor< CSStr, CSStr, CSStr, CSStr, SQInteger >()
.Ctor< CSStr, CSStr, CSStr, CSStr, SQInteger, CSStr >()
// Core Meta-methods
.Func(_SC("_cmp"), &Account::Cmp)
.SquirrelFunc(_SC("_typename"), &Account::Typename)
.Func(_SC("_tostring"), &Account::ToString)
// Properties
.Prop(_SC("Port"), &Account::GetPortNum, &Account::SetPortNum)
.Prop(_SC("Host"), &Account::GetHost, &Account::SetHost)
.Prop(_SC("User"), &Account::GetUser, &Account::SetUser)
.Prop(_SC("Pass"), &Account::GetPass, &Account::SetPass)
.Prop(_SC("Socket"), &Account::GetSocket, &Account::SetSocket)
.Prop(_SC("Flags"), &Account::GetFlags, &Account::SetFlags)
.Prop(_SC("SSL_Key"), &Account::GetSSL_Key, &Account::SetSSL_Key)
.Prop(_SC("SSL_Cert"), &Account::GetSSL_Cert, &Account::SetSSL_Cert)
.Prop(_SC("SSL_CA"), &Account::GetSSL_CA, &Account::SetSSL_CA)
.Prop(_SC("SSL_CA_Path"), &Account::GetSSL_CA_Path, &Account::SetSSL_CA_Path)
.Prop(_SC("SSL_Cipher"), &Account::GetSSL_Cipher, &Account::SetSSL_Cipher)
.Prop(_SC("AutoCommit"), &Account::GetAutoCommit, &Account::SetAutoCommit)
.Prop(_SC("Options"), &Account::GetOptionsTable)
.Prop(_SC("OptionsCount"), &Account::OptionsCount)
.Prop(_SC("OptionsEmpty"), &Account::OptionsEmpty)
// Member Methods
.Func(_SC("EnableFlags"), &Account::EnableFlags)
.Func(_SC("DisableFlags"), &Account::DisableFlags)
.Func(_SC("SetSSL"), &Account::SetSSL)
.Func(_SC("GetOption"), &Account::GetOption)
.Func(_SC("SetOption"), &Account::SetOption)
.Func(_SC("RemoveOption"), &Account::RemoveOption)
.Func(_SC("OptionsClear"), &Account::OptionsClear)
.Func(_SC("Connect"), &Account::Connect)
);
}
} // Namespace:: SqMod } // Namespace:: SqMod

View File

@ -27,16 +27,32 @@ namespace SqMod {
* Handle validation. * Handle validation.
*/ */
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) #if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
#define THROW_CURRENT(x, a) x.GetHnd().ThrowCurrent(a, __FILE__, __LINE__) #define SQMOD_THROW_CURRENT(x, a) (x).ThrowCurrent(a, __FILE__, __LINE__)
#define THROW_CURRENT_HND(x, a) x.ThrowCurrent(a, __FILE__, __LINE__) #define SQMOD_VALIDATE(x) (x).Validate(__FILE__, __LINE__)
#define SQMOD_VALIDATE_CREATED(x) (x).ValidateCreated(__FILE__, __LINE__)
#define SQMOD_VALIDATE_PARAM(x, i) (x).ValidateParam((i), __FILE__, __LINE__)
#define SQMOD_VALIDATE_FIELD(x, i) (x).ValidateField((i), __FILE__, __LINE__)
#define SQMOD_GET_VALID(x) (x).GetValid(__FILE__, __LINE__)
#define SQMOD_GET_CREATED(x) (x).GetCreated(__FILE__, __LINE__)
#else #else
#define THROW_CURRENT(x, a) x.GetHnd().ThrowCurrent(a) #define SQMOD_THROW_CURRENT(x, a) (x).ThrowCurrent(a)
#define THROW_CURRENT_HND(x, a) x.ThrowCurrent(a) #define SQMOD_VALIDATE(x) (x).Validate()
#define SQMOD_VALIDATE_CREATED(x) (x).ValidateCreated()
#define SQMOD_VALIDATE_PARAM(x, i) (x).ValidateParam((i))
#define SQMOD_VALIDATE_FIELD(x, i) (x).ValidateField((i))
#define SQMOD_VALIDATE_ROW(x) (x).ValidateRow()
#define SQMOD_GET_VALID(x) (x).GetValid()
#define SQMOD_GET_CREATED(x) (x).GetCreated()
#endif // _DEBUG #endif // _DEBUG
/* ------------------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------------------
* Forward declarations. * Forward declarations.
*/ */
struct ConnHnd;
struct StmtHnd;
struct ResHnd;
// ------------------------------------------------------------------------------------------------
class Account; class Account;
class Column; class Column;
class Connection; class Connection;
@ -44,6 +60,13 @@ class ResultSet;
class Statement; class Statement;
class Transaction; class Transaction;
/* ------------------------------------------------------------------------------------------------
* Common typedefs.
*/
typedef SharedPtr< ConnHnd > ConnRef;
typedef SharedPtr< StmtHnd > StmtRef;
typedef SharedPtr< ResHnd > ResRef;
/* ------------------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------------------
* Replicate the values of a script Date type to a database time type. * Replicate the values of a script Date type to a database time type.
*/ */

View File

@ -1,5 +1,6 @@
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
#include "Connection.hpp" #include "Connection.hpp"
#include "Account.hpp"
#include "Statement.hpp" #include "Statement.hpp"
#include "ResultSet.hpp" #include "ResultSet.hpp"
#include "Transaction.hpp" #include "Transaction.hpp"
@ -19,151 +20,119 @@ SQInteger Connection::Typename(HSQUIRRELVM vm)
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Int32 Connection::Cmp(const Connection & o) const #if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void Connection::Validate(CCStr file, Int32 line) const
{ {
if (m_Handle == o.m_Handle) if (!m_Handle)
{ {
return 0; SqThrowF("Invalid MySQL connection reference =>[%s:%d]", file, line);
}
else if (m_Handle.HndPtr() > o.m_Handle.HndPtr())
{
return 1;
}
else
{
return -1;
} }
} }
#else
void Connection::Validate() const
{
if (!m_Handle)
{
SqThrowF("Invalid MySQL connection reference");
}
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
CSStr Connection::ToString() const #if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void Connection::ValidateCreated(CCStr file, Int32 line) const
{ {
// Do we have a valid handle? if (!m_Handle)
if (m_Handle)
{ {
ToStringF("%s:%s@%s:%u", m_Handle->mUser.c_str(), m_Handle->mPass.c_str(), SqThrowF("Invalid MySQL connection reference =>[%s:%d]", file, line);
m_Handle->mHost.c_str(), m_Handle->mPort);
} }
// Default to an empty string else if (m_Handle->mPtr == nullptr)
return _SC("");
}
// ------------------------------------------------------------------------------------------------
SQInteger Connection::GetErrNo() const
{
// Validate the managed handle
m_Handle.Validate();
// Return the requested information
return static_cast< SQInteger >(mysql_errno(m_Handle));
}
// ------------------------------------------------------------------------------------------------
CSStr Connection::GetErrStr() const
{
// Validate the managed handle
m_Handle.Validate();
// Return the requested information
return mysql_error(m_Handle);
}
// ------------------------------------------------------------------------------------------------
void Connection::SetName(CSStr name)
{
// Validate the managed handle
m_Handle.Validate();
// Attempt to select the database with the given name
if (mysql_select_db(m_Handle, name) != 0)
{ {
THROW_CURRENT(m_Handle, "Cannot select database"); SqThrowF("Invalid MySQL connection =>[%s:%d]", file, line);
}
// Remember the database name
m_Handle->mName.assign(name);
}
// ------------------------------------------------------------------------------------------------
void Connection::SetCharset(CSStr charset)
{
// Validate the managed handle
m_Handle.Validate();
// Attempt to Set the default character set for the managed connection
if (mysql_set_character_set(m_Handle, charset) != 0)
{
THROW_CURRENT(m_Handle, "Cannot apply character set");
}
// Remember the character set
m_Handle->mCharset.assign(charset);
}
// ------------------------------------------------------------------------------------------------
void Connection::SetAutoCommit(bool toggle)
{
// Validate the managed handle
m_Handle.Validate();
// Attempt to toggle auto-commit if necessary
if (m_Handle->mAutoCommit != toggle && mysql_autocommit(m_Handle, toggle) != 0)
{
THROW_CURRENT(m_Handle, "Cannot toggle auto-commit");
}
else
{
m_Handle->mAutoCommit = toggle;
} }
} }
#else
void Connection::ValidateCreated() const
{
if (!m_Handle)
{
SqThrowF("Invalid MySQL connection reference");
}
else if (m_Handle->mPtr == nullptr)
{
SqThrowF("Invalid MySQL connection");
}
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Object Connection::Execute(CSStr query) #if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
const ConnRef & Connection::GetValid(CCStr file, Int32 line) const
{ {
// Validate the managed handle Validate(file, line);
m_Handle.Validate(); return m_Handle;
// Perform the requested operation
return MakeULongObj(m_Handle->Execute(query));
} }
#else
const ConnRef & Connection::GetValid() const
{
Validate();
return m_Handle;
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
const ConnRef & Connection::GetCreated(CCStr file, Int32 line) const
{
ValidateCreated(file, line);
return m_Handle;
}
#else
const ConnRef & Connection::GetCreated() const
{
ValidateCreated();
return m_Handle;
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Object Connection::Insert(CSStr query) Object Connection::Insert(CSStr query)
{ {
// Validate the managed handle
m_Handle.Validate();
// Make sure the specified query is valid // Make sure the specified query is valid
if (!query || *query == '\0') if (!query || *query == '\0')
{ {
STHROWF("Invalid or empty MySQL query"); STHROWF("Invalid or empty MySQL query");
} }
// Attempt to execute the specified query // Attempt to execute the specified query
else if (mysql_real_query(m_Handle, query, std::strlen(query)) != 0) else if (mysql_real_query(SQMOD_GET_CREATED(*this)->mPtr, query, std::strlen(query)) != 0)
{ {
THROW_CURRENT(m_Handle, "Unable to execute query"); SQMOD_THROW_CURRENT(*m_Handle, "Unable to execute MySQL query");
} }
// Return the identifier of the inserted row // Return the identifier of the inserted row
return MakeULongObj(mysql_insert_id(m_Handle)); return MakeULongObj(mysql_insert_id(m_Handle->mPtr));
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
ResultSet Connection::Query(CSStr query) ResultSet Connection::Query(CSStr query)
{ {
// Validate the managed handle
m_Handle.Validate();
// Make sure the specified query is valid // Make sure the specified query is valid
if (!query || *query == '\0') if (!query || *query == '\0')
{ {
STHROWF("Invalid or empty MySQL query"); STHROWF("Invalid or empty MySQL query");
} }
// Attempt to execute the specified query // Attempt to execute the specified query
else if (mysql_real_query(m_Handle, query, std::strlen(query)) != 0) else if (mysql_real_query(SQMOD_GET_CREATED(*this)->mPtr, query, std::strlen(query)) != 0)
{ {
THROW_CURRENT(m_Handle, "Unable to execute query"); SQMOD_THROW_CURRENT(*m_Handle, "Unable to execute MySQL query");
} }
// Return the identifier of the inserted row // Return the identifier of the inserted row
return ResultSet(ResHnd(m_Handle)); return ResultSet(m_Handle);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Statement Connection::GetStatement(CSStr query) Statement Connection::GetStatement(CSStr query)
{ {
// Validate the managed handle return Statement(SQMOD_GET_CREATED(*this), query);
m_Handle.Validate();
// Return the requested information
return Statement(m_Handle, query);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -172,4 +141,50 @@ Transaction Connection::GetTransaction()
return Transaction(); return Transaction();
} }
// ================================================================================================
void Register_Connection(Table & sqlns)
{
sqlns.Bind(_SC("Connection")
, Class< Connection >(sqlns.GetVM(), _SC("SqMySQLConnection"))
// Constructors
.Ctor()
.Ctor< const Account & >()
// Core Meta-methods
.Func(_SC("_cmp"), &Connection::Cmp)
.SquirrelFunc(_SC("_typename"), &Connection::Typename)
.Func(_SC("_tostring"), &Connection::ToString)
// Properties
.Prop(_SC("IsValid"), &Connection::IsValid)
.Prop(_SC("Connected"), &Connection::IsConnected)
.Prop(_SC("References"), &Connection::GetRefCount)
.Prop(_SC("ErrNo"), &Connection::GetErrNo)
.Prop(_SC("ErrStr"), &Connection::GetErrStr)
.Prop(_SC("LastErrNo"), &Connection::GetLastErrNo)
.Prop(_SC("LastErrStr"), &Connection::GetLastErrStr)
.Prop(_SC("Port"), &Connection::GetPortNum)
.Prop(_SC("Host"), &Connection::GetHost)
.Prop(_SC("User"), &Connection::GetUser)
.Prop(_SC("Pass"), &Connection::GetPass)
.Prop(_SC("Name"), &Connection::GetName, &Connection::SetName)
.Prop(_SC("Socket"), &Connection::GetSocket)
.Prop(_SC("Flags"), &Connection::GetFlags)
.Prop(_SC("SSL_Key"), &Connection::GetSSL_Key)
.Prop(_SC("SSL_Cert"), &Connection::GetSSL_Cert)
.Prop(_SC("SSL_CA"), &Connection::GetSSL_CA)
.Prop(_SC("SSL_CA_Path"), &Connection::GetSSL_CA_Path)
.Prop(_SC("SSL_Cipher"), &Connection::GetSSL_Cipher)
.Prop(_SC("Charset"), &Connection::GetCharset, &Connection::SetCharset)
.Prop(_SC("AutoCommit"), &Connection::GetAutoCommit, &Connection::SetAutoCommit)
.Prop(_SC("InTransaction"), &Connection::GetInTransaction)
// Member Methods
.Func(_SC("Disconnect"), &Connection::Disconnect)
.Func(_SC("SelectDb"), &Connection::SetName)
.Func(_SC("Execute"), &Connection::Execute)
.Func(_SC("Insert"), &Connection::Insert)
.Func(_SC("Query"), &Connection::Query)
.Func(_SC("Statement"), &Connection::GetStatement)
.Func(_SC("Transaction"), &Connection::GetTransaction)
);
}
} // Namespace:: SqMod } // Namespace:: SqMod

View File

@ -15,7 +15,45 @@ class Connection
private: private:
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
ConnHnd m_Handle; // Handle to the actual database connection. ConnRef m_Handle; // Reference to the actual database connection.
protected:
/* --------------------------------------------------------------------------------------------
* Validate the managed connection handle and throw an error if invalid.
*/
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void Validate(CCStr file, Int32 line) const;
#else
void Validate() const;
#endif // _DEBUG
/* --------------------------------------------------------------------------------------------
* Validate the managed connection handle and throw an error if invalid.
*/
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void ValidateCreated(CCStr file, Int32 line) const;
#else
void ValidateCreated() const;
#endif // _DEBUG
/* --------------------------------------------------------------------------------------------
* Validate the managed connection handle and throw an error if invalid.
*/
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
const ConnRef & GetValid(CCStr file, Int32 line) const;
#else
const ConnRef & GetValid() const;
#endif // _DEBUG
/* --------------------------------------------------------------------------------------------
* Validate the managed connection handle and throw an error if invalid.
*/
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
const ConnRef & GetCreated(CCStr file, Int32 line) const;
#else
const ConnRef & GetCreated() const;
#endif // _DEBUG
public: public:
@ -32,15 +70,15 @@ public:
* Base constructor. * Base constructor.
*/ */
Connection(const Account & acc) Connection(const Account & acc)
: m_Handle(acc) : m_Handle(new ConnHnd())
{ {
/* ... */ m_Handle->Create(acc);
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Base constructor. * Base constructor.
*/ */
Connection(const ConnHnd & conn) Connection(const ConnRef & conn)
: m_Handle(conn) : m_Handle(conn)
{ {
/* ... */ /* ... */
@ -56,14 +94,6 @@ public:
*/ */
Connection(Connection && o) = default; Connection(Connection && o) = default;
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~Connection()
{
// Let the handle deal with closing the connection if necessary
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Copy assignment operator. * Copy assignment operator.
*/ */
@ -77,18 +107,43 @@ public:
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Used by the script engine to compare two instances of this type. * Used by the script engine to compare two instances of this type.
*/ */
Int32 Cmp(const Connection & o) const; Int32 Cmp(const Connection & o) const
{
if (m_Handle.Get() == o.m_Handle.Get())
{
return 0;
}
else if (m_Handle.Get() > o.m_Handle.Get())
{
return 1;
}
else
{
return -1;
}
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Used by the script engine to convert an instance of this type to a string. * Used by the script engine to convert an instance of this type to a string.
*/ */
CSStr ToString() const; CSStr ToString() const
{
return m_Handle ? mysql_get_host_info(m_Handle->mPtr) : _SC("");
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Used by the script engine to retrieve the name from instances of this type. * Used by the script engine to retrieve the name from instances of this type.
*/ */
static SQInteger Typename(HSQUIRRELVM vm); static SQInteger Typename(HSQUIRRELVM vm);
/* --------------------------------------------------------------------------------------------
* Retrieve the associated connection handle.
*/
const ConnRef & GetHandle() const
{
return m_Handle;
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* See whether the managed handle is valid. * See whether the managed handle is valid.
*/ */
@ -98,80 +153,43 @@ public:
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Validate the managed connection handle and throw exception if it doesn't exist. * See whether the managed connection handle was connected.
*/ */
void Validate() const; bool IsConnected() const
/* --------------------------------------------------------------------------------------------
* Implicit conversion to the managed connection handle.
*/
operator ConnHnd & ()
{ {
return m_Handle; return m_Handle && (m_Handle->mPtr != nullptr);
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Implicit conversion to the managed connection handle. * Return the number of active references to this connection handle.
*/ */
operator const ConnHnd & () const Uint32 GetRefCount() const
{ {
return m_Handle; return m_Handle.Count();
}
/* --------------------------------------------------------------------------------------------
* Retrieve the managed connection handle.
*/
ConnHnd & GetHnd()
{
return m_Handle;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the managed connection handle.
*/
const ConnHnd & GetHnd() const
{
return m_Handle;
}
/* --------------------------------------------------------------------------------------------
* See whether a successful connection was made or not.
*/
bool Connected() const
{
return m_Handle;
}
/* --------------------------------------------------------------------------------------------
* Disconnect from the currently connected database.
*/
void Disconnect()
{
// Validate the managed handle
m_Handle.Validate();
// Perform the requested operation
m_Handle->Disconnect();
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Retrieve the current error number. * Retrieve the current error number.
*/ */
SQInteger GetErrNo() const; SQInteger GetErrNo() const
{
return static_cast< SQInteger >(mysql_errno(SQMOD_GET_CREATED(*this)->mPtr));
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Retrieve the current error message. * Retrieve the current error message.
*/ */
CSStr GetErrStr() const; CSStr GetErrStr() const
{
return mysql_error(SQMOD_GET_CREATED(*this)->mPtr);
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Retrieve the last received error number. * Retrieve the last received error number.
*/ */
SQInteger GetLastErrNo() const SQInteger GetLastErrNo() const
{ {
// Validate the managed handle return static_cast< SQInteger >(SQMOD_GET_VALID(*this)->mErrNo);
m_Handle.Validate();
// Return the requested information
return static_cast< SQInteger >(m_Handle->mErrNo);
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
@ -179,10 +197,7 @@ public:
*/ */
const String & GetLastErrStr() const const String & GetLastErrStr() const
{ {
// Validate the managed handle return SQMOD_GET_VALID(*this)->mErrStr;
m_Handle.Validate();
// Return the requested information
return m_Handle->mErrStr;
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
@ -190,10 +205,7 @@ public:
*/ */
SQInteger GetPortNum() const SQInteger GetPortNum() const
{ {
// Validate the managed handle return static_cast< SQInteger >(SQMOD_GET_VALID(*this)->mPort);
m_Handle.Validate();
// Return the requested information
return static_cast< SQInteger >(m_Handle->mPort);
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
@ -201,10 +213,7 @@ public:
*/ */
const String & GetHost() const const String & GetHost() const
{ {
// Validate the managed handle return SQMOD_GET_VALID(*this)->mHost;
m_Handle.Validate();
// Return the requested information
return m_Handle->mHost;
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
@ -212,10 +221,7 @@ public:
*/ */
const String & GetUser() const const String & GetUser() const
{ {
// Validate the managed handle return SQMOD_GET_VALID(*this)->mUser;
m_Handle.Validate();
// Return the requested information
return m_Handle->mUser;
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
@ -223,10 +229,7 @@ public:
*/ */
const String & GetPass() const const String & GetPass() const
{ {
// Validate the managed handle return SQMOD_GET_VALID(*this)->mPass;
m_Handle.Validate();
// Return the requested information
return m_Handle->mPass;
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
@ -234,26 +237,34 @@ public:
*/ */
const String & GetName() const const String & GetName() const
{ {
// Validate the managed handle return SQMOD_GET_VALID(*this)->mName;
m_Handle.Validate();
// Return the requested information
return m_Handle->mName;
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Modify the selected database name. * Modify the selected database name.
*/ */
void SetName(CSStr name); void SetName(CSStr name)
{
// Validate the specified name
if (!name)
{
STHROWF("Invalid MySQL database name");
}
// Attempt to select the database with the given name
else if (mysql_select_db(SQMOD_GET_CREATED(*this)->mPtr, name) != 0)
{
SQMOD_THROW_CURRENT(*m_Handle, "Cannot select MySQL database");
}
// Remember the database name
m_Handle->mName.assign(name);
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Retrieve the connection socket. * Retrieve the connection socket.
*/ */
const String & GetSocket() const const String & GetSocket() const
{ {
// Validate the managed handle return SQMOD_GET_VALID(*this)->mSocket;
m_Handle.Validate();
// Return the requested information
return m_Handle->mSocket;
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
@ -261,10 +272,7 @@ public:
*/ */
SQInteger GetFlags() const SQInteger GetFlags() const
{ {
// Validate the managed handle return static_cast< SQInteger >(SQMOD_GET_VALID(*this)->mFlags);
m_Handle.Validate();
// Return the requested information
return static_cast< SQInteger >(m_Handle->mFlags);
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
@ -272,10 +280,7 @@ public:
*/ */
const String & GetSSL_Key() const const String & GetSSL_Key() const
{ {
// Validate the managed handle return SQMOD_GET_VALID(*this)->mSSL_Key;
m_Handle.Validate();
// Return the requested information
return m_Handle->mSSL_Key;
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
@ -283,10 +288,7 @@ public:
*/ */
const String & GetSSL_Cert() const const String & GetSSL_Cert() const
{ {
// Validate the managed handle return SQMOD_GET_VALID(*this)->mSSL_Cert;
m_Handle.Validate();
// Return the requested information
return m_Handle->mSSL_Cert;
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
@ -294,10 +296,7 @@ public:
*/ */
const String & GetSSL_CA() const const String & GetSSL_CA() const
{ {
// Validate the managed handle return SQMOD_GET_VALID(*this)->mSSL_CA;
m_Handle.Validate();
// Return the requested information
return m_Handle->mSSL_CA;
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
@ -305,10 +304,7 @@ public:
*/ */
const String & GetSSL_CA_Path() const const String & GetSSL_CA_Path() const
{ {
// Validate the managed handle return SQMOD_GET_VALID(*this)->mSSL_CA_Path;
m_Handle.Validate();
// Return the requested information
return m_Handle->mSSL_CA_Path;
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
@ -316,10 +312,7 @@ public:
*/ */
const String & GetSSL_Cipher() const const String & GetSSL_Cipher() const
{ {
// Validate the managed handle return SQMOD_GET_VALID(*this)->mSSL_Cipher;
m_Handle.Validate();
// Return the requested information
return m_Handle->mSSL_Cipher;
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
@ -327,48 +320,76 @@ public:
*/ */
const String & GetCharset() const const String & GetCharset() const
{ {
// Validate the managed handle return SQMOD_GET_VALID(*this)->mCharset;
m_Handle.Validate();
// Return the requested information
return m_Handle->mCharset;
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Modify the default character set for the managed connection. * Modify the default character set for the managed connection.
*/ */
void SetCharset(CSStr charset); void SetCharset(CSStr charset)
{
// Validate the specified string
if (!charset)
{
STHROWF("Invalid charset string");
}
// Attempt to Set the default character set for the managed connection
else if (mysql_set_character_set(SQMOD_GET_CREATED(*this)->mPtr, charset) != 0)
{
SQMOD_THROW_CURRENT(*m_Handle, "Cannot apply character set");
}
// Remember the character set
m_Handle->mCharset.assign(charset);
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* See whether auto-commit is enabled or not. * See whether auto-commit is enabled or not.
*/ */
bool GetAutoCommit() const bool GetAutoCommit() const
{ {
// Validate the managed handle return SQMOD_GET_VALID((*this))->mAutoCommit;
m_Handle.Validate();
// Return the requested information
return m_Handle->mAutoCommit;
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Set whether auto-commit should be enabled or not. * Set whether auto-commit should be enabled or not.
*/ */
void SetAutoCommit(bool toggle); void SetAutoCommit(bool toggle)
{
// Attempt to toggle auto-commit if necessary
if (SQMOD_GET_CREATED(*this)->mAutoCommit != toggle &&
mysql_autocommit(m_Handle->mPtr, toggle) != 0)
{
SQMOD_THROW_CURRENT(*m_Handle, "Cannot toggle auto-commit");
}
else
{
m_Handle->mAutoCommit = toggle;
}
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* See whether the connection is in the middle of a transaction. * See whether the connection is in the middle of a transaction.
*/ */
bool GetInTransaction() const bool GetInTransaction() const
{ {
// Validate the managed handle return SQMOD_GET_VALID(*this)->mInTransaction;
m_Handle.Validate(); }
// Return the requested information
return m_Handle->mInTransaction; /* --------------------------------------------------------------------------------------------
* Disconnect from the currently connected database.
*/
void Disconnect()
{
SQMOD_GET_CREATED(*this)->Disconnect();
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Execute a query on the server. * Execute a query on the server.
*/ */
Object Execute(CSStr query); Object Execute(CSStr query)
{
return MakeULongObj(SQMOD_GET_CREATED(*this)->Execute(query));
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Execute a query on the server. * Execute a query on the server.

View File

@ -11,79 +11,107 @@
namespace SqMod { namespace SqMod {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConnHnd::Validate() const void ConnHnd::GrabCurrent()
{ {
// Is the handle valid?
if ((m_Hnd == nullptr) || (m_Hnd->mPtr == nullptr))
{
STHROWF("Invalid MySQL connection reference");
}
}
// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void ConnHnd::Handle::ThrowCurrent(CCStr act, CCStr file, Int32 line)
#else
void ConnHnd::Handle::ThrowCurrent(CCStr act)
#endif // _DEBUG
{
// Grab the error number and message
mErrNo = mysql_errno(mPtr); mErrNo = mysql_errno(mPtr);
mErrStr.assign(mysql_error(mPtr)); mErrStr.assign(mysql_error(mPtr));
// Throw the exception with the resulted message
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
throw Sqrat::Exception(FmtStr("%s (%u) : %s =>[%s:%d]", act,
mErrNo, mErrStr.c_str(), file, line));
#else
throw Sqrat::Exception(FmtStr("%s (%u) : %s", act,
mErrNo, mErrStr.c_str()));
#endif // _DEBUG
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
ConnHnd::Handle::Handle(const Account & acc) #if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
: mPtr(mysql_init(NULL)) void ConnHnd::ThrowCurrent(CCStr act, CCStr file, Int32 line)
, mRef(0) {
GrabCurrent();
// Throw the exception with the resulted message
throw Sqrat::Exception(FmtStr("%s (%u) : %s =>[%s:%d]", act,
mErrNo, mErrStr.c_str(), file, line));
}
#else
void ConnHnd::ThrowCurrent(CCStr act)
{
GrabCurrent();
// Throw the exception with the resulted message
throw Sqrat::Exception(FmtStr("%s (%u) : %s", act,
mErrNo, mErrStr.c_str()));
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------
ConnHnd::ConnHnd()
: mPtr(nullptr)
, mErrNo(0) , mErrNo(0)
, mErrStr(_SC("")) , mErrStr(_SC(""))
, mPort(acc.GetPortNum()) , mPort()
, mHost(acc.GetHost()) , mHost()
, mUser(acc.GetUser()) , mUser()
, mPass(acc.GetPass()) , mPass()
, mName(acc.GetName()) , mName()
, mSocket(acc.GetSocket()) , mSocket()
, mFlags(acc.GetFlags()) , mFlags()
, mSSL_Key(acc.GetSSL_Key()) , mSSL_Key()
, mSSL_Cert(acc.GetSSL_Cert()) , mSSL_Cert()
, mSSL_CA(acc.GetSSL_CA()) , mSSL_CA()
, mSSL_CA_Path(acc.GetSSL_CA_Path()) , mSSL_CA_Path()
, mSSL_Cipher(acc.GetSSL_Cipher()) , mSSL_Cipher()
, mCharset() , mCharset()
, mAutoCommit(acc.GetAutoCommit()) , mAutoCommit()
, mInTransaction(false) , mInTransaction(false)
{ {
/* ... */
}
// ------------------------------------------------------------------------------------------------
ConnHnd::~ConnHnd()
{
Disconnect();
}
// ------------------------------------------------------------------------------------------------
void ConnHnd::Create(const Account & acc)
{
// Is this connection already created?
if (mPtr != nullptr)
{
STHROWF("MySQL connection was already created");
}
// Attempt to initialize a connection handle
mPtr = mysql_init(NULL);
// See if a connection handle could be initialized // See if a connection handle could be initialized
if (!mPtr) if (!mPtr)
{ {
THROW_CURRENT_HND((*this), "Cannot create MYSQL object"); STHROWF("Cannot initialize MYSQL connection structure");
} }
// Store all the account information
mPort = acc.GetPortNum();
mHost = acc.GetHost();
mUser = acc.GetUser();
mPass = acc.GetPass();
mName = acc.GetName();
mSocket = acc.GetSocket();
mFlags = acc.GetFlags();
mSSL_Key = acc.GetSSL_Key();
mSSL_Cert = acc.GetSSL_Cert();
mSSL_CA = acc.GetSSL_CA();
mSSL_CA_Path = acc.GetSSL_CA_Path();
mSSL_Cipher = acc.GetSSL_Cipher();
mAutoCommit = acc.GetAutoCommit();
// Attempt to configure SSL if specified // Attempt to configure SSL if specified
else if (!mSSL_Key.empty() && mysql_ssl_set(mPtr, mSSL_Key.c_str(), mSSL_Cert.c_str(), mSSL_CA.c_str(), if (!mSSL_Key.empty() && mysql_ssl_set(mPtr, mSSL_Key.c_str(), mSSL_Cert.c_str(), mSSL_CA.c_str(),
mSSL_CA_Path.c_str(), mSSL_Cipher.c_str()) != 0) mSSL_CA_Path.c_str(), mSSL_Cipher.c_str()) != 0)
{ {
THROW_CURRENT_HND((*this), "Cannot configure SSL"); SQMOD_THROW_CURRENT(*this, "Cannot configure SSL");
} }
// Attempt to connect to the specified server // Attempt to connect to the specified server
else if (!mysql_real_connect(mPtr, mHost.c_str(), mUser.c_str(), mPass.c_str(), else if (!mysql_real_connect(mPtr, mHost.c_str(), mUser.c_str(), mPass.c_str(),
mName.empty() ? nullptr : mName.c_str(), mPort, (mName.empty() ? nullptr : mName.c_str()), mPort,
mSocket.empty() ? nullptr : mSocket.c_str(), mFlags)) (mSocket.empty() ? nullptr : mSocket.c_str()), mFlags))
{ {
THROW_CURRENT_HND((*this), "Cannot connect to database"); SQMOD_THROW_CURRENT(*this, "Cannot connect to database");
} }
// Attempt configure the auto-commit option // Attempt configure the auto-commit option
else if (mysql_autocommit(mPtr, mAutoCommit) != 0) else if (mysql_autocommit(mPtr, mAutoCommit) != 0)
{ {
THROW_CURRENT_HND((*this), "Cannot configure auto-commit"); SQMOD_THROW_CURRENT(*this, "Cannot configure auto-commit");
} }
// Get iterators to the options container // Get iterators to the options container
Account::Options::const_iterator itr = acc.GetOptions().cbegin(); Account::Options::const_iterator itr = acc.GetOptions().cbegin();
@ -99,7 +127,7 @@ ConnHnd::Handle::Handle(const Account & acc)
// Execute the resulted query // Execute the resulted query
if (Execute(sql.c_str(), static_cast< Ulong >(sql.size())) != 1) if (Execute(sql.c_str(), static_cast< Ulong >(sql.size())) != 1)
{ {
THROW_CURRENT_HND((*this), "Unable to apply option"); SQMOD_THROW_CURRENT(*this, "Unable to apply option");
} }
} }
MY_CHARSET_INFO charsetinfo; MY_CHARSET_INFO charsetinfo;
@ -113,13 +141,7 @@ ConnHnd::Handle::Handle(const Account & acc)
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
ConnHnd::Handle::~Handle() void ConnHnd::Disconnect()
{
Disconnect();
}
// ------------------------------------------------------------------------------------------------
void ConnHnd::Handle::Disconnect()
{ {
if (mPtr != nullptr) if (mPtr != nullptr)
{ {
@ -133,7 +155,7 @@ void ConnHnd::Handle::Disconnect()
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Uint64 ConnHnd::Handle::Execute(CSStr query, Ulong size) Uint64 ConnHnd::Execute(CSStr query, Ulong size)
{ {
// Make sure that we are connected // Make sure that we are connected
if (!mPtr) if (!mPtr)
@ -151,10 +173,11 @@ Uint64 ConnHnd::Handle::Execute(CSStr query, Ulong size)
size = std::strlen(query); size = std::strlen(query);
} }
// Attempt to execute the specified query // Attempt to execute the specified query
else if (mysql_query(mPtr, query) != 0) else if (mysql_real_query(mPtr, query, size))
{ {
THROW_CURRENT_HND((*this), "Unable to execute query"); SQMOD_THROW_CURRENT(*this, "Unable to execute query");
} }
// Where the number of affected rows will be stored // Where the number of affected rows will be stored
Uint64 affected = 0UL; Uint64 affected = 0UL;
// Count the number of affected rows by any "upsert" statement // Count the number of affected rows by any "upsert" statement
@ -162,6 +185,7 @@ Uint64 ConnHnd::Handle::Execute(CSStr query, Ulong size)
{ {
// Attempt to retrieve a buffered result set from the executed query // Attempt to retrieve a buffered result set from the executed query
ResType * result = mysql_store_result(mPtr); ResType * result = mysql_store_result(mPtr);
// If we have a result, then this was a SELECT statement and we should not count it // If we have a result, then this was a SELECT statement and we should not count it
// because it returns the number of selected rows and not modified/affected // because it returns the number of selected rows and not modified/affected
if (result) if (result)
@ -177,15 +201,16 @@ Uint64 ConnHnd::Handle::Execute(CSStr query, Ulong size)
} }
else else
{ {
THROW_CURRENT_HND((*this), "Unable to count affected rows"); SQMOD_THROW_CURRENT(*this, "Unable to count affected rows");
} }
// Prepare the next result from the executed query // Prepare the next result from the executed query
// If return code is 0 then we have a result ready to process // If return code is 0 then we have a result ready to process
const Int32 status = mysql_next_result(mPtr); const Int32 status = mysql_next_result(mPtr);
// If return code is higher than 0 then an error occurred // If return code is higher than 0 then an error occurred
if (status > 0) if (status > 0)
{ {
THROW_CURRENT_HND((*this), "Unable to prepare next result"); SQMOD_THROW_CURRENT(*this, "Unable to prepare next result");
} }
// If return code is less than 0 then there are no results left // If return code is less than 0 then there are no results left
else if (status < 0) else if (status < 0)
@ -197,4 +222,4 @@ Uint64 ConnHnd::Handle::Execute(CSStr query, Ulong size)
return affected; return affected;
} }
} // Namespace:: SqMod } // Namespace:: SqMod

View File

@ -8,14 +8,10 @@
namespace SqMod { namespace SqMod {
/* ------------------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------------------
* Manages a reference counted database connection handle. * The structure that holds the data associated with a certain connection.
*/ */
class ConnHnd struct ConnHnd
{ {
// --------------------------------------------------------------------------------------------
friend class Connection;
friend class Statement;
public: public:
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
@ -29,343 +25,79 @@ public:
typedef Type& Reference; // Reference to the managed type. typedef Type& Reference; // Reference to the managed type.
typedef const Type& ConstRef; // Constant reference to the managed type. typedef const Type& ConstRef; // Constant reference to the managed type.
// --------------------------------------------------------------------------------------------
typedef unsigned int Counter; // Reference counter type.
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
typedef MYSQL_RES ResType; // Database result type. typedef MYSQL_RES ResType; // Database result type.
/* --------------------------------------------------------------------------------------------
* Validate the connection handle and throw an error if invalid.
*/
void Validate() const;
protected:
/* --------------------------------------------------------------------------------------------
* The structure that holds the data associated with a certain connection.
*/
struct Handle
{
// ----------------------------------------------------------------------------------------
Pointer mPtr; // The connection handle resource.
Counter mRef; // Reference count to the managed handle.
// ----------------------------------------------------------------------------------------
Uint32 mErrNo; // Last received error string.
String mErrStr; // Last received error message.
// ----------------------------------------------------------------------------------------
Uint16 mPort; // Server port.
String mHost; // Host address.
String mUser; // User name user.
String mPass; // User password.
String mName; // Database name.
String mSocket; // Unix socket.
Ulong mFlags; // Client flags.
// ----------------------------------------------------------------------------------------
String mSSL_Key; // SSL key.
String mSSL_Cert; // SSL certificate.
String mSSL_CA; // SSL certificate authority.
String mSSL_CA_Path; // SSL certificate authority path.
String mSSL_Cipher; // SSL Cipher.
// ----------------------------------------------------------------------------------------
String mCharset; // Default connection character set.
// ----------------------------------------------------------------------------------------
bool mAutoCommit; // Whether autocommit is enabled on this connection.
bool mInTransaction; // Whether the connection is in the middle of a transaction.
/* ----------------------------------------------------------------------------------------
* Base constructor.
*/
Handle(const Account & acc);
/* ----------------------------------------------------------------------------------------
* Destructor.
*/
~Handle();
/* ----------------------------------------------------------------------------------------
* Grab the current error in the connection handle and throw it.
*/
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void ThrowCurrent(CCStr act, CCStr file, Int32 line);
#else
void ThrowCurrent(CCStr act);
#endif // _DEBUG
/* ----------------------------------------------------------------------------------------
* Disconnect the managed connection handle.
*/
void Disconnect();
/* ----------------------------------------------------------------------------------------
* Execute a query on the server.
*/
Uint64 Execute(CSStr query, Ulong size = 0UL);
};
private:
// --------------------------------------------------------------------------------------------
Handle * m_Hnd; // The managed handle instance.
/* --------------------------------------------------------------------------------------------
* Grab a strong reference to a connection handle.
*/
void Grab()
{
if (m_Hnd)
{
++(m_Hnd->mRef);
}
}
/* --------------------------------------------------------------------------------------------
* Drop a strong reference to a connection handle.
*/
void Drop()
{
if (m_Hnd && --(m_Hnd->mRef) == 0)
{
delete m_Hnd; // Let the destructor take care of cleaning up (if necessary)
}
}
/* --------------------------------------------------------------------------------------------
* Base constructor.
*/
ConnHnd(const Account & acc)
: m_Hnd(new Handle(acc))
{
/* ... */
}
public: public:
/* -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
* Default constructor (null). Pointer mPtr; // The connection handle resource.
*/
ConnHnd() // --------------------------------------------------------------------------------------------
: m_Hnd(nullptr) Uint32 mErrNo; // Last received error string.
{ String mErrStr; // Last received error message.
/* ... */
} // --------------------------------------------------------------------------------------------
Uint16 mPort; // Server port.
String mHost; // Host address.
String mUser; // User name user.
String mPass; // User password.
String mName; // Database name.
String mSocket; // Unix socket.
Ulong mFlags; // Client flags.
// --------------------------------------------------------------------------------------------
String mSSL_Key; // SSL key.
String mSSL_Cert; // SSL certificate.
String mSSL_CA; // SSL certificate authority.
String mSSL_CA_Path; // SSL certificate authority path.
String mSSL_Cipher; // SSL Cipher.
// --------------------------------------------------------------------------------------------
String mCharset; // Default connection character set.
// --------------------------------------------------------------------------------------------
bool mAutoCommit; // Whether autocommit is enabled on this connection.
bool mInTransaction; // Whether the connection is in the middle of a transaction.
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Copy constructor. * Default constructor.
*/ */
ConnHnd(const ConnHnd & o) ConnHnd();
: m_Hnd(o.m_Hnd)
{
Grab();
}
/* --------------------------------------------------------------------------------------------
* Move constructor.
*/
ConnHnd(ConnHnd && o)
: m_Hnd(o.m_Hnd)
{
o.m_Hnd = nullptr;
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Destructor. * Destructor.
*/ */
~ConnHnd() ~ConnHnd();
{
Drop();
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Copy assignment operator. * Grab the current error in the connection handle.
*/ */
ConnHnd & operator = (const ConnHnd & o) void GrabCurrent();
{
if (m_Hnd != o.m_Hnd)
{
Drop();
m_Hnd = o.m_Hnd;
Grab();
}
return *this;
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Move assignment operator. * Grab the current error in the connection handle and throw it.
*/ */
ConnHnd & operator = (ConnHnd && o) #if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
{ void ThrowCurrent(CCStr act, CCStr file, Int32 line);
if (m_Hnd != o.m_Hnd) #else
{ void ThrowCurrent(CCStr act);
m_Hnd = o.m_Hnd; #endif // _DEBUG
o.m_Hnd = nullptr;
}
return *this;
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Status assignment operator. * Create the connection handle.
*/ */
ConnHnd & operator = (Uint32 status) void Create(const Account & acc);
{
if (m_Hnd)
{
m_Hnd->mErrNo = status;
}
return *this;
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Perform an equality comparison between two connection handles. * Disconnect the managed connection handle.
*/ */
bool operator == (const ConnHnd & o) const void Disconnect();
{
return (m_Hnd == o.m_Hnd);
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Perform an inequality comparison between two connection handles. * Execute a query on the server.
*/ */
bool operator != (const ConnHnd & o) const Uint64 Execute(CSStr query, Ulong size = 0UL);
{
return (m_Hnd != o.m_Hnd);
}
/* --------------------------------------------------------------------------------------------
* Perform an equality comparison with an integer value status.
*/
bool operator == (Uint32 status) const
{
if (m_Hnd)
{
return (m_Hnd->mErrNo == status);
}
return false;
}
/* --------------------------------------------------------------------------------------------
* Perform an inequality comparison with an integer value status.
*/
bool operator != (Uint32 status) const
{
if (m_Hnd)
{
return (m_Hnd->mErrNo != status);
}
return false;
}
/* --------------------------------------------------------------------------------------------
* Implicit conversion to boolean for use in boolean operations.
*/
operator bool () const
{
return (m_Hnd != nullptr) && (m_Hnd->mPtr != nullptr);
}
/* --------------------------------------------------------------------------------------------
* Implicit conversion to the managed instance.
*/
operator Pointer ()
{
return (m_Hnd != nullptr) ? m_Hnd->mPtr : nullptr;
}
/* --------------------------------------------------------------------------------------------
* Implicit conversion to the managed instance.
*/
operator Pointer () const
{
return (m_Hnd != nullptr) ? m_Hnd->mPtr : nullptr;
}
/* --------------------------------------------------------------------------------------------
* Implicit conversion to the managed instance.
*/
operator Reference ()
{
assert((m_Hnd != nullptr) && (m_Hnd->mPtr != nullptr));
return *(m_Hnd->mPtr);
}
/* --------------------------------------------------------------------------------------------
* Implicit conversion to the managed instance.
*/
operator ConstRef () const
{
assert((m_Hnd != nullptr) && (m_Hnd->mPtr != nullptr));
return *(m_Hnd->mPtr);
}
/* --------------------------------------------------------------------------------------------
* Member operator for dereferencing the managed pointer.
*/
Handle * operator -> () const
{
assert(m_Hnd != nullptr);
return m_Hnd;
}
/* --------------------------------------------------------------------------------------------
* Indirection operator for obtaining a reference of the managed pointer.
*/
Handle & operator * () const
{
assert(m_Hnd != nullptr);
return *m_Hnd;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the raw handle structure pointer.
*/
Handle * HndPtr()
{
return m_Hnd;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the raw handle structure pointer.
*/
Handle * HndPtr() const
{
return m_Hnd;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the number of active references to the managed instance.
*/
Counter Count() const
{
return (m_Hnd != nullptr) ? m_Hnd->mRef : 0;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the handle reference but only if valid.
*/
Handle & GetHnd()
{
// Validate the managed handle
Validate();
// Return the requesed information
return *m_Hnd;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the handle reference but only if valid.
*/
const Handle & GetHnd() const
{
// Validate the managed handle
Validate();
// Return the requesed information
return *m_Hnd;
}
}; };
} // Namespace:: SqMod } // Namespace:: SqMod

View File

@ -1,409 +0,0 @@
#ifndef _SQMYSQL_HANDLE_RESULT_HPP_
#define _SQMYSQL_HANDLE_RESULT_HPP_
// ------------------------------------------------------------------------------------------------
#include "Handle/Statement.hpp"
// ------------------------------------------------------------------------------------------------
#include <Base/Buffer.hpp>
// ------------------------------------------------------------------------------------------------
#include <unordered_map>
// ------------------------------------------------------------------------------------------------
namespace SqMod {
/* ------------------------------------------------------------------------------------------------
* Manages a reference counted result set handle.
*/
class ResHnd
{
// --------------------------------------------------------------------------------------------
friend class Connection;
friend class Statement;
friend class ResultSet;
public:
// --------------------------------------------------------------------------------------------
typedef MYSQL_RES Type; // The managed type.
// --------------------------------------------------------------------------------------------
typedef Type* Pointer; // Pointer to the managed type.
typedef const Type* ConstPtr; // Constant pointer to the managed type.
// --------------------------------------------------------------------------------------------
typedef Type& Reference; // Reference to the managed type.
typedef const Type& ConstRef; // Constant reference to the managed type.
// --------------------------------------------------------------------------------------------
typedef unsigned int Counter; // Reference counter type.
// --------------------------------------------------------------------------------------------
typedef MYSQL_FIELD FieldType; // Database field type.
typedef MYSQL_BIND BindType; // Database bind type.
typedef MYSQL_TIME TimeType; // Database time type.
typedef MYSQL_ROW RowType; // Database row type.
typedef my_bool BoolType; // Database boolean type.
/* --------------------------------------------------------------------------------------------
* Validate the result set handle and throw an error if invalid.
*/
void Validate() const;
/* --------------------------------------------------------------------------------------------
* Validate the result set handle and specified index and throw an error if invalid.
*/
void ValidateIndex(Uint32 idx) const;
protected:
// --------------------------------------------------------------------------------------------
typedef std::unordered_map< String, Uint32 > IndexMap;
/* --------------------------------------------------------------------------------------------
* The structure that holds the data associated with a certain bind point.
*/
struct Bind
{
// ----------------------------------------------------------------------------------------
BoolType mIsNull; // Allows the database to specify if the field is null.
BoolType mError; // Allows the database if errors occured on this field.
Buffer mData; // Buffer to store non fundamental data for the field.
BindType * mBind; // The associated database bind point handle.
TimeType mTime; // Structure used to retrieve time data from database.
// ----------------------------------------------------------------------------------------
union
{
Uint64 mUint64; // Retrieve unsigned integer values from a field.
Int64 mInt64; // Retrieve signed integer values from a field.
Int32 mInt32[2]; // Retrieve 32 bit signed integer values from a field.
Float64 mFloat64; // Retrieve 32 bit floating point values from a field.
Float32 mFloat32[2]; // Retrieve 64 bit floating point values from the field.
};
/* ----------------------------------------------------------------------------------------
* Default constructor.
*/
Bind()
: mIsNull(0), mError(0), mData(), mBind(nullptr), mTime(), mUint64(0)
{
/* ... */
}
/* ----------------------------------------------------------------------------------------
* Copy constructor. (disabled)
*/
Bind(const Bind & o) = delete;
/* ----------------------------------------------------------------------------------------
* Move constructor. (disabled)
*/
Bind(Bind && o) = delete;
/* ----------------------------------------------------------------------------------------
* Copy assignment operator. (disabled)
*/
Bind & operator = (const Bind & o) = delete;
/* ----------------------------------------------------------------------------------------
* Move assignment operator. (disabled)
*/
Bind & operator = (Bind && o) = delete;
/* ----------------------------------------------------------------------------------------
* Retrieve the used buffer.
*/
CStr GetBuffer()
{
return mData ? mData.Data() : reinterpret_cast< CStr >(&mUint64);
}
/* ----------------------------------------------------------------------------------------
* Retrieve the buffer length.
*/
Ulong GetLength() const
{
return mBind == nullptr ? 0 : mBind->buffer_length;
}
/* ----------------------------------------------------------------------------------------
* Configure the output to match the requirements of a certain field.
*/
void SetOutput(const FieldType & field, BindType * bind);
};
/* --------------------------------------------------------------------------------------------
* The structure that holds the data associated with a certain result set handle.
*/
struct Handle
{
// ----------------------------------------------------------------------------------------
Pointer mPtr; // The managed result set handle.
Counter mRef; // Reference count to the managed handle.
// ----------------------------------------------------------------------------------------
Uint32 mFieldCount; // Number of fields in the result set.
Ulong * mLengths; // Data length when the result set came from a connection.
FieldType * mFields; // Fields in the results set.
Bind * mBinds; // Bind wrappers.
BindType * mMyBinds; // Bind points.
RowType mRow; // Row data.
// ----------------------------------------------------------------------------------------
StmtHnd mStatement; // Associated statement.
IndexMap mIndexes; // Field names and their associated index.
/* ----------------------------------------------------------------------------------------
* Connection constructor.
*/
Handle(const ConnHnd & conn);
/* ----------------------------------------------------------------------------------------
* Statement constructor.
*/
Handle(const StmtHnd & stmt);
/* ----------------------------------------------------------------------------------------
* Destructor.
*/
~Handle();
};
private:
// --------------------------------------------------------------------------------------------
Handle * m_Hnd; // The managed handle instance.
/* --------------------------------------------------------------------------------------------
* Grab a strong reference to a result set handle.
*/
void Grab()
{
if (m_Hnd)
{
++(m_Hnd->mRef);
}
}
/* --------------------------------------------------------------------------------------------
* Drop a strong reference to a result set handle.
*/
void Drop()
{
if (m_Hnd && --(m_Hnd->mRef) == 0)
{
delete m_Hnd; // Let the destructor take care of cleaning up (if necessary)
}
}
/* --------------------------------------------------------------------------------------------
* Connection constructor.
*/
ResHnd(const ConnHnd & conn)
: m_Hnd(conn ? new Handle(conn) : nullptr)
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Connection constructor.
*/
ResHnd(const StmtHnd & stmt)
: m_Hnd(stmt ? new Handle(stmt) : nullptr)
{
/* ... */
}
public:
/* --------------------------------------------------------------------------------------------
* Default constructor (null).
*/
ResHnd()
: m_Hnd(nullptr)
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Copy constructor.
*/
ResHnd(const ResHnd & o)
: m_Hnd(o.m_Hnd)
{
Grab();
}
/* --------------------------------------------------------------------------------------------
* Move constructor.
*/
ResHnd(ResHnd && o)
: m_Hnd(o.m_Hnd)
{
o.m_Hnd = nullptr;
}
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~ResHnd()
{
Drop();
}
/* --------------------------------------------------------------------------------------------
* Copy assignment operator.
*/
ResHnd & operator = (const ResHnd & o)
{
if (m_Hnd != o.m_Hnd)
{
Drop();
m_Hnd = o.m_Hnd;
Grab();
}
return *this;
}
/* --------------------------------------------------------------------------------------------
* Move assignment operator.
*/
ResHnd & operator = (ResHnd && o)
{
if (m_Hnd != o.m_Hnd)
{
m_Hnd = o.m_Hnd;
o.m_Hnd = nullptr;
}
return *this;
}
/* --------------------------------------------------------------------------------------------
* Perform an equality comparison between two result set handles.
*/
bool operator == (const ResHnd & o) const
{
return (m_Hnd == o.m_Hnd);
}
/* --------------------------------------------------------------------------------------------
* Perform an inequality comparison between two result set handles.
*/
bool operator != (const ResHnd & o) const
{
return (m_Hnd != o.m_Hnd);
}
/* --------------------------------------------------------------------------------------------
* Implicit conversion to boolean for use in boolean operations.
*/
operator bool () const
{
return (m_Hnd != nullptr) && (m_Hnd->mPtr != nullptr);
}
/* --------------------------------------------------------------------------------------------
* Implicit conversion to the managed instance.
*/
operator Pointer ()
{
return (m_Hnd != nullptr) ? m_Hnd->mPtr : nullptr;
}
/* --------------------------------------------------------------------------------------------
* Implicit conversion to the managed instance.
*/
operator Pointer () const
{
return (m_Hnd != nullptr) ? m_Hnd->mPtr : nullptr;
}
/* --------------------------------------------------------------------------------------------
* Implicit conversion to the managed instance.
*/
operator Reference ()
{
assert((m_Hnd != nullptr) && (m_Hnd->mPtr != nullptr));
return *(m_Hnd->mPtr);
}
/* --------------------------------------------------------------------------------------------
* Implicit conversion to the managed instance.
*/
operator ConstRef () const
{
assert((m_Hnd != nullptr) && (m_Hnd->mPtr != nullptr));
return *(m_Hnd->mPtr);
}
/* --------------------------------------------------------------------------------------------
* Member operator for dereferencing the managed pointer.
*/
Handle * operator -> () const
{
assert(m_Hnd != nullptr);
return m_Hnd;
}
/* --------------------------------------------------------------------------------------------
* Indirection operator for obtaining a reference of the managed pointer.
*/
Handle & operator * () const
{
assert(m_Hnd != nullptr);
return *m_Hnd;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the raw handle structure pointer.
*/
Handle * HndPtr()
{
return m_Hnd;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the raw handle structure pointer.
*/
Handle * HndPtr() const
{
return m_Hnd;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the number of active references to the managed instance.
*/
Counter Count() const
{
return (m_Hnd != nullptr) ? m_Hnd->mRef : 0;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the handle reference but only if valid.
*/
Handle & GetHnd()
{
// Validate the managed handle
Validate();
// Return the requesed information
return *m_Hnd;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the handle reference but only if valid.
*/
const Handle & GetHnd() const
{
// Validate the managed handle
Validate();
// Return the requesed information
return *m_Hnd;
}
};
} // Namespace:: SqMod
#endif // _SQMYSQL_HANDLE_RESULT_HPP_

View File

@ -1,5 +1,5 @@
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
#include "Handle/Result.hpp" #include "Handle/ResultSet.hpp"
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
#include <cstdio> #include <cstdio>
@ -10,31 +10,7 @@
namespace SqMod { namespace SqMod {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ResHnd::Validate() const void ResBind::SetOutput(const FieldType & field, BindType * bind)
{
// Is the handle valid?
if ((m_Hnd == nullptr) || (m_Hnd->mPtr == nullptr))
{
STHROWF("Invalid MySQL query result reference");
}
}
// ------------------------------------------------------------------------------------------------
void ResHnd::ValidateIndex(Uint32 idx) const
{
// Is the handle valid?
if ((m_Hnd == nullptr) || (m_Hnd->mPtr == nullptr))
{
STHROWF("Invalid MySQL query result reference");
}
else if (idx >= m_Hnd->mFieldCount)
{
STHROWF("The specified index is out of range: %u >= %u", idx, m_Hnd->mFieldCount);
}
}
// ------------------------------------------------------------------------------------------------
void ResHnd::Bind::SetOutput(const FieldType & field, BindType * bind)
{ {
// Associate the library bind point with our bind wrapper // Associate the library bind point with our bind wrapper
mBind = bind; mBind = bind;
@ -113,26 +89,154 @@ void ResHnd::Bind::SetOutput(const FieldType & field, BindType * bind)
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
ResHnd::Handle::Handle(const ConnHnd & conn) ResHnd::ResHnd()
: mPtr(mysql_store_result(conn)) : mPtr(nullptr)
, mRef(1)
, mFieldCount(0) , mFieldCount(0)
, mLengths(nullptr) , mLengths(nullptr)
, mFields(nullptr) , mFields(nullptr)
, mBinds(nullptr) , mBinds(nullptr)
, mMyBinds(nullptr) , mMyBinds(nullptr)
, mRow(nullptr) , mRow(nullptr)
, mConnection()
, mStatement() , mStatement()
, mIndexes() , mIndexes()
{ {
/* ... */
}
// ------------------------------------------------------------------------------------------------
ResHnd::~ResHnd()
{
// Is there a result-set that we should free?
if (mPtr)
{
mysql_free_result(mPtr);
}
// Are there any bind points that we should free?
if (mMyBinds)
{
delete [] (mMyBinds);
}
// Was this result-set from a statement?
if (mStatement)
{
// Are there any rows pointers we should free?
if (mRow)
{
delete [] (mRow);
}
// Free the result-set in the statement
mysql_stmt_free_result(mStatement->mPtr);
}
// Are there any bind wrappers that we should free?
if (mBinds)
{
delete [] (mBinds);
}
}
// ------------------------------------------------------------------------------------------------
void ResHnd::GrabCurrent()
{
if (mConnection)
{
mConnection->GrabCurrent();
}
else if (mStatement)
{
mStatement->GrabCurrent();
}
}
// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void ResHnd::ThrowCurrent(CCStr act, CCStr file, Int32 line)
{
GrabCurrent();
// Throw the exception with the resulted message
if (mConnection)
{
mConnection->ThrowCurrent(act, file, line);
}
else if (mStatement)
{
mStatement->ThrowCurrent(act, file, line);
}
}
#else
void ResHnd::ThrowCurrent(CCStr act)
{
GrabCurrent();
// Throw the exception with the resulted message
if (mConnection)
{
mConnection->ThrowCurrent(act);
}
else if (mStatement)
{
mStatement->ThrowCurrent(act);
}
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void ResHnd::ValidateField(Uint32 idx, CCStr file, Int32 line) const
{
// Is the handle valid?
if (mPtr == nullptr)
{
STHROWF("Invalid MySQL result-set reference =>[%s:%d]", file, line);
}
else if (idx >= mFieldCount)
{
STHROWF("Field index is out of range: %u >= %lu =>[%s:%d]", idx, mFieldCount, file, line);
}
}
#else
void ResHnd::ValidateField(Uint32 idx) const
{
// Is the handle valid?
if (mPtr == nullptr)
{
STHROWF("Invalid MySQL result-set reference");
}
else if (idx >= mFieldCount)
{
STHROWF("Field index is out of range: %u >= %lu", idx, mFieldCount);
}
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------
void ResHnd::Create(const ConnRef & conn)
{
// Is this result-set already created?
if (mPtr != nullptr)
{
STHROWF("MySQL result-set was already created");
}
// Validate the specified connection handle
else if (!conn)
{
STHROWF("Invalid MySQL connection reference");
}
else if (conn->mPtr == nullptr)
{
STHROWF("Invalid MySQL connection");
}
// Store the connection handle
mConnection = conn;
// Retrieve the complete result-set to the client, if any
mPtr = mysql_store_result(mConnection->mPtr);
// Did this query return any results? // Did this query return any results?
if (!mPtr) if (!mPtr)
{ {
return; // We're done here! return; // We're done here!
} }
// Obtain the number of fields in the result set // Obtain the number of fields in the result-set
mFieldCount = mysql_num_fields(mPtr); mFieldCount = mysql_num_fields(mPtr);
// Obtain an array representing the fields in the result set // Obtain an array representing the fields in the result-set
mFields = mysql_fetch_fields(mPtr); mFields = mysql_fetch_fields(mPtr);
// Associate the field names with their index // Associate the field names with their index
for (Uint32 i = 0; i < mFieldCount; ++i) for (Uint32 i = 0; i < mFieldCount; ++i)
@ -142,47 +246,66 @@ ResHnd::Handle::Handle(const ConnHnd & conn)
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
ResHnd::Handle::Handle(const StmtHnd & stmt) void ResHnd::Create(const StmtRef & stmt)
: mPtr(nullptr)
, mRef(1)
, mFieldCount(0)
, mLengths(nullptr)
, mFields(nullptr)
, mBinds(nullptr)
, mMyBinds(nullptr)
, mRow(nullptr)
, mStatement(stmt)
, mIndexes()
{ {
// Is this result-set already created?
if (mPtr != nullptr)
{
STHROWF("MySQL result-set was already created");
}
// Validate the given statement handle // Validate the given statement handle
mStatement.Validate(); else if (!stmt)
{
STHROWF("Invalid MySQL statement reference");
}
else if (stmt->mPtr == nullptr)
{
STHROWF("Invalid MySQL statement");
}
// Store the statement handle
mStatement = stmt;
// Set the parameter value for the next operation // Set the parameter value for the next operation
int max_length = 1; int max_length = 1;
// Force mysql_stmt_store_result() to update the meta-data MYSQL_FIELD->max_length value // Force mysql_stmt_store_result() to update the meta-data MYSQL_FIELD->max_length value
if (mysql_stmt_attr_set(mStatement, STMT_ATTR_UPDATE_MAX_LENGTH, &max_length) != 0) if (mysql_stmt_attr_set(mStatement->mPtr, STMT_ATTR_UPDATE_MAX_LENGTH, &max_length) != 0)
{ {
THROW_CURRENT(mStatement, "Cannot apply statement attribute"); SQMOD_THROW_CURRENT(*mStatement, "Cannot apply MySQL statement attribute");
} }
// Attempt to buffer the complete result set on the client // Attempt to buffer the complete result-set on the client
if (mysql_stmt_store_result(mStatement)) if (mysql_stmt_store_result(mStatement->mPtr))
{ {
THROW_CURRENT(mStatement, "Cannot buffer result-set"); SQMOD_THROW_CURRENT(*mStatement, "Cannot buffer MySQL result-set");
} }
// Obtain the number of fields in the result set // Obtain the number of fields in the result-set
mFieldCount = mysql_stmt_field_count(mStatement); mFieldCount = mysql_stmt_field_count(mStatement->mPtr);
// Obtain the result set meta-data // Obtain the result-set meta-data
mPtr = mysql_stmt_result_metadata(mStatement); mPtr = mysql_stmt_result_metadata(mStatement->mPtr);
// Obtain an array representing the fields in the result set // Obtain an array representing the fields in the result-set
mFields = mysql_fetch_fields(mPtr); mFields = mysql_fetch_fields(mPtr);
// Are there any fields to allocate // Are there any fields to allocate
if (mFieldCount > 0) if (mFieldCount > 0)
{ {
// Allocate the bind wrappers // Allocate the bind wrappers
mBinds = new Bind[mFieldCount]; mBinds = new ResBind[mFieldCount];
// Validate the allocated structures
if (!mBinds)
{
STHROWF("Unable to allocate MySQL bind point wrappers");
}
// Allocate the bind points // Allocate the bind points
mMyBinds = new BindType[mFieldCount]; mMyBinds = new BindType[mFieldCount];
// Validate the allocated structures
if (!mMyBinds)
{
STHROWF("Unable to allocate MySQL bind point structures");
}
// Allocate the row pointers // Allocate the row pointers
mRow = new CStr[mFieldCount]; mRow = new CStr[mFieldCount];
// Validate the allocated structures
if (!mRow)
{
STHROWF("Unable to allocate MySQL row pointers");
}
// Initialize the bind points to null // Initialize the bind points to null
std::memset(mMyBinds, 0, sizeof(BindType) * mFieldCount); std::memset(mMyBinds, 0, sizeof(BindType) * mFieldCount);
} }
@ -197,45 +320,10 @@ ResHnd::Handle::Handle(const StmtHnd & stmt)
mRow[i] = mBinds[i].GetBuffer(); mRow[i] = mBinds[i].GetBuffer();
} }
// Associate our bind points with the statement for result storage // Associate our bind points with the statement for result storage
if (mFieldCount > 0 && mysql_stmt_bind_result(mStatement, mMyBinds) != 0) if (mFieldCount > 0 && mysql_stmt_bind_result(mStatement->mPtr, mMyBinds) != 0)
{ {
THROW_CURRENT(mStatement, "Cannot bind variables to statement"); SQMOD_THROW_CURRENT(*mStatement, "Cannot bind MySQL variables to statement");
} }
} }
// ------------------------------------------------------------------------------------------------
ResHnd::Handle::~Handle()
{
// Is there a result set that we should free?
if (mPtr)
{
mysql_free_result(mPtr);
}
// Are there any bind points that we should free?
if (mMyBinds)
{
delete [] mMyBinds;
}
// Was this result set from a statement?
if (mStatement)
{
// Are there any rows pointers we should free?
if (mRow)
{
delete [] mRow;
}
// Free the result set in the statement
mysql_stmt_free_result(mStatement);
}
// Are there any bind wrappers that we should free?
if (mBinds)
{
delete [] mBinds;
}
}
// ------------------------------------------------------------------------------------------------
} // Namespace:: SqMod } // Namespace:: SqMod

View File

@ -0,0 +1,209 @@
#ifndef _SQMYSQL_HANDLE_RESULTSET_HPP_
#define _SQMYSQL_HANDLE_RESULTSET_HPP_
// ------------------------------------------------------------------------------------------------
#include "Handle/Statement.hpp"
#include "Base/Buffer.hpp"
// ------------------------------------------------------------------------------------------------
#include <unordered_map>
// ------------------------------------------------------------------------------------------------
namespace SqMod {
/* ------------------------------------------------------------------------------------------------
* The structure that holds the data associated with a certain field.
*/
struct ResBind
{
public:
// --------------------------------------------------------------------------------------------
typedef MYSQL_RES Type; // The managed type.
// --------------------------------------------------------------------------------------------
typedef Type* Pointer; // Pointer to the managed type.
typedef const Type* ConstPtr; // Constant pointer to the managed type.
// --------------------------------------------------------------------------------------------
typedef Type& Reference; // Reference to the managed type.
typedef const Type& ConstRef; // Constant reference to the managed type.
// --------------------------------------------------------------------------------------------
typedef MYSQL_FIELD FieldType; // Database field type.
typedef MYSQL_BIND BindType; // Database bind type.
typedef MYSQL_TIME TimeType; // Database time type.
typedef MYSQL_ROW RowType; // Database row type.
typedef my_bool BoolType; // Database boolean type.
// --------------------------------------------------------------------------------------------
typedef std::unordered_map< String, Uint32 > IndexMap;
public:
// --------------------------------------------------------------------------------------------
BoolType mIsNull; // Allows the database to specify if the field is null.
BoolType mError; // Allows the database if errors occured on this field.
Buffer mData; // Buffer to store non fundamental data for the field.
BindType * mBind; // The associated database bind point handle.
TimeType mTime; // Structure used to retrieve time data from database.
// --------------------------------------------------------------------------------------------
union
{
Uint64 mUint64; // Retrieve unsigned integer values from a field.
Int64 mInt64; // Retrieve signed integer values from a field.
Int32 mInt32[2]; // Retrieve 32 bit signed integer values from a field.
Float64 mFloat64; // Retrieve 32 bit floating point values from a field.
Float32 mFloat32[2]; // Retrieve 64 bit floating point values from the field.
};
public:
/* --------------------------------------------------------------------------------------------
* Default constructor.
*/
ResBind()
: mIsNull(0), mError(0), mData(), mBind(nullptr), mTime(), mUint64(0)
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Copy constructor. (disabled)
*/
ResBind(const ResBind & o) = delete;
/* --------------------------------------------------------------------------------------------
* Move constructor. (disabled)
*/
ResBind(ResBind && o) = delete;
/* --------------------------------------------------------------------------------------------
* Copy assignment operator. (disabled)
*/
ResBind & operator = (const ResBind & o) = delete;
/* --------------------------------------------------------------------------------------------
* Move assignment operator. (disabled)
*/
ResBind & operator = (ResBind && o) = delete;
/* --------------------------------------------------------------------------------------------
* Retrieve the used buffer.
*/
CStr GetBuffer()
{
return mData ? mData.Data() : reinterpret_cast< CStr >(&mUint64);
}
/* --------------------------------------------------------------------------------------------
* Retrieve the buffer length.
*/
Ulong GetLength() const
{
return mBind == nullptr ? 0 : mBind->buffer_length;
}
/* --------------------------------------------------------------------------------------------
* Configure the output to match the requirements of a certain field.
*/
void SetOutput(const FieldType & field, BindType * bind);
};
/* ------------------------------------------------------------------------------------------------
* The structure that holds the data associated with a certain result-set handle.
*/
struct ResHnd
{
public:
// --------------------------------------------------------------------------------------------
typedef MYSQL_RES Type; // The managed type.
// --------------------------------------------------------------------------------------------
typedef Type* Pointer; // Pointer to the managed type.
typedef const Type* ConstPtr; // Constant pointer to the managed type.
// --------------------------------------------------------------------------------------------
typedef Type& Reference; // Reference to the managed type.
typedef const Type& ConstRef; // Constant reference to the managed type.
// --------------------------------------------------------------------------------------------
typedef MYSQL_FIELD FieldType; // Database field type.
typedef MYSQL_BIND BindType; // Database bind type.
typedef MYSQL_TIME TimeType; // Database time type.
typedef MYSQL_ROW RowType; // Database row type.
typedef my_bool BoolType; // Database boolean type.
// --------------------------------------------------------------------------------------------
typedef std::unordered_map< String, Uint32 > IndexMap; // Name to index association of fields.
public:
// --------------------------------------------------------------------------------------------
Pointer mPtr; // The managed result-set handle.
// --------------------------------------------------------------------------------------------
Uint32 mFieldCount; // Number of fields in the result-set.
Ulong * mLengths; // Data length when the result-set came from a connection.
FieldType * mFields; // Fields in the results set.
ResBind * mBinds; // Bind wrappers.
BindType * mMyBinds; // Bind points.
RowType mRow; // Row data.
// --------------------------------------------------------------------------------------------
ConnRef mConnection; // Associated connection.
StmtRef mStatement; // Associated statement.
IndexMap mIndexes; // Field names and their associated index.
public:
/* --------------------------------------------------------------------------------------------
* Default constructor.
*/
ResHnd();
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~ResHnd();
/* --------------------------------------------------------------------------------------------
* Grab the current error in the associated statement or connection handle.
*/
void GrabCurrent();
/* --------------------------------------------------------------------------------------------
* Grab the current error in the associated statement or connection handle and throw it.
*/
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void ThrowCurrent(CCStr act, CCStr file, Int32 line);
#else
void ThrowCurrent(CCStr act);
#endif // _DEBUG
/* --------------------------------------------------------------------------------------------
* Validate the statement handle and field index and throw an error if invalid.
*/
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void ValidateField(Uint32 idx, CCStr file, Int32 line) const;
#else
void ValidateField(Uint32 idx) const;
#endif // _DEBUG
/* --------------------------------------------------------------------------------------------
* Create the result-set from a Connection.
*/
void Create(const ConnRef & conn);
/* --------------------------------------------------------------------------------------------
* Create the result-set from a Statement.
*/
void Create(const StmtRef & stmt);
};
} // Namespace:: SqMod
#endif // _SQMYSQL_HANDLE_RESULTSET_HPP_

View File

@ -10,51 +10,7 @@
namespace SqMod { namespace SqMod {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void StmtHnd::Validate() const void StmtBind::SetInput(enum_field_types type, BindType * bind, CCStr buffer, Ulong length)
{
// Is the handle valid?
if ((m_Hnd == nullptr) || (m_Hnd->mPtr == nullptr))
{
STHROWF("Invalid MySQL statement reference");
}
}
// ------------------------------------------------------------------------------------------------
void StmtHnd::ValidateIndex(Uint32 idx) const
{
// Is the handle valid?
if ((m_Hnd == nullptr) || (m_Hnd->mPtr == nullptr))
{
STHROWF("Invalid MySQL statement reference");
}
else if (idx >= m_Hnd->mParams)
{
STHROWF("Parameter index is out of range: %u >= %lu", idx, m_Hnd->mParams);
}
}
// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void StmtHnd::Handle::ThrowCurrent(CCStr act, CCStr file, Int32 line)
#else
void StmtHnd::Handle::ThrowCurrent(CCStr act)
#endif // _DEBUG
{
// Grab the error number and message
mErrNo = mysql_stmt_errno(mPtr);
mErrStr.assign(mysql_stmt_error(mPtr));
// Throw the exception with the resulted message
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
throw Sqrat::Exception(FmtStr("%s (%u) : %s =>[%s:%d]", act,
mErrNo, mErrStr.c_str(), file, line));
#else
throw Sqrat::Exception(FmtStr("%s (%u) : %s", act,
mErrNo, mErrStr.c_str()));
#endif // _DEBUG
}
// ------------------------------------------------------------------------------------------------
void StmtHnd::Bind::SetInput(enum_field_types type, BindType * bind, CCStr buffer, Ulong length)
{ {
// Associate the library bind point with our bind wrapper // Associate the library bind point with our bind wrapper
mBind = bind; mBind = bind;
@ -138,53 +94,86 @@ void StmtHnd::Bind::SetInput(enum_field_types type, BindType * bind, CCStr buffe
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
StmtHnd::Handle::Handle(const ConnHnd & conn, CSStr query) void StmtHnd::GrabCurrent()
: mPtr(mysql_stmt_init(conn))
, mRef(1)
, mErrNo(0)
, mParams(0)
, mBinds(nullptr)
, mMyBinds(nullptr)
, mConnection(conn)
, mQuery(query ? query : _SC(""))
{ {
// Validate the obtained statement handle mErrNo = mysql_stmt_errno(mPtr);
if (!mPtr) mErrStr.assign(mysql_stmt_error(mPtr));
{
THROW_CURRENT(mConnection, "Cannot initialize statement");
}
// Attempt to prepare the statement
else if (mysql_stmt_prepare(mPtr, mQuery.c_str(), mQuery.size()))
{
THROW_CURRENT_HND((*this), "Cannot prepare statement");
}
// Retrieve the amount of parameters supported by this statement
mParams = mysql_stmt_param_count(mPtr);
// Are there any parameters to allocate?
if (mParams <= 0)
{
return;
}
// Allocate the necessary structures
mBinds = new Bind[mParams];
mMyBinds = new BindType[mParams];
// Reset the allocated structures
std::memset(mBinds, 0, sizeof(Bind) * mParams);
std::memset(mMyBinds, 0, sizeof(BindType) * mParams);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
StmtHnd::Handle::~Handle() #if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void StmtHnd::ThrowCurrent(CCStr act, CCStr file, Int32 line)
{
GrabCurrent();
// Throw the exception with the resulted message
throw Sqrat::Exception(FmtStr("%s (%u) : %s =>[%s:%d]", act,
mErrNo, mErrStr.c_str(), file, line));
}
#else
void StmtHnd::ThrowCurrent(CCStr act)
{
GrabCurrent();
// Throw the exception with the resulted message
throw Sqrat::Exception(FmtStr("%s (%u) : %s", act,
mErrNo, mErrStr.c_str()));
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void StmtHnd::ValidateParam(Uint32 idx, CCStr file, Int32 line) const
{
// Is the handle valid?
if (mPtr == nullptr)
{
STHROWF("Invalid MySQL statement reference =>[%s:%d]", file, line);
}
else if (idx >= mParams)
{
STHROWF("Parameter index is out of range: %u >= %lu =>[%s:%d]", idx, mParams, file, line);
}
}
#else
void StmtHnd::ValidateParam(Uint32 idx) const
{
// Is the handle valid?
if (mPtr == nullptr)
{
STHROWF("Invalid MySQL statement reference");
}
else if (idx >= mParams)
{
STHROWF("Parameter index is out of range: %u >= %lu", idx, mParams);
}
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------
StmtHnd::StmtHnd()
: mPtr(nullptr)
, mErrNo(0)
, mErrStr(_SC(""))
, mParams(0)
, mBinds(nullptr)
, mMyBinds(nullptr)
, mConnection()
, mQuery(_SC(""))
{
}
// ------------------------------------------------------------------------------------------------
StmtHnd::~StmtHnd()
{ {
// Should delete native bindings? // Should delete native bindings?
if (mMyBinds) if (mMyBinds)
{ {
delete [] mMyBinds; delete [] (mMyBinds);
} }
// Should we delete binding wrappers? // Should we delete binding wrappers?
if (mBinds) if (mBinds)
{ {
delete [] mBinds; delete [] (mBinds);
} }
// Should we release any statement? // Should we release any statement?
if (mPtr) if (mPtr)
@ -194,6 +183,67 @@ StmtHnd::Handle::~Handle()
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void StmtHnd::Create(const ConnRef & conn, CSStr query)
{
// Is this statement already created?
if (mPtr != nullptr)
{
STHROWF("MySQL statement was already created");
}
// Validate the specified connection handle
else if (!conn)
{
STHROWF("Invalid MySQL connection reference");
}
else if (conn->mPtr == nullptr)
{
STHROWF("Invalid MySQL connection");
}
// Validate the specified query string
else if (!query || *query == '\0')
{
STHROWF("Invalid or empty MySQL query");
}
// Store the connection handle and query string
mConnection = conn;
mQuery.assign(query);
// Attempt to initialize the statement handle
mPtr = mysql_stmt_init(mConnection->mPtr);
// Validate the obtained statement handle
if (!mPtr)
{
SQMOD_THROW_CURRENT(*mConnection, "Cannot initialize MySQL statement");
}
// Attempt to prepare the statement with the given query
else if (mysql_stmt_prepare(mPtr, mQuery.c_str(), mQuery.size()))
{
SQMOD_THROW_CURRENT(*this, "Cannot prepare MySQL statement");
}
// Retrieve the amount of parameters supported by this statement
mParams = mysql_stmt_param_count(mPtr);
// Are there any parameters to allocate?
if (mParams <= 0)
{
// We're done here!
return;
}
// Allocate the binding wrappers
mBinds = new StmtBind[mParams];
// Validate the allocated memory
if (!mBinds)
{
STHROWF("Unable to allocate MySQL bind point wrappers");
}
// Allocate the binding points
mMyBinds = new BindType[mParams];
// Validate the allocated memory
if (!mMyBinds)
{
STHROWF("Unable to allocate MySQL bind point structures");
}
// Reset the allocated points
std::memset(mMyBinds, 0, sizeof(BindType) * mParams);
}
} // Namespace:: SqMod } // Namespace:: SqMod

View File

@ -3,22 +3,16 @@
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
#include "Handle/Connection.hpp" #include "Handle/Connection.hpp"
#include "Base/Buffer.hpp"
// ------------------------------------------------------------------------------------------------
#include <Base/Buffer.hpp>
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
namespace SqMod { namespace SqMod {
/* ------------------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------------------
* Manages a reference counted statement handle. * The structure that holds the data associated with a certain bind point.
*/ */
class StmtHnd struct StmtBind
{ {
// --------------------------------------------------------------------------------------------
friend class Connection;
friend class Statement;
public: public:
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
@ -33,409 +27,163 @@ public:
typedef const Type& ConstRef; // Constant reference to the managed type. typedef const Type& ConstRef; // Constant reference to the managed type.
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
typedef unsigned int Counter; // Reference counter type. typedef MYSQL_BIND BindType; // Database bind type.
typedef MYSQL_TIME TimeType; // Database time type.
typedef my_bool BoolType; // Database boolean type.
public:
// --------------------------------------------------------------------------------------------
BoolType mIsNull; // Allows the database to specify if the parameter is null.
BoolType mError; // Allows the database if errors occured on this parameter.
Buffer mData; // Buffer to store non fundamental data for the parameter.
BindType * mBind; // The associated database bind point handle.
TimeType mTime; // Structure used to store time data from database.
// --------------------------------------------------------------------------------------------
union
{
Uint64 mUint64; // Store unsigned integer values for the parameter.
Int64 mInt64; // Store signed integer values for the parameter.
Int32 mInt32[2]; // Store 32 bit signed integer values for the parameter.
Float64 mFloat64; // Store 32 bit floating point values for the parameter.
Float32 mFloat32[2]; // Store 64 bit floating point values for the parameter.
};
public:
/* --------------------------------------------------------------------------------------------
* Default constructor.
*/
StmtBind()
: mIsNull(0), mError(0), mData(), mBind(nullptr), mTime(), mUint64(0)
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Copy constructor. (disabled)
*/
StmtBind(const StmtBind & o) = delete;
/* --------------------------------------------------------------------------------------------
* Move constructor. (disabled)
*/
StmtBind(StmtBind && o) = delete;
/* --------------------------------------------------------------------------------------------
* Copy assignment operator. (disabled)
*/
StmtBind & operator = (const StmtBind & o) = delete;
/* --------------------------------------------------------------------------------------------
* Move assignment operator. (disabled)
*/
StmtBind & operator = (StmtBind && o) = delete;
/* --------------------------------------------------------------------------------------------
* Retrieve the used buffer.
*/
CStr GetBuffer()
{
return mData ? mData.Data() : reinterpret_cast< CStr >(&mUint64);
}
/* --------------------------------------------------------------------------------------------
* Retrieve the buffer length.
*/
Ulong GetLength() const
{
return (mBind == nullptr) ? 0 : mBind->buffer_length;
}
/* --------------------------------------------------------------------------------------------
* Configure the input of a certain statement parameter.
*/
void SetInput(enum_field_types type, BindType * bind, CCStr buffer = nullptr, Ulong length = 0);
};
/* ------------------------------------------------------------------------------------------------
* The structure that holds the data associated with a certain statement handle.
*/
struct StmtHnd
{
public:
// --------------------------------------------------------------------------------------------
typedef MYSQL_STMT Type; // The managed type.
// --------------------------------------------------------------------------------------------
typedef Type* Pointer; // Pointer to the managed type.
typedef const Type* ConstPtr; // Constant pointer to the managed type.
// --------------------------------------------------------------------------------------------
typedef Type& Reference; // Reference to the managed type.
typedef const Type& ConstRef; // Constant reference to the managed type.
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
typedef MYSQL_BIND BindType; // Database bind type. typedef MYSQL_BIND BindType; // Database bind type.
typedef MYSQL_TIME TimeType; // Database time type. typedef MYSQL_TIME TimeType; // Database time type.
typedef my_bool BoolType; // Database boolean type. typedef my_bool BoolType; // Database boolean type.
/* --------------------------------------------------------------------------------------------
* Validate the statement handle and throw an error if invalid.
*/
void Validate() const;
/* --------------------------------------------------------------------------------------------
* Validate the statement handle and parameter index and throw an error if invalid.
*/
void ValidateIndex(Uint32 idx) const;
protected:
// --------------------------------------------------------------------------------------------
typedef std::map< String, int > Indexes; // Container used to identify column indexes.
/* --------------------------------------------------------------------------------------------
* The structure that holds the data associated with a certain bind point.
*/
struct Bind
{
// ----------------------------------------------------------------------------------------
BoolType mIsNull; // Allows the database to specify if the parameter is null.
BoolType mError; // Allows the database if errors occured on this parameter.
Buffer mData; // Buffer to store non fundamental data for the parameter.
BindType * mBind; // The associated database bind point handle.
TimeType mTime; // Structure used to store time data from database.
// ----------------------------------------------------------------------------------------
union
{
Uint64 mUint64; // Store unsigned integer values for the parameter.
Int64 mInt64; // Store signed integer values for the parameter.
Int32 mInt32[2]; // Store 32 bit signed integer values for the parameter.
Float64 mFloat64; // Store 32 bit floating point values for the parameter.
Float32 mFloat32[2]; // Store 64 bit floating point values for the parameter.
};
/* ----------------------------------------------------------------------------------------
* Default constructor.
*/
Bind()
: mIsNull(0), mError(0), mData(), mBind(nullptr), mTime(), mUint64(0)
{
/* ... */
}
/* ----------------------------------------------------------------------------------------
* Copy constructor. (disabled)
*/
Bind(const Bind & o) = delete;
/* ----------------------------------------------------------------------------------------
* Move constructor. (disabled)
*/
Bind(Bind && o) = delete;
/* ----------------------------------------------------------------------------------------
* Copy assignment operator. (disabled)
*/
Bind & operator = (const Bind & o) = delete;
/* ----------------------------------------------------------------------------------------
* Move assignment operator. (disabled)
*/
Bind & operator = (Bind && o) = delete;
/* ----------------------------------------------------------------------------------------
* Retrieve the used buffer.
*/
CStr GetBuffer()
{
return mData ? mData.Data() : reinterpret_cast< CStr >(&mUint64);
}
/* ----------------------------------------------------------------------------------------
* Retrieve the buffer length.
*/
Ulong GetLength() const
{
return mBind == nullptr ? 0 : mBind->buffer_length;
}
/* ----------------------------------------------------------------------------------------
* Configure the input of a certain statement parameter.
*/
void SetInput(enum_field_types type, BindType * bind, CCStr buffer = nullptr, Ulong length = 0UL);
};
/* --------------------------------------------------------------------------------------------
* The structure that holds the data associated with a certain statement handle.
*/
struct Handle
{
// ----------------------------------------------------------------------------------------
Pointer mPtr; // The managed statement handle.
Counter mRef; // Reference count to the managed handle.
// ----------------------------------------------------------------------------------------
Uint32 mErrNo; // Last received error string.
String mErrStr; // Last received error message.
// ----------------------------------------------------------------------------------------
Ulong mParams; // Number of parameters in the statement.
Bind * mBinds; // List of parameter binds.
BindType * mMyBinds; // List of parameter binds.
// ----------------------------------------------------------------------------------------
ConnHnd mConnection; // Reference to the associated connection.
String mQuery; // The query string.
/* ----------------------------------------------------------------------------------------
* Base constructor.
*/
Handle(const ConnHnd & conn, CSStr query);
/* ----------------------------------------------------------------------------------------
* Destructor.
*/
~Handle();
/* ----------------------------------------------------------------------------------------
* Grab the current error in the connection handle and throw it.
*/
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void ThrowCurrent(CCStr act, CCStr file, Int32 line);
#else
void ThrowCurrent(CCStr act);
#endif // _DEBUG
/* ----------------------------------------------------------------------------------------
* Create the database statement resource.
*/
void Create(CSStr query);
};
private:
// --------------------------------------------------------------------------------------------
Handle * m_Hnd; // The managed handle instance.
/* --------------------------------------------------------------------------------------------
* Grab a strong reference to a statement handle.
*/
void Grab()
{
if (m_Hnd)
{
++(m_Hnd->mRef);
}
}
/* --------------------------------------------------------------------------------------------
* Drop a strong reference to a statement handle.
*/
void Drop()
{
if (m_Hnd && --(m_Hnd->mRef) == 0)
{
delete m_Hnd; // Let the destructor take care of cleaning up (if necessary)
}
}
/* --------------------------------------------------------------------------------------------
* Base constructor.
*/
StmtHnd(const ConnHnd & db, CSStr query)
: m_Hnd(new Handle(db, query))
{
/* ... */
}
public: public:
/* -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
* Default constructor (null). Pointer mPtr; // The managed statement handle.
*/
StmtHnd() // --------------------------------------------------------------------------------------------
: m_Hnd(nullptr) Uint32 mErrNo; // Last received error string.
{ String mErrStr; // Last received error message.
/* ... */
} // --------------------------------------------------------------------------------------------
Ulong mParams; // Number of parameters in the statement.
StmtBind * mBinds; // List of parameter binds.
BindType * mMyBinds; // List of parameter binds.
// --------------------------------------------------------------------------------------------
ConnRef mConnection; // Reference to the associated connection.
String mQuery; // The query string.
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Copy constructor. * Default constructor.
*/ */
StmtHnd(const StmtHnd & o) StmtHnd();
: m_Hnd(o.m_Hnd)
{
Grab();
}
/* --------------------------------------------------------------------------------------------
* Move constructor.
*/
StmtHnd(StmtHnd && o)
: m_Hnd(o.m_Hnd)
{
o.m_Hnd = nullptr;
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Destructor. * Destructor.
*/ */
~StmtHnd() ~StmtHnd();
{
Drop();
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Copy assignment operator. * Grab the current error in the associated statement handle.
*/ */
StmtHnd & operator = (const StmtHnd & o) void GrabCurrent();
{
if (m_Hnd != o.m_Hnd)
{
Drop();
m_Hnd = o.m_Hnd;
Grab();
}
return *this;
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Move assignment operator. * Grab the current error in the associated statement handle and throw it.
*/ */
StmtHnd & operator = (StmtHnd && o) #if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
{ void ThrowCurrent(CCStr act, CCStr file, Int32 line);
if (m_Hnd != o.m_Hnd) #else
{ void ThrowCurrent(CCStr act);
m_Hnd = o.m_Hnd; #endif // _DEBUG
o.m_Hnd = nullptr;
}
return *this;
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Status assignment operator. * Validate the associated statement handle and parameter index and throw an error if invalid.
*/ */
StmtHnd & operator = (Uint32 status) #if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
{ void ValidateParam(Uint32 idx, CCStr file, Int32 line) const;
if (m_Hnd) #else
{ void ValidateParam(Uint32 idx) const;
m_Hnd->mErrNo = status; #endif // _DEBUG
}
return *this;
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Perform an equality comparison between two statement handles. * Create the actual statement.
*/ */
bool operator == (const StmtHnd & o) const void Create(const ConnRef & conn, CSStr query);
{
return (m_Hnd == o.m_Hnd);
}
/* --------------------------------------------------------------------------------------------
* Perform an inequality comparison between two statement handles.
*/
bool operator != (const StmtHnd & o) const
{
return (m_Hnd != o.m_Hnd);
}
/* --------------------------------------------------------------------------------------------
* Perform an equality comparison with an integer value status.
*/
bool operator == (Uint32 status) const
{
if (m_Hnd)
{
return (m_Hnd->mErrNo == status);
}
return false;
}
/* --------------------------------------------------------------------------------------------
* Perform an inequality comparison with an integer status value.
*/
bool operator != (Uint32 status) const
{
if (m_Hnd)
{
return (m_Hnd->mErrNo != status);
}
return false;
}
/* --------------------------------------------------------------------------------------------
* Implicit conversion to boolean for use in boolean operations.
*/
operator bool () const
{
return (m_Hnd != nullptr) && (m_Hnd->mPtr != nullptr);
}
/* --------------------------------------------------------------------------------------------
* Implicit conversion to the managed instance.
*/
operator Pointer ()
{
return (m_Hnd != nullptr) ? m_Hnd->mPtr : nullptr;
}
/* --------------------------------------------------------------------------------------------
* Implicit conversion to the managed instance.
*/
operator Pointer () const
{
return (m_Hnd != nullptr) ? m_Hnd->mPtr : nullptr;
}
/* --------------------------------------------------------------------------------------------
* Implicit conversion to the managed instance.
*/
operator Reference ()
{
assert((m_Hnd != nullptr) && (m_Hnd->mPtr != nullptr));
return *(m_Hnd->mPtr);
}
/* --------------------------------------------------------------------------------------------
* Implicit conversion to the managed instance.
*/
operator ConstRef () const
{
assert((m_Hnd != nullptr) && (m_Hnd->mPtr != nullptr));
return *(m_Hnd->mPtr);
}
/* --------------------------------------------------------------------------------------------
* Member operator for dereferencing the managed pointer.
*/
Handle * operator -> () const
{
assert(m_Hnd != nullptr);
return m_Hnd;
}
/* --------------------------------------------------------------------------------------------
* Indirection operator for obtaining a reference of the managed pointer.
*/
Handle & operator * () const
{
assert(m_Hnd != nullptr);
return *m_Hnd;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the raw handle structure pointer.
*/
Handle * HndPtr()
{
return m_Hnd;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the raw handle structure pointer.
*/
Handle * HndPtr() const
{
return m_Hnd;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the number of active references to the managed instance.
*/
Counter Count() const
{
return (m_Hnd != nullptr) ? m_Hnd->mRef : 0;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the handle reference but only if valid.
*/
Handle & GetHnd()
{
// Validate the managed handle
Validate();
// Return the requesed information
return *m_Hnd;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the handle reference but only if valid.
*/
const Handle & GetHnd() const
{
// Validate the managed handle
Validate();
// Return the requesed information
return *m_Hnd;
}
}; };
} // Namespace:: SqMod } // Namespace:: SqMod
#endif // _SQMYSQL_HANDLE_STATEMENT_HPP_ #endif // _SQMYSQL_HANDLE_STATEMENT_HPP_

View File

@ -169,6 +169,9 @@ void UnbindCallbacks()
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
extern void Register_Account(Table & sqlns); extern void Register_Account(Table & sqlns);
extern void Register_Connection(Table & sqlns);
extern void Register_ResultSet(Table & sqlns);
extern void Register_Statement(Table & sqlns);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void RegisterAPI(HSQUIRRELVM vm) void RegisterAPI(HSQUIRRELVM vm)
@ -176,6 +179,9 @@ void RegisterAPI(HSQUIRRELVM vm)
Table sqlns(vm); Table sqlns(vm);
Register_Account(sqlns); Register_Account(sqlns);
Register_Connection(sqlns);
Register_ResultSet(sqlns);
Register_Statement(sqlns);
RootTable(vm).Bind(_SC("SqMySQL"), sqlns); RootTable(vm).Bind(_SC("SqMySQL"), sqlns);
} }

View File

@ -13,39 +13,100 @@ SQInteger ResultSet::Typename(HSQUIRRELVM vm)
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Int32 ResultSet::Cmp(const ResultSet & o) const #if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void ResultSet::Validate(CCStr file, Int32 line) const
{ {
if (m_Handle == o.m_Handle) if (!m_Handle)
{ {
return 0; SqThrowF("Invalid MySQL result-set reference =>[%s:%d]", file, line);
}
else if (m_Handle.HndPtr() > o.m_Handle.HndPtr())
{
return 1;
}
else
{
return -1;
} }
} }
#else
void ResultSet::Validate() const
{
if (!m_Handle)
{
SqThrowF("Invalid MySQL result-set reference");
}
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
CSStr ResultSet::ToString() const #if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void ResultSet::ValidateCreated(CCStr file, Int32 line) const
{ {
// Do we have a valid handle? if (!m_Handle)
if (m_Handle)
{ {
ToStrF("%u", m_Handle->mFieldCount); SqThrowF("Invalid MySQL result-set reference =>[%s:%d]", file, line);
}
else if (m_Handle->mPtr == nullptr)
{
SqThrowF("Invalid MySQL result-set =>[%s:%d]", file, line);
} }
// Default to an empty string
return _SC("");
} }
#else
void ResultSet::ValidateCreated() const
{
if (!m_Handle)
{
SqThrowF("Invalid MySQL result-set reference");
}
else if (m_Handle->mPtr == nullptr)
{
SqThrowF("Invalid MySQL result-set");
}
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
const ResRef & ResultSet::GetValid(CCStr file, Int32 line) const
{
Validate(file, line);
return m_Handle;
}
#else
const ResRef & ResultSet::GetValid() const
{
Validate();
return m_Handle;
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
const ResRef & ResultSet::GetCreated(CCStr file, Int32 line) const
{
ValidateCreated(file, line);
return m_Handle;
}
#else
const ResRef & ResultSet::GetCreated() const
{
ValidateCreated();
return m_Handle;
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void ResultSet::ValidateField(Int32 idx, CCStr file, Int32 line) const
{
ValidateCreated(file, line);
m_Handle->ValidateField(idx, file, line);
}
#else
void ResultSet::ValidateField(Int32 idx) const
{
ValidateCreated();
m_Handle->ValidateField(idx);
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
SQInteger ResultSet::GetInt8(Uint32 idx) const SQInteger ResultSet::GetInt8(Uint32 idx) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_FIELD(*this, idx);
m_Handle.ValidateIndex(idx);
// Should we retrieve the value from the bind wrapper? // Should we retrieve the value from the bind wrapper?
if (m_Handle->mStatement) if (m_Handle->mStatement)
{ {
@ -58,8 +119,7 @@ SQInteger ResultSet::GetInt8(Uint32 idx) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
SQInteger ResultSet::GetUint8(Uint32 idx) const SQInteger ResultSet::GetUint8(Uint32 idx) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_FIELD(*this, idx);
m_Handle.ValidateIndex(idx);
// Should we retrieve the value from the bind wrapper? // Should we retrieve the value from the bind wrapper?
if (m_Handle->mStatement) if (m_Handle->mStatement)
{ {
@ -72,8 +132,7 @@ SQInteger ResultSet::GetUint8(Uint32 idx) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
SQInteger ResultSet::GetInt16(Uint32 idx) const SQInteger ResultSet::GetInt16(Uint32 idx) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_FIELD(*this, idx);
m_Handle.ValidateIndex(idx);
// Should we retrieve the value from the bind wrapper? // Should we retrieve the value from the bind wrapper?
if (m_Handle->mStatement) if (m_Handle->mStatement)
{ {
@ -86,8 +145,7 @@ SQInteger ResultSet::GetInt16(Uint32 idx) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
SQInteger ResultSet::GetUint16(Uint32 idx) const SQInteger ResultSet::GetUint16(Uint32 idx) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_FIELD(*this, idx);
m_Handle.ValidateIndex(idx);
// Should we retrieve the value from the bind wrapper? // Should we retrieve the value from the bind wrapper?
if (m_Handle->mStatement) if (m_Handle->mStatement)
{ {
@ -100,8 +158,7 @@ SQInteger ResultSet::GetUint16(Uint32 idx) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
SQInteger ResultSet::GetInt32(Uint32 idx) const SQInteger ResultSet::GetInt32(Uint32 idx) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_FIELD(*this, idx);
m_Handle.ValidateIndex(idx);
// Should we retrieve the value from the bind wrapper? // Should we retrieve the value from the bind wrapper?
if (m_Handle->mStatement) if (m_Handle->mStatement)
{ {
@ -114,8 +171,7 @@ SQInteger ResultSet::GetInt32(Uint32 idx) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
SQInteger ResultSet::GetUint32(Uint32 idx) const SQInteger ResultSet::GetUint32(Uint32 idx) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_FIELD(*this, idx);
m_Handle.ValidateIndex(idx);
// Should we retrieve the value from the bind wrapper? // Should we retrieve the value from the bind wrapper?
if (m_Handle->mStatement) if (m_Handle->mStatement)
{ {
@ -128,8 +184,7 @@ SQInteger ResultSet::GetUint32(Uint32 idx) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Int64 ResultSet::GetInt64(Uint32 idx) const Int64 ResultSet::GetInt64(Uint32 idx) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_FIELD(*this, idx);
m_Handle.ValidateIndex(idx);
// Should we retrieve the value from the bind wrapper? // Should we retrieve the value from the bind wrapper?
if (m_Handle->mStatement) if (m_Handle->mStatement)
{ {
@ -142,8 +197,7 @@ Int64 ResultSet::GetInt64(Uint32 idx) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Uint64 ResultSet::GetUint64(Uint32 idx) const Uint64 ResultSet::GetUint64(Uint32 idx) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_FIELD(*this, idx);
m_Handle.ValidateIndex(idx);
// Should we retrieve the value from the bind wrapper? // Should we retrieve the value from the bind wrapper?
if (m_Handle->mStatement) if (m_Handle->mStatement)
{ {
@ -156,8 +210,7 @@ Uint64 ResultSet::GetUint64(Uint32 idx) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
SQFloat ResultSet::GetFloat32(Uint32 idx) const SQFloat ResultSet::GetFloat32(Uint32 idx) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_FIELD(*this, idx);
m_Handle.ValidateIndex(idx);
// Should we retrieve the value from the bind wrapper? // Should we retrieve the value from the bind wrapper?
if (m_Handle->mStatement) if (m_Handle->mStatement)
{ {
@ -170,8 +223,7 @@ SQFloat ResultSet::GetFloat32(Uint32 idx) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
SQFloat ResultSet::GetFloat64(Uint32 idx) const SQFloat ResultSet::GetFloat64(Uint32 idx) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_FIELD(*this, idx);
m_Handle.ValidateIndex(idx);
// Should we retrieve the value from the bind wrapper? // Should we retrieve the value from the bind wrapper?
if (m_Handle->mStatement) if (m_Handle->mStatement)
{ {
@ -184,8 +236,7 @@ SQFloat ResultSet::GetFloat64(Uint32 idx) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool ResultSet::GetBoolean(Uint32 idx) const bool ResultSet::GetBoolean(Uint32 idx) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_FIELD(*this, idx);
m_Handle.ValidateIndex(idx);
// Should we retrieve the value from the bind wrapper? // Should we retrieve the value from the bind wrapper?
if (m_Handle->mStatement) if (m_Handle->mStatement)
{ {
@ -195,5 +246,34 @@ bool ResultSet::GetBoolean(Uint32 idx) const
return ConvTo< bool >::From(*reinterpret_cast< Uint8 ** >(m_Handle->mRow)[idx]); return ConvTo< bool >::From(*reinterpret_cast< Uint8 ** >(m_Handle->mRow)[idx]);
} }
// ================================================================================================
void Register_ResultSet(Table & sqlns)
{
sqlns.Bind(_SC("ResultSet")
, Class< ResultSet >(sqlns.GetVM(), _SC("SqMySQLResultSet"))
// Constructors
.Ctor()
.Ctor< const ResultSet & >()
// Core Meta-methods
.Func(_SC("_cmp"), &ResultSet::Cmp)
.SquirrelFunc(_SC("_typename"), &ResultSet::Typename)
.Func(_SC("_tostring"), &ResultSet::ToString)
// Properties
.Prop(_SC("IsValid"), &ResultSet::IsValid)
// Member Methods
.Func(_SC("GetInt8"), &ResultSet::GetInt8)
.Func(_SC("GetUint8"), &ResultSet::GetUint8)
.Func(_SC("GetInt16"), &ResultSet::GetInt16)
.Func(_SC("GetUint16"), &ResultSet::GetUint16)
.Func(_SC("GetInt32"), &ResultSet::GetInt32)
.Func(_SC("GetUint32"), &ResultSet::GetUint32)
.Func(_SC("GetInt64"), &ResultSet::GetInt64)
.Func(_SC("GetUint64"), &ResultSet::GetUint64)
.Func(_SC("GetFloat32"), &ResultSet::GetFloat32)
.Func(_SC("GetFloat64"), &ResultSet::GetFloat64)
.Func(_SC("GetBool"), &ResultSet::GetBoolean)
.Func(_SC("GetBoolean"), &ResultSet::GetBoolean)
);
}
} // Namespace:: SqMod } // Namespace:: SqMod

View File

@ -2,7 +2,7 @@
#define _SQMYSQL_RESULTSET_HPP_ #define _SQMYSQL_RESULTSET_HPP_
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
#include "Handle/Result.hpp" #include "Handle/ResultSet.hpp"
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
namespace SqMod { namespace SqMod {
@ -15,7 +15,54 @@ class ResultSet
private: private:
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
ResHnd m_Handle; // The managed result set. ResRef m_Handle; // Reference to the actual database result-set.
protected:
/* --------------------------------------------------------------------------------------------
* Validate the managed statement handle and throw an error if invalid.
*/
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void Validate(CCStr file, Int32 line) const;
#else
void Validate() const;
#endif // _DEBUG
/* --------------------------------------------------------------------------------------------
* Validate the managed statement handle and throw an error if invalid.
*/
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void ValidateCreated(CCStr file, Int32 line) const;
#else
void ValidateCreated() const;
#endif // _DEBUG
/* --------------------------------------------------------------------------------------------
* Validate the managed statement handle and throw an error if invalid.
*/
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
const ResRef & GetValid(CCStr file, Int32 line) const;
#else
const ResRef & GetValid() const;
#endif // _DEBUG
/* --------------------------------------------------------------------------------------------
* Validate the managed statement handle and throw an error if invalid.
*/
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
const ResRef & GetCreated(CCStr file, Int32 line) const;
#else
const ResRef & GetCreated() const;
#endif // _DEBUG
/* --------------------------------------------------------------------------------------------
* Validate the statement reference and field index, and throw an error if they're invalid.
*/
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void ValidateField(Int32 idx, CCStr file, Int32 line) const;
#else
void ValidateField(Int32 idx) const;
#endif // _DEBUG
public: public:
@ -29,9 +76,27 @@ public:
} }
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Base constructor. * Connection constructor.
*/ */
ResultSet(const ResHnd & hnd) ResultSet(const ConnRef & conn)
: m_Handle(new ResHnd())
{
m_Handle->Create(conn);
}
/* --------------------------------------------------------------------------------------------
* Statement constructor.
*/
ResultSet(const StmtRef & stmt)
: m_Handle(new ResHnd())
{
m_Handle->Create(stmt);
}
/* --------------------------------------------------------------------------------------------
* Handle constructor.
*/
ResultSet(const ResRef & hnd)
: m_Handle(hnd) : m_Handle(hnd)
{ {
/* ... */ /* ... */
@ -65,12 +130,35 @@ public:
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Used by the script engine to compare two instances of this type. * Used by the script engine to compare two instances of this type.
*/ */
Int32 Cmp(const ResultSet & o) const; Int32 Cmp(const ResultSet & o) const
{
if (m_Handle.Get() == o.m_Handle.Get())
{
return 0;
}
else if (m_Handle.Get() > o.m_Handle.Get())
{
return 1;
}
else
{
return -1;
}
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Used by the script engine to convert an instance of this type to a string. * Used by the script engine to convert an instance of this type to a string.
*/ */
CSStr ToString() const; CSStr ToString() const
{
// Do we have a valid handle?
if (m_Handle)
{
ToStrF("%u", m_Handle->mFieldCount);
}
// Default to a negative value
return _SC("-1");
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Used by the script engine to retrieve the name from instances of this type. * Used by the script engine to retrieve the name from instances of this type.
@ -139,7 +227,6 @@ public:
* Retrieve a boolean from a field. * Retrieve a boolean from a field.
*/ */
bool GetBoolean(Uint32 idx) const; bool GetBoolean(Uint32 idx) const;
}; };
} // Namespace:: SqMod } // Namespace:: SqMod

View File

@ -19,135 +19,170 @@ SQInteger Statement::Typename(HSQUIRRELVM vm)
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Int32 Statement::Cmp(const Statement & o) const #if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void Statement::Validate(CCStr file, Int32 line) const
{ {
if (m_Handle == o.m_Handle) if (!m_Handle)
{ {
return 0; SqThrowF("Invalid MySQL statement reference =>[%s:%d]", file, line);
}
else if (m_Handle.HndPtr() > o.m_Handle.HndPtr())
{
return 1;
}
else
{
return -1;
} }
} }
#else
void Statement::Validate() const
{
if (!m_Handle)
{
SqThrowF("Invalid MySQL statement reference");
}
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
CSStr Statement::ToString() const #if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void Statement::ValidateCreated(CCStr file, Int32 line) const
{ {
// Do we have a valid handle? if (!m_Handle)
if (m_Handle)
{ {
m_Handle->mQuery.c_str(); SqThrowF("Invalid MySQL statement reference =>[%s:%d]", file, line);
}
else if (m_Handle->mPtr == nullptr)
{
SqThrowF("Invalid MySQL statement =>[%s:%d]", file, line);
} }
// Default to an empty string
return _SC("");
} }
#else
void Statement::ValidateCreated() const
{
if (!m_Handle)
{
SqThrowF("Invalid MySQL statement reference");
}
else if (m_Handle->mPtr == nullptr)
{
SqThrowF("Invalid MySQL statement");
}
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Statement::Statement() #if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
: m_Handle() const StmtRef & Statement::GetValid(CCStr file, Int32 line) const
{ {
Validate(file, line);
return m_Handle;
} }
#else
const StmtRef & Statement::GetValid() const
{
Validate();
return m_Handle;
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Statement::Statement(const ConnHnd & connection, CSStr query) #if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
: m_Handle(connection, query) const StmtRef & Statement::GetCreated(CCStr file, Int32 line) const
{ {
ValidateCreated(file, line);
return m_Handle;
} }
#else
const StmtRef & Statement::GetCreated() const
{
ValidateCreated();
return m_Handle;
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void Statement::ValidateParam(Int32 idx, CCStr file, Int32 line) const
{
ValidateCreated(file, line);
m_Handle->ValidateParam(idx, file, line);
}
#else
void Statement::ValidateParam(Int32 idx) const
{
ValidateCreated();
m_Handle->ValidateParam(idx);
}
#endif // _DEBUG
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Statement::Statement(const Connection & connection, CSStr query) Statement::Statement(const Connection & connection, CSStr query)
: m_Handle(connection.GetHnd(), query) : Statement(connection.GetHandle(), query)
{ {
/* ... */
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Connection Statement::GetConnection() const Connection Statement::GetConnection() const
{ {
// Validate the managed handle return Connection(SQMOD_GET_VALID(*this)->mConnection);
m_Handle.Validate();
// Return the requested information
return Connection(m_Handle->mConnection);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Statement::SetConnection(const Connection & conn) void Statement::SetConnection(const Connection & conn)
{ {
// Validate the managed handle SQMOD_GET_VALID(*this)->mConnection = conn.GetHandle();
m_Handle.Validate();
// Perform the requested operation
m_Handle->mConnection = conn.GetHnd();
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Int32 Statement::Execute() Int32 Statement::Execute()
{ {
// Validate the managed handle
m_Handle.Validate();
// Attempt to bind the parameters // Attempt to bind the parameters
if (mysql_stmt_bind_param(m_Handle, m_Handle->mMyBinds)) if (mysql_stmt_bind_param(SQMOD_GET_CREATED(*this)->mPtr, m_Handle->mMyBinds))
{ {
THROW_CURRENT(m_Handle, "Cannot bind statement parameters"); SQMOD_THROW_CURRENT(*m_Handle, "Cannot bind MySQL statement parameters");
} }
// Attempt to execute the statement // Attempt to execute the statement
else if (mysql_stmt_execute(m_Handle)) else if (mysql_stmt_execute(m_Handle->mPtr))
{ {
THROW_CURRENT(m_Handle, "Cannot execute statement"); SQMOD_THROW_CURRENT(*m_Handle, "Cannot execute MySQL statement");
} }
// Return the number of rows affected by this query // Return the number of rows affected by this query
return mysql_stmt_affected_rows(m_Handle); return mysql_stmt_affected_rows(m_Handle->mPtr);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Uint32 Statement::Insert() Uint32 Statement::Insert()
{ {
// Validate the managed handle
m_Handle.Validate();
// Attempt to bind the parameters // Attempt to bind the parameters
if (mysql_stmt_bind_param(m_Handle, m_Handle->mMyBinds)) if (mysql_stmt_bind_param(SQMOD_GET_CREATED(*this)->mPtr, m_Handle->mMyBinds))
{ {
THROW_CURRENT(m_Handle, "Cannot bind statement parameters"); SQMOD_THROW_CURRENT(*m_Handle, "Cannot bind MySQL statement parameters");
} }
// Attempt to execute the statement // Attempt to execute the statement
else if (mysql_stmt_execute(m_Handle)) else if (mysql_stmt_execute(m_Handle->mPtr))
{ {
THROW_CURRENT(m_Handle, "Cannot execute statement"); SQMOD_THROW_CURRENT(*m_Handle, "Cannot execute MySQL statement");
} }
// Return the identifier of the inserted row // Return the identifier of the inserted row
return mysql_stmt_insert_id(m_Handle); return mysql_stmt_insert_id(m_Handle->mPtr);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
ResultSet Statement::Query() ResultSet Statement::Query()
{ {
// Validate the managed handle
m_Handle.Validate();
// Attempt to bind the parameters // Attempt to bind the parameters
if (mysql_stmt_bind_param(m_Handle, m_Handle->mMyBinds)) if (mysql_stmt_bind_param(SQMOD_GET_CREATED(*this)->mPtr, m_Handle->mMyBinds))
{ {
THROW_CURRENT(m_Handle, "Cannot bind statement parameters"); SQMOD_THROW_CURRENT(*m_Handle, "Cannot bind MySQL statement parameters");
} }
// Attempt to execute the statement // Attempt to execute the statement
else if (mysql_stmt_execute(m_Handle)) else if (mysql_stmt_execute(m_Handle->mPtr))
{ {
THROW_CURRENT(m_Handle, "Cannot execute statement"); SQMOD_THROW_CURRENT(*m_Handle, "Cannot execute MySQL statement");
} }
// Return the results of this query // Return the results of this query
return ResultSet(ResHnd(m_Handle)); return ResultSet(m_Handle);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Statement::SetInt8(Uint32 idx, SQInteger val) const void Statement::SetInt8(Uint32 idx, SQInteger val) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_PARAM(*this, idx);
m_Handle.ValidateIndex(idx);
// Attempt to set the input value // Attempt to set the input value
m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_TINY, &(m_Handle->mMyBinds[idx])); m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_TINY, &(m_Handle->mMyBinds[idx]));
// Assign the value to the input // Assign the value to the input
@ -157,8 +192,7 @@ void Statement::SetInt8(Uint32 idx, SQInteger val) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Statement::SetUint8(Uint32 idx, SQInteger val) const void Statement::SetUint8(Uint32 idx, SQInteger val) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_PARAM(*this, idx);
m_Handle.ValidateIndex(idx);
// Attempt to set the input value // Attempt to set the input value
m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_TINY, &(m_Handle->mMyBinds[idx])); m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_TINY, &(m_Handle->mMyBinds[idx]));
// Assign the value to the input // Assign the value to the input
@ -170,8 +204,7 @@ void Statement::SetUint8(Uint32 idx, SQInteger val) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Statement::SetInt16(Uint32 idx, SQInteger val) const void Statement::SetInt16(Uint32 idx, SQInteger val) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_PARAM(*this, idx);
m_Handle.ValidateIndex(idx);
// Attempt to set the input value // Attempt to set the input value
m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_SHORT, &(m_Handle->mMyBinds[idx])); m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_SHORT, &(m_Handle->mMyBinds[idx]));
// Assign the value to the input // Assign the value to the input
@ -181,8 +214,7 @@ void Statement::SetInt16(Uint32 idx, SQInteger val) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Statement::SetUint16(Uint32 idx, SQInteger val) const void Statement::SetUint16(Uint32 idx, SQInteger val) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_PARAM(*this, idx);
m_Handle.ValidateIndex(idx);
// Attempt to set the input value // Attempt to set the input value
m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_SHORT, &(m_Handle->mMyBinds[idx])); m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_SHORT, &(m_Handle->mMyBinds[idx]));
// Assign the value to the input // Assign the value to the input
@ -194,8 +226,7 @@ void Statement::SetUint16(Uint32 idx, SQInteger val) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Statement::SetInt32(Uint32 idx, SQInteger val) const void Statement::SetInt32(Uint32 idx, SQInteger val) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_PARAM(*this, idx);
m_Handle.ValidateIndex(idx);
// Attempt to set the input value // Attempt to set the input value
m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_LONG, &(m_Handle->mMyBinds[idx])); m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_LONG, &(m_Handle->mMyBinds[idx]));
// Assign the value to the input // Assign the value to the input
@ -205,8 +236,7 @@ void Statement::SetInt32(Uint32 idx, SQInteger val) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Statement::SetUint32(Uint32 idx, SQInteger val) const void Statement::SetUint32(Uint32 idx, SQInteger val) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_PARAM(*this, idx);
m_Handle.ValidateIndex(idx);
// Attempt to set the input value // Attempt to set the input value
m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_LONG, &(m_Handle->mMyBinds[idx])); m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_LONG, &(m_Handle->mMyBinds[idx]));
// Assign the value to the input // Assign the value to the input
@ -218,8 +248,7 @@ void Statement::SetUint32(Uint32 idx, SQInteger val) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Statement::SetInt64(Uint32 idx, SQInteger val) const void Statement::SetInt64(Uint32 idx, SQInteger val) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_PARAM(*this, idx);
m_Handle.ValidateIndex(idx);
// Attempt to set the input value // Attempt to set the input value
m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_LONGLONG, &(m_Handle->mMyBinds[idx])); m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_LONGLONG, &(m_Handle->mMyBinds[idx]));
// Assign the value to the input // Assign the value to the input
@ -229,8 +258,7 @@ void Statement::SetInt64(Uint32 idx, SQInteger val) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Statement::SetUint64(Uint32 idx, SQInteger val) const void Statement::SetUint64(Uint32 idx, SQInteger val) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_PARAM(*this, idx);
m_Handle.ValidateIndex(idx);
// Attempt to set the input value // Attempt to set the input value
m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_LONGLONG, &(m_Handle->mMyBinds[idx])); m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_LONGLONG, &(m_Handle->mMyBinds[idx]));
// Assign the value to the input // Assign the value to the input
@ -242,39 +270,23 @@ void Statement::SetUint64(Uint32 idx, SQInteger val) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Statement::SetSLongInt(Uint32 idx, Object & val) const void Statement::SetSLongInt(Uint32 idx, Object & val) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_PARAM(*this, idx);
m_Handle.ValidateIndex(idx);
// Attempt to set the input value // Attempt to set the input value
m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_LONGLONG, &(m_Handle->mMyBinds[idx])); m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_LONGLONG, &(m_Handle->mMyBinds[idx]));
// Obtain the initial stack size // Attempt to assign the numeric value inside the specified object
const StackGuard sg; m_Handle->mBinds[idx].mInt64 = FetchSLongObjVal(val);
// Push the specified object onto the stack
Var< Object >::push(_SqVM, val);
// Attempt to get the numeric value inside the specified object
if (SQ_FAILED(_SqMod->GetSLongValue(_SqVM, -1, &(m_Handle->mBinds[idx].mInt64))))
{
STHROWF("Invalid long integer specified");
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Statement::SetULongInt(Uint32 idx, Object & val) const void Statement::SetULongInt(Uint32 idx, Object & val) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_PARAM(*this, idx);
m_Handle.ValidateIndex(idx);
// Attempt to set the input value // Attempt to set the input value
m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_LONGLONG, &(m_Handle->mMyBinds[idx])); m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_LONGLONG, &(m_Handle->mMyBinds[idx]));
// Attempt to assign the numeric value inside the specified object
m_Handle->mBinds[idx].mUint64 = FetchULongObjVal(val);
// Specify that this value is unsigned // Specify that this value is unsigned
m_Handle->mMyBinds[idx].is_unsigned = true; m_Handle->mMyBinds[idx].is_unsigned = true;
// Obtain the initial stack size
const StackGuard sg;
// Push the specified object onto the stack
Var< Object >::push(_SqVM, val);
// Attempt to get the numeric value inside the specified object
if (SQ_FAILED(_SqMod->GetULongValue(_SqVM, -1, &(m_Handle->mBinds[idx].mUint64))))
{
STHROWF("Invalid long integer specified");
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -290,8 +302,7 @@ void Statement::SetInteger(Uint32 idx, SQInteger val) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Statement::SetFloat32(Uint32 idx, SQFloat val) const void Statement::SetFloat32(Uint32 idx, SQFloat val) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_PARAM(*this, idx);
m_Handle.ValidateIndex(idx);
// Attempt to set the input value // Attempt to set the input value
m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_FLOAT, &(m_Handle->mMyBinds[idx])); m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_FLOAT, &(m_Handle->mMyBinds[idx]));
// Assign the value to the input // Assign the value to the input
@ -301,8 +312,7 @@ void Statement::SetFloat32(Uint32 idx, SQFloat val) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Statement::SetFloat64(Uint32 idx, SQFloat val) const void Statement::SetFloat64(Uint32 idx, SQFloat val) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_PARAM(*this, idx);
m_Handle.ValidateIndex(idx);
// Attempt to set the input value // Attempt to set the input value
m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_DOUBLE, &(m_Handle->mMyBinds[idx])); m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_DOUBLE, &(m_Handle->mMyBinds[idx]));
// Assign the value to the input // Assign the value to the input
@ -322,8 +332,7 @@ void Statement::SetFloat(Uint32 idx, SQFloat val) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Statement::SetBoolean(Uint32 idx, bool val) const void Statement::SetBoolean(Uint32 idx, bool val) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_PARAM(*this, idx);
m_Handle.ValidateIndex(idx);
// Attempt to set the input value // Attempt to set the input value
m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_TINY, &(m_Handle->mMyBinds[idx])); m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_TINY, &(m_Handle->mMyBinds[idx]));
// Assign the value to the input // Assign the value to the input
@ -333,8 +342,7 @@ void Statement::SetBoolean(Uint32 idx, bool val) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Statement::SetDate(Uint32 idx, Object & val) const void Statement::SetDate(Uint32 idx, Object & val) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_PARAM(*this, idx);
m_Handle.ValidateIndex(idx);
// Attempt to set the input value // Attempt to set the input value
m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_DATE, &(m_Handle->mMyBinds[idx])); m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_DATE, &(m_Handle->mMyBinds[idx]));
// Assign the value to the input // Assign the value to the input
@ -344,8 +352,7 @@ void Statement::SetDate(Uint32 idx, Object & val) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Statement::SetTime(Uint32 idx, Object & val) const void Statement::SetTime(Uint32 idx, Object & val) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_PARAM(*this, idx);
m_Handle.ValidateIndex(idx);
// Attempt to set the input value // Attempt to set the input value
m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_TIME, &(m_Handle->mMyBinds[idx])); m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_TIME, &(m_Handle->mMyBinds[idx]));
// Assign the value to the input // Assign the value to the input
@ -355,8 +362,7 @@ void Statement::SetTime(Uint32 idx, Object & val) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Statement::SetDatetime(Uint32 idx, Object & val) const void Statement::SetDatetime(Uint32 idx, Object & val) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_PARAM(*this, idx);
m_Handle.ValidateIndex(idx);
// Attempt to set the input value // Attempt to set the input value
m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_DATETIME, &(m_Handle->mMyBinds[idx])); m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_DATETIME, &(m_Handle->mMyBinds[idx]));
// Assign the value to the input // Assign the value to the input
@ -366,8 +372,7 @@ void Statement::SetDatetime(Uint32 idx, Object & val) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Statement::SetString(Uint32 idx, CSStr val) const void Statement::SetString(Uint32 idx, CSStr val) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_PARAM(*this, idx);
m_Handle.ValidateIndex(idx);
// Attempt to set the input value // Attempt to set the input value
m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_STRING, &(m_Handle->mMyBinds[idx]), val, std::strlen(val)); m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_STRING, &(m_Handle->mMyBinds[idx]), val, std::strlen(val));
} }
@ -375,8 +380,7 @@ void Statement::SetString(Uint32 idx, CSStr val) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Statement::SetEnum(Uint32 idx, CSStr val) const void Statement::SetEnum(Uint32 idx, CSStr val) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_PARAM(*this, idx);
m_Handle.ValidateIndex(idx);
// Attempt to set the input value // Attempt to set the input value
m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_ENUM, &(m_Handle->mMyBinds[idx]), val, std::strlen(val)); m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_ENUM, &(m_Handle->mMyBinds[idx]), val, std::strlen(val));
} }
@ -384,8 +388,7 @@ void Statement::SetEnum(Uint32 idx, CSStr val) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Statement::SetSet(Uint32 idx, CSStr val) const void Statement::SetSet(Uint32 idx, CSStr val) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_PARAM(*this, idx);
m_Handle.ValidateIndex(idx);
// Attempt to set the input value // Attempt to set the input value
m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_SET, &(m_Handle->mMyBinds[idx]), val, std::strlen(val)); m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_SET, &(m_Handle->mMyBinds[idx]), val, std::strlen(val));
} }
@ -405,10 +408,57 @@ void Statement::SetData(Uint32 /*idx*/, Object & /*val*/) const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Statement::SetNull(Uint32 idx) const void Statement::SetNull(Uint32 idx) const
{ {
// Validate the managed handle and specified index SQMOD_VALIDATE_PARAM(*this, idx);
m_Handle.ValidateIndex(idx);
// Attempt to set the input value // Attempt to set the input value
m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_NULL, &(m_Handle->mMyBinds[idx])); m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_NULL, &(m_Handle->mMyBinds[idx]));
} }
} // Namespace:: SqMod // ================================================================================================
void Register_Statement(Table & sqlns)
{
sqlns.Bind(_SC("Statement")
, Class< Statement >(sqlns.GetVM(), _SC("SqMySQLStatement"))
// Constructors
.Ctor()
.Ctor< const Statement & >()
.Ctor< const Connection &, CSStr >()
// Core Meta-methods
.Func(_SC("_cmp"), &Statement::Cmp)
.SquirrelFunc(_SC("_typename"), &Statement::Typename)
.Func(_SC("_tostring"), &Statement::ToString)
// Properties
.Prop(_SC("IsValid"), &Statement::IsValid)
.Prop(_SC("Connection"), &Statement::GetConnection, &Statement::SetConnection)
// Member Methods
.Func(_SC("Execute"), &Statement::Execute)
.Func(_SC("Insert"), &Statement::Insert)
.Func(_SC("Query"), &Statement::Query)
.Func(_SC("SetInt8"), &Statement::SetInt8)
.Func(_SC("SetUint8"), &Statement::SetUint8)
.Func(_SC("SetInt16"), &Statement::SetInt16)
.Func(_SC("SetUint16"), &Statement::SetUint16)
.Func(_SC("SetInt32"), &Statement::SetInt32)
.Func(_SC("SetUint32"), &Statement::SetUint32)
.Func(_SC("SetInt64"), &Statement::SetInt64)
.Func(_SC("SetUint64"), &Statement::SetUint64)
.Func(_SC("SetSLongInt"), &Statement::SetSLongInt)
.Func(_SC("SetULongInt"), &Statement::SetULongInt)
.Func(_SC("SetInteger"), &Statement::SetInteger)
.Func(_SC("SetFloat32"), &Statement::SetFloat32)
.Func(_SC("SetFloat64"), &Statement::SetFloat64)
.Func(_SC("SetFloat"), &Statement::SetFloat)
.Func(_SC("SetBoolean"), &Statement::SetBoolean)
.Func(_SC("SetDate"), &Statement::SetDate)
.Func(_SC("SetTime"), &Statement::SetTime)
.Func(_SC("SetDatetime"), &Statement::SetDatetime)
.Func(_SC("SetString"), &Statement::SetString)
.Func(_SC("SetEnum"), &Statement::SetEnum)
.Func(_SC("SetSet"), &Statement::SetSet)
.Func(_SC("SetBlob"), &Statement::SetBlob)
.Func(_SC("SetData"), &Statement::SetData)
.Func(_SC("SetBuffer"), &Statement::SetData)
.Func(_SC("SetNull"), &Statement::SetNull)
);
}
} // Namespace:: SqMod

View File

@ -15,19 +15,74 @@ class Statement
private: private:
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
StmtHnd m_Handle; // Reference to the managed statement. StmtRef m_Handle; // Reference to the actual database statement.
protected:
/* --------------------------------------------------------------------------------------------
* Validate the managed statement handle and throw an error if invalid.
*/
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void Validate(CCStr file, Int32 line) const;
#else
void Validate() const;
#endif // _DEBUG
/* --------------------------------------------------------------------------------------------
* Validate the managed statement handle and throw an error if invalid.
*/
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void ValidateCreated(CCStr file, Int32 line) const;
#else
void ValidateCreated() const;
#endif // _DEBUG
/* --------------------------------------------------------------------------------------------
* Validate the managed statement handle and throw an error if invalid.
*/
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
const StmtRef & GetValid(CCStr file, Int32 line) const;
#else
const StmtRef & GetValid() const;
#endif // _DEBUG
/* --------------------------------------------------------------------------------------------
* Validate the managed statement handle and throw an error if invalid.
*/
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
const StmtRef & GetCreated(CCStr file, Int32 line) const;
#else
const StmtRef & GetCreated() const;
#endif // _DEBUG
/* --------------------------------------------------------------------------------------------
* Validate the statement reference and parameter index, and throw an error if they're invalid.
*/
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void ValidateParam(Int32 idx, CCStr file, Int32 line) const;
#else
void ValidateParam(Int32 idx) const;
#endif // _DEBUG
public: public:
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Default constructor. * Default constructor.
*/ */
Statement(); Statement()
: m_Handle()
{
/* ... */
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Construct a statement under the specified connection using the specified string. * Construct a statement under the specified connection using the specified string.
*/ */
Statement(const ConnHnd & connection, CSStr query); Statement(const ConnRef & connection, CSStr query)
: m_Handle(new StmtHnd())
{
m_Handle->Create(connection, query);
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Construct a statement under the specified connection using the specified string. * Construct a statement under the specified connection using the specified string.
@ -44,11 +99,6 @@ public:
*/ */
Statement(Statement && o) = default; Statement(Statement && o) = default;
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~Statement() = default;
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Copy assignment operator. * Copy assignment operator.
*/ */
@ -62,18 +112,49 @@ public:
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Used by the script engine to compare two instances of this type. * Used by the script engine to compare two instances of this type.
*/ */
Int32 Cmp(const Statement & o) const; Int32 Cmp(const Statement & o) const
{
if (m_Handle.Get() == o.m_Handle.Get())
{
return 0;
}
else if (m_Handle.Get() > o.m_Handle.Get())
{
return 1;
}
else
{
return -1;
}
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Used by the script engine to convert an instance of this type to a string. * Used by the script engine to convert an instance of this type to a string.
*/ */
CSStr ToString() const; const String & ToString() const
{
// Do we have a valid handle?
if (m_Handle)
{
m_Handle->mQuery;
}
// Default to an empty string
return NullString();
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* Used by the script engine to retrieve the name from instances of this type. * Used by the script engine to retrieve the name from instances of this type.
*/ */
static SQInteger Typename(HSQUIRRELVM vm); static SQInteger Typename(HSQUIRRELVM vm);
/* --------------------------------------------------------------------------------------------
* Retrieve the associated connection handle.
*/
const StmtRef & GetHandle() const
{
return m_Handle;
}
/* -------------------------------------------------------------------------------------------- /* --------------------------------------------------------------------------------------------
* See whether the managed handle is valid. * See whether the managed handle is valid.
*/ */