mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2025-08-03 14:41:48 +02:00
Partial and untested revision of the MySQL module.
This commit is contained in:
@@ -11,79 +11,107 @@
|
||||
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);
|
||||
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)
|
||||
: mPtr(mysql_init(NULL))
|
||||
, mRef(0)
|
||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
||||
void ConnHnd::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 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)
|
||||
, mErrStr(_SC(""))
|
||||
, 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())
|
||||
, mPort()
|
||||
, mHost()
|
||||
, mUser()
|
||||
, mPass()
|
||||
, mName()
|
||||
, mSocket()
|
||||
, mFlags()
|
||||
, mSSL_Key()
|
||||
, mSSL_Cert()
|
||||
, mSSL_CA()
|
||||
, mSSL_CA_Path()
|
||||
, mSSL_Cipher()
|
||||
, mCharset()
|
||||
, mAutoCommit(acc.GetAutoCommit())
|
||||
, mAutoCommit()
|
||||
, 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
|
||||
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
|
||||
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)
|
||||
{
|
||||
THROW_CURRENT_HND((*this), "Cannot configure SSL");
|
||||
SQMOD_THROW_CURRENT(*this, "Cannot configure SSL");
|
||||
}
|
||||
// Attempt to connect to the specified server
|
||||
else if (!mysql_real_connect(mPtr, mHost.c_str(), mUser.c_str(), mPass.c_str(),
|
||||
mName.empty() ? nullptr : mName.c_str(), mPort,
|
||||
mSocket.empty() ? nullptr : mSocket.c_str(), mFlags))
|
||||
(mName.empty() ? nullptr : mName.c_str()), mPort,
|
||||
(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
|
||||
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
|
||||
Account::Options::const_iterator itr = acc.GetOptions().cbegin();
|
||||
@@ -99,7 +127,7 @@ ConnHnd::Handle::Handle(const Account & acc)
|
||||
// Execute the resulted query
|
||||
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;
|
||||
@@ -113,13 +141,7 @@ ConnHnd::Handle::Handle(const Account & acc)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ConnHnd::Handle::~Handle()
|
||||
{
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConnHnd::Handle::Disconnect()
|
||||
void ConnHnd::Disconnect()
|
||||
{
|
||||
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
|
||||
if (!mPtr)
|
||||
@@ -151,10 +173,11 @@ Uint64 ConnHnd::Handle::Execute(CSStr query, Ulong size)
|
||||
size = std::strlen(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
|
||||
Uint64 affected = 0UL;
|
||||
// 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
|
||||
ResType * result = mysql_store_result(mPtr);
|
||||
|
||||
// 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
|
||||
if (result)
|
||||
@@ -177,15 +201,16 @@ Uint64 ConnHnd::Handle::Execute(CSStr query, Ulong size)
|
||||
}
|
||||
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
|
||||
// If return code is 0 then we have a result ready to process
|
||||
const Int32 status = mysql_next_result(mPtr);
|
||||
|
||||
// If return code is higher than 0 then an error occurred
|
||||
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
|
||||
else if (status < 0)
|
||||
@@ -197,4 +222,4 @@ Uint64 ConnHnd::Handle::Execute(CSStr query, Ulong size)
|
||||
return affected;
|
||||
}
|
||||
|
||||
} // Namespace:: SqMod
|
||||
} // Namespace:: SqMod
|
@@ -8,14 +8,10 @@
|
||||
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:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
@@ -29,343 +25,79 @@ public:
|
||||
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_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:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor (null).
|
||||
*/
|
||||
ConnHnd()
|
||||
: m_Hnd(nullptr)
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Pointer mPtr; // The connection handle resource.
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
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)
|
||||
: m_Hnd(o.m_Hnd)
|
||||
{
|
||||
Grab();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor.
|
||||
*/
|
||||
ConnHnd(ConnHnd && o)
|
||||
: m_Hnd(o.m_Hnd)
|
||||
{
|
||||
o.m_Hnd = nullptr;
|
||||
}
|
||||
ConnHnd();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~ConnHnd()
|
||||
{
|
||||
Drop();
|
||||
}
|
||||
~ConnHnd();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator.
|
||||
* Grab the current error in the connection handle.
|
||||
*/
|
||||
ConnHnd & operator = (const ConnHnd & o)
|
||||
{
|
||||
if (m_Hnd != o.m_Hnd)
|
||||
{
|
||||
Drop();
|
||||
m_Hnd = o.m_Hnd;
|
||||
Grab();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
void GrabCurrent();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move assignment operator.
|
||||
* Grab the current error in the connection handle and throw it.
|
||||
*/
|
||||
ConnHnd & operator = (ConnHnd && o)
|
||||
{
|
||||
if (m_Hnd != o.m_Hnd)
|
||||
{
|
||||
m_Hnd = o.m_Hnd;
|
||||
o.m_Hnd = nullptr;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
||||
void ThrowCurrent(CCStr act, CCStr file, Int32 line);
|
||||
#else
|
||||
void ThrowCurrent(CCStr act);
|
||||
#endif // _DEBUG
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Status assignment operator.
|
||||
* Create the connection handle.
|
||||
*/
|
||||
ConnHnd & operator = (Uint32 status)
|
||||
{
|
||||
if (m_Hnd)
|
||||
{
|
||||
m_Hnd->mErrNo = status;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
void Create(const Account & acc);
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Perform an equality comparison between two connection handles.
|
||||
* Disconnect the managed connection handle.
|
||||
*/
|
||||
bool operator == (const ConnHnd & o) const
|
||||
{
|
||||
return (m_Hnd == o.m_Hnd);
|
||||
}
|
||||
void Disconnect();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Perform an inequality comparison between two connection handles.
|
||||
* Execute a query on the server.
|
||||
*/
|
||||
bool operator != (const ConnHnd & 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 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;
|
||||
}
|
||||
Uint64 Execute(CSStr query, Ulong size = 0UL);
|
||||
};
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
@@ -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_
|
@@ -1,5 +1,5 @@
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Handle/Result.hpp"
|
||||
#include "Handle/ResultSet.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <cstdio>
|
||||
@@ -10,31 +10,7 @@
|
||||
namespace SqMod {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ResHnd::Validate() const
|
||||
{
|
||||
// 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)
|
||||
void ResBind::SetOutput(const FieldType & field, BindType * bind)
|
||||
{
|
||||
// Associate the library bind point with our bind wrapper
|
||||
mBind = bind;
|
||||
@@ -113,26 +89,154 @@ void ResHnd::Bind::SetOutput(const FieldType & field, BindType * bind)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ResHnd::Handle::Handle(const ConnHnd & conn)
|
||||
: mPtr(mysql_store_result(conn))
|
||||
, mRef(1)
|
||||
ResHnd::ResHnd()
|
||||
: mPtr(nullptr)
|
||||
, mFieldCount(0)
|
||||
, mLengths(nullptr)
|
||||
, mFields(nullptr)
|
||||
, mBinds(nullptr)
|
||||
, mMyBinds(nullptr)
|
||||
, mRow(nullptr)
|
||||
, mConnection()
|
||||
, mStatement()
|
||||
, 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?
|
||||
if (!mPtr)
|
||||
{
|
||||
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);
|
||||
// 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);
|
||||
// Associate the field names with their index
|
||||
for (Uint32 i = 0; i < mFieldCount; ++i)
|
||||
@@ -142,47 +246,66 @@ ResHnd::Handle::Handle(const ConnHnd & conn)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ResHnd::Handle::Handle(const StmtHnd & stmt)
|
||||
: mPtr(nullptr)
|
||||
, mRef(1)
|
||||
, mFieldCount(0)
|
||||
, mLengths(nullptr)
|
||||
, mFields(nullptr)
|
||||
, mBinds(nullptr)
|
||||
, mMyBinds(nullptr)
|
||||
, mRow(nullptr)
|
||||
, mStatement(stmt)
|
||||
, mIndexes()
|
||||
void ResHnd::Create(const StmtRef & stmt)
|
||||
{
|
||||
// Is this result-set already created?
|
||||
if (mPtr != nullptr)
|
||||
{
|
||||
STHROWF("MySQL result-set was already created");
|
||||
}
|
||||
// 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
|
||||
int max_length = 1;
|
||||
// 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
|
||||
if (mysql_stmt_store_result(mStatement))
|
||||
// Attempt to buffer the complete result-set on the client
|
||||
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
|
||||
mFieldCount = mysql_stmt_field_count(mStatement);
|
||||
// Obtain the result set meta-data
|
||||
mPtr = mysql_stmt_result_metadata(mStatement);
|
||||
// Obtain an array representing the fields in the result set
|
||||
// Obtain the number of fields in the result-set
|
||||
mFieldCount = mysql_stmt_field_count(mStatement->mPtr);
|
||||
// Obtain the result-set meta-data
|
||||
mPtr = mysql_stmt_result_metadata(mStatement->mPtr);
|
||||
// Obtain an array representing the fields in the result-set
|
||||
mFields = mysql_fetch_fields(mPtr);
|
||||
// Are there any fields to allocate
|
||||
if (mFieldCount > 0)
|
||||
{
|
||||
// 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
|
||||
mMyBinds = new BindType[mFieldCount];
|
||||
// Validate the allocated structures
|
||||
if (!mMyBinds)
|
||||
{
|
||||
STHROWF("Unable to allocate MySQL bind point structures");
|
||||
}
|
||||
// Allocate the row pointers
|
||||
mRow = new CStr[mFieldCount];
|
||||
// Validate the allocated structures
|
||||
if (!mRow)
|
||||
{
|
||||
STHROWF("Unable to allocate MySQL row pointers");
|
||||
}
|
||||
// Initialize the bind points to null
|
||||
std::memset(mMyBinds, 0, sizeof(BindType) * mFieldCount);
|
||||
}
|
||||
@@ -197,45 +320,10 @@ ResHnd::Handle::Handle(const StmtHnd & stmt)
|
||||
mRow[i] = mBinds[i].GetBuffer();
|
||||
}
|
||||
// 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
|
209
modules/mysql/Handle/ResultSet.hpp
Normal file
209
modules/mysql/Handle/ResultSet.hpp
Normal 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_
|
@@ -10,51 +10,7 @@
|
||||
namespace SqMod {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void StmtHnd::Validate() const
|
||||
{
|
||||
// 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)
|
||||
void StmtBind::SetInput(enum_field_types type, BindType * bind, CCStr buffer, Ulong length)
|
||||
{
|
||||
// Associate the library bind point with our bind wrapper
|
||||
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)
|
||||
: mPtr(mysql_stmt_init(conn))
|
||||
, mRef(1)
|
||||
, mErrNo(0)
|
||||
, mParams(0)
|
||||
, mBinds(nullptr)
|
||||
, mMyBinds(nullptr)
|
||||
, mConnection(conn)
|
||||
, mQuery(query ? query : _SC(""))
|
||||
void StmtHnd::GrabCurrent()
|
||||
{
|
||||
// Validate the obtained statement handle
|
||||
if (!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);
|
||||
mErrNo = mysql_stmt_errno(mPtr);
|
||||
mErrStr.assign(mysql_stmt_error(mPtr));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
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?
|
||||
if (mMyBinds)
|
||||
{
|
||||
delete [] mMyBinds;
|
||||
delete [] (mMyBinds);
|
||||
}
|
||||
// Should we delete binding wrappers?
|
||||
if (mBinds)
|
||||
{
|
||||
delete [] mBinds;
|
||||
delete [] (mBinds);
|
||||
}
|
||||
// Should we release any statement?
|
||||
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
|
||||
|
@@ -3,22 +3,16 @@
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include "Handle/Connection.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
#include <Base/Buffer.hpp>
|
||||
#include "Base/Buffer.hpp"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
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:
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
@@ -33,409 +27,163 @@ public:
|
||||
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_TIME TimeType; // Database time 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:
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Default constructor (null).
|
||||
*/
|
||||
StmtHnd()
|
||||
: m_Hnd(nullptr)
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
// --------------------------------------------------------------------------------------------
|
||||
Pointer mPtr; // The managed statement handle.
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
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)
|
||||
: m_Hnd(o.m_Hnd)
|
||||
|
||||
{
|
||||
Grab();
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move constructor.
|
||||
*/
|
||||
StmtHnd(StmtHnd && o)
|
||||
: m_Hnd(o.m_Hnd)
|
||||
{
|
||||
o.m_Hnd = nullptr;
|
||||
}
|
||||
StmtHnd();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Destructor.
|
||||
*/
|
||||
~StmtHnd()
|
||||
{
|
||||
Drop();
|
||||
}
|
||||
~StmtHnd();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Copy assignment operator.
|
||||
* Grab the current error in the associated statement handle.
|
||||
*/
|
||||
StmtHnd & operator = (const StmtHnd & o)
|
||||
{
|
||||
if (m_Hnd != o.m_Hnd)
|
||||
{
|
||||
Drop();
|
||||
m_Hnd = o.m_Hnd;
|
||||
Grab();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
void GrabCurrent();
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Move assignment operator.
|
||||
* Grab the current error in the associated statement handle and throw it.
|
||||
*/
|
||||
StmtHnd & operator = (StmtHnd && o)
|
||||
{
|
||||
if (m_Hnd != o.m_Hnd)
|
||||
{
|
||||
m_Hnd = o.m_Hnd;
|
||||
o.m_Hnd = nullptr;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
||||
void ThrowCurrent(CCStr act, CCStr file, Int32 line);
|
||||
#else
|
||||
void ThrowCurrent(CCStr act);
|
||||
#endif // _DEBUG
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Status assignment operator.
|
||||
* Validate the associated statement handle and parameter index and throw an error if invalid.
|
||||
*/
|
||||
StmtHnd & operator = (Uint32 status)
|
||||
{
|
||||
if (m_Hnd)
|
||||
{
|
||||
m_Hnd->mErrNo = status;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
|
||||
void ValidateParam(Uint32 idx, CCStr file, Int32 line) const;
|
||||
#else
|
||||
void ValidateParam(Uint32 idx) const;
|
||||
#endif // _DEBUG
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
* Perform an equality comparison between two statement handles.
|
||||
* Create the actual statement.
|
||||
*/
|
||||
bool operator == (const StmtHnd & o) const
|
||||
{
|
||||
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;
|
||||
}
|
||||
void Create(const ConnRef & conn, CSStr query);
|
||||
};
|
||||
|
||||
|
||||
} // Namespace:: SqMod
|
||||
|
||||
#endif // _SQMYSQL_HANDLE_STATEMENT_HPP_
|
||||
|
Reference in New Issue
Block a user