1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2025-06-15 22:57:12 +02:00

Partial untested implementation of the MySQL module.

This commit is contained in:
Sandu Liviu Catalin
2016-06-03 21:33:21 +03:00
parent f6987b3de2
commit 279479cddc
35 changed files with 3487 additions and 1357 deletions

View File

@ -0,0 +1,207 @@
// ------------------------------------------------------------------------------------------------
#include "Handle/Connection.hpp"
#include "Account.hpp"
// ------------------------------------------------------------------------------------------------
#include <cstdio>
#include <cstring>
#include <cstdlib>
// ------------------------------------------------------------------------------------------------
namespace SqMod {
// ------------------------------------------------------------------------------------------------
void ConnHnd::Validate() const
{
// 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)
, 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())
, mCharset()
, mQueue()
, mAutoCommit(acc.GetAutoCommit())
, mInTransaction(false)
{
// See if a connection handle could be initialized
if (!mPtr)
{
THROW_CURRENT_HND((*this), "Cannot create MYSQL object");
}
// 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(),
mSSL_CA_Path.c_str(), mSSL_Cipher.c_str()) != 0)
{
THROW_CURRENT_HND((*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))
{
THROW_CURRENT_HND((*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");
}
// Get iterators to the options container
Account::Options::const_iterator itr = acc.GetOptions().cbegin();
Account::Options::const_iterator end = acc.GetOptions().cend();
// Process each option in the container
for (String sql(128, 0); itr != end; ++itr)
{
// Prepare the SQL query that applies the option
sql.assign("SET OPTION ");
sql.append(itr->first);
sql.append("=");
sql.append(itr->second);
// Execute the resulted query
if (Execute(sql.c_str(), static_cast< Ulong >(sql.size())) != 1)
{
THROW_CURRENT_HND((*this), "Unable to apply option");
}
}
MY_CHARSET_INFO charsetinfo;
// Grab the information about the current character set
mysql_get_character_set_info(mPtr, &charsetinfo);
// We only need the character set name
if (charsetinfo.name != nullptr)
{
mCharset.assign(charsetinfo.name);
}
}
// ------------------------------------------------------------------------------------------------
ConnHnd::Handle::~Handle()
{
}
// ------------------------------------------------------------------------------------------------
void ConnHnd::Handle::Disconnect()
{
if (mPtr != nullptr)
{
mysql_close(mPtr);
// mysql_init() called mysql_thread_init() therefore it needs to clear memory
// when the MYSQL handle is closed
mysql_thread_end();
// Prevent further use of this handle
mPtr = nullptr;
}
}
// ------------------------------------------------------------------------------------------------
Int32 ConnHnd::Handle::Flush(Uint32 /*num*/, Object & /*env*/, Function & /*func*/)
{
return 0;
}
// ------------------------------------------------------------------------------------------------
Ulong ConnHnd::Handle::Execute(CSStr query, Ulong size)
{
// Make sure that we are connected
if (!mPtr)
{
STHROWF("Invalid MySQL connection");
}
// Make sure the specified query is valid
else if (!query || *query == '\0')
{
STHROWF("Invalid or empty MySQL query");
}
// Are we supposed to compute the size?
else if (!size)
{
size = std::strlen(query);
}
// Attempt to execute the specified query
else if (mysql_real_query(mPtr, query, size) != 0)
{
THROW_CURRENT_HND((*this), "Unable to execute query");
}
// Where the number of affected rows will be stored
Ulong affected = 0UL;
// Count the number of affected rows by any "upsert" statement
while (true)
{
// 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)
{
// Just, free the memory associated with the obtained result set
mysql_free_result(result);
}
// Non SELCT queries should have a field count of 0
else if (mysql_field_count(mPtr) == 0)
{
// Sum the number of affected rows by this statement
affected += mysql_affected_rows(mPtr);
}
else
{
THROW_CURRENT_HND((*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");
}
// If return code is less than 0 then there are no results left
else if (status < 0)
{
break;
}
}
// Return the number of affected rows
return affected;
}
} // Namespace:: SqMod

View File

@ -0,0 +1,387 @@
#ifndef _SQMYSQL_HANDLE_CONNECTION_HPP_
#define _SQMYSQL_HANDLE_CONNECTION_HPP_
// ------------------------------------------------------------------------------------------------
#include "Common.hpp"
// ------------------------------------------------------------------------------------------------
#include <vector>
// ------------------------------------------------------------------------------------------------
namespace SqMod {
/* ------------------------------------------------------------------------------------------------
* Manages a reference counted database connection handle.
*/
class ConnHnd
{
// --------------------------------------------------------------------------------------------
friend class Connection;
friend class Statement;
public:
// --------------------------------------------------------------------------------------------
typedef MYSQL 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_RES ResType; // Database result type.
/* --------------------------------------------------------------------------------------------
* Validate the connection handle and throw an error if invalid.
*/
void Validate() const;
protected:
// --------------------------------------------------------------------------------------------
typedef std::vector< String > QueryList; // Container used to queue queries.
/* --------------------------------------------------------------------------------------------
* 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.
// ----------------------------------------------------------------------------------------
QueryList mQueue; // A queue of queries to be executed in groups.
// ----------------------------------------------------------------------------------------
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 specific amount of queries from the queue.
*/
Int32 Flush(Uint32 num, Object & env, Function & func);
/* ----------------------------------------------------------------------------------------
* Execute a query on the server.
*/
Ulong 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)
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Copy 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;
}
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~ConnHnd()
{
Drop();
}
/* --------------------------------------------------------------------------------------------
* Copy assignment operator.
*/
ConnHnd & operator = (const ConnHnd & o)
{
if (m_Hnd != o.m_Hnd)
{
Drop();
m_Hnd = o.m_Hnd;
Grab();
}
return *this;
}
/* --------------------------------------------------------------------------------------------
* Move assignment operator.
*/
ConnHnd & operator = (ConnHnd && o)
{
if (m_Hnd != o.m_Hnd)
{
m_Hnd = o.m_Hnd;
o.m_Hnd = nullptr;
}
return *this;
}
/* --------------------------------------------------------------------------------------------
* Status assignment operator.
*/
ConnHnd & operator = (Uint32 status)
{
if (m_Hnd)
{
m_Hnd->mErrNo = status;
}
return *this;
}
/* --------------------------------------------------------------------------------------------
* Perform an equality comparison between two connection handles.
*/
bool operator == (const ConnHnd & o) const
{
return (m_Hnd == o.m_Hnd);
}
/* --------------------------------------------------------------------------------------------
* Perform an inequality comparison between two connection handles.
*/
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;
}
};
} // Namespace:: SqMod
#endif // _SQMYSQL_HANDLE_CONNECTION_HPP_

View File

@ -0,0 +1,240 @@
// ------------------------------------------------------------------------------------------------
#include "Handle/Result.hpp"
// ------------------------------------------------------------------------------------------------
#include <cstdio>
#include <cstring>
#include <cstdlib>
// ------------------------------------------------------------------------------------------------
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)
{
// Associate the library bind point with our bind wrapper
mBind = bind;
// Assign the 64 bit unsigned integer as the default buffer
mBind->buffer = &mUint64;
// Match the bind point type to the one from the field
mBind->buffer_type = field.type;
// Default to n empty buffer until type identification
mBind->buffer_length = 0;
// Allow the library to specify whether the value is null
mBind->is_null = &mIsNull;
// Allow the library to specify if errors occurred
mBind->error = &mError;
// Tell the library where to read the buffer size
mBind->length = &(mBind->buffer_length);
// Identify and configure the field type
switch (field.type)
{
case MYSQL_TYPE_NULL:
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_BIT:
{
mBind->buffer_length = 1;
} break;
case MYSQL_TYPE_YEAR:
case MYSQL_TYPE_SHORT:
{
mBind->buffer_length = sizeof(Int16);
} break;
case MYSQL_TYPE_INT24:
case MYSQL_TYPE_LONG:
{
mBind->buffer_length = sizeof(Int32);
} break;
case MYSQL_TYPE_LONGLONG:
{
mBind->buffer_length = sizeof(Int64);
} break;
case MYSQL_TYPE_FLOAT:
{
mBind->buffer_length = sizeof(Float32);
} break;
case MYSQL_TYPE_DOUBLE:
{
mBind->buffer_length = sizeof(Float64);
} break;
case MYSQL_TYPE_NEWDATE:
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_TIME:
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_TIMESTAMP:
{
mBind->buffer = &mTime;
} break;
case MYSQL_TYPE_DECIMAL:
case MYSQL_TYPE_NEWDECIMAL:
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_ENUM:
case MYSQL_TYPE_VARCHAR:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
{
// Allocate a buffer to match the field size
mData.Adjust(field.max_length);
// Assign the buffer as the new bind point buffer
mBind->buffer = mData.Data();
// Assign the buffer size as the new bind point size
mBind->buffer_length = mData.Capacity();
} break;
default: STHROWF("Unknown MySQL field type");
}
}
// ------------------------------------------------------------------------------------------------
ResHnd::Handle::Handle(const ConnHnd & conn)
: mPtr(mysql_store_result(conn))
, mRef(1)
, mFieldCount(0)
, mLengths(nullptr)
, mFields(nullptr)
, mBinds(nullptr)
, mMyBinds(nullptr)
, mRow(nullptr)
, mStatement()
, mIndexes()
{
// Did this query return any results?
if (!mPtr)
{
return; // We're done here!
}
// Obtain the number of fields in the result set
mFieldCount = mysql_num_fields(mPtr);
// 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)
{
mIndexes[mFields[i].name] = i;
}
}
// ------------------------------------------------------------------------------------------------
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()
{
// Validate the given statement handle
mStatement.Validate();
// 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)
{
THROW_CURRENT(mStatement, "Cannot apply statement attribute");
}
// Attempt to buffer the complete result set on the client
if (mysql_stmt_store_result(mStatement))
{
THROW_CURRENT(mStatement, "Cannot buffer 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
mFields = mysql_fetch_fields(mPtr);
// Are there any fields to allocate
if (mFieldCount > 0)
{
// Allocate the bind wrappers
mBinds = new Bind[mFieldCount];
// Allocate the bind points
mMyBinds = new BindType[mFieldCount];
// Allocate the row pointers
mRow = new CStr[mFieldCount];
// Initialize the bind points to null
std::memset(mMyBinds, 0, sizeof(BindType) * mFieldCount);
}
// Configure bind points and make associations
for (Uint32 i = 0; i < mFieldCount; ++i)
{
// Associate the current field name with the current index
mIndexes[mFields[i].name] = i;
// Configure the current bind point according to the associated field
mBinds[i].SetOutput(mFields[i], &mMyBinds[i]);
// Store the bind point buffer into the associated row
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)
{
THROW_CURRENT(mStatement, "Cannot bind 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

View File

@ -0,0 +1,409 @@
#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

@ -0,0 +1,198 @@
// ------------------------------------------------------------------------------------------------
#include "Handle/Statement.hpp"
// ------------------------------------------------------------------------------------------------
#include <cstdio>
#include <cstring>
#include <cstdlib>
// ------------------------------------------------------------------------------------------------
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)
{
// Associate the library bind point with our bind wrapper
mBind = bind;
// Assign the 64 bit unsigned integer as the default buffer
mBind->buffer = &mUint64;
// Match the bind point type to the one from the field
mBind->buffer_type = type;
// Default to n empty buffer until type identification
mBind->buffer_length = 0;
// Allow the library to specify whether the value is null
mBind->is_null = &mIsNull;
// Allow the library to specify if errors occurred
mBind->error = &mError;
// Tell the library where to read the buffer size
mBind->length = &(mBind->buffer_length);
// Identify and configure the parameter type
switch (type)
{
case MYSQL_TYPE_NULL:
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_BIT:
{
mBind->buffer_length = 1;
} break;
case MYSQL_TYPE_YEAR:
case MYSQL_TYPE_SHORT:
{
mBind->buffer_length = sizeof(Int16);
} break;
case MYSQL_TYPE_INT24:
case MYSQL_TYPE_LONG:
{
mBind->buffer_length = sizeof(Int32);
} break;
case MYSQL_TYPE_LONGLONG:
{
mBind->buffer_length = sizeof(Int64);
} break;
case MYSQL_TYPE_FLOAT:
{
mBind->buffer_length = sizeof(Float32);
} break;
case MYSQL_TYPE_DOUBLE:
{
mBind->buffer_length = sizeof(Float64);
} break;
case MYSQL_TYPE_NEWDATE:
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_TIME:
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_TIMESTAMP:
{
mBind->buffer = &mTime;
} break;
case MYSQL_TYPE_DECIMAL:
case MYSQL_TYPE_NEWDECIMAL:
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_ENUM:
case MYSQL_TYPE_VARCHAR:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
{
// Allocate a buffer to match the specified size
mData.Adjust(length);
// Should we copy anything into the buffer?
if (buffer)
{
mData.Append(buffer, length);
}
// Assign the buffer as the new bind point buffer
mBind->buffer = mData.Data();
// Assign the buffer cursor position as the new bind point size
mBind->buffer_length = mData.Position();
} break;
default: STHROWF("Unknown MySQL parameter type");
}
}
// ------------------------------------------------------------------------------------------------
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(""))
{
// 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);
}
// ------------------------------------------------------------------------------------------------
StmtHnd::Handle::~Handle()
{
// Should delete native bindings?
if (mMyBinds)
{
delete [] mMyBinds;
}
// Should we delete binding wrappers?
if (mBinds)
{
delete [] mBinds;
}
// Should we release any statement?
if (mPtr)
{
mysql_stmt_close(mPtr);
}
}
// ------------------------------------------------------------------------------------------------
} // Namespace:: SqMod

View File

@ -0,0 +1,441 @@
#ifndef _SQMYSQL_HANDLE_STATEMENT_HPP_
#define _SQMYSQL_HANDLE_STATEMENT_HPP_
// ------------------------------------------------------------------------------------------------
#include "Handle/Connection.hpp"
// ------------------------------------------------------------------------------------------------
#include <Base/Buffer.hpp>
// ------------------------------------------------------------------------------------------------
namespace SqMod {
/* ------------------------------------------------------------------------------------------------
* Manages a reference counted statement handle.
*/
class StmtHnd
{
// --------------------------------------------------------------------------------------------
friend class Connection;
friend class Statement;
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 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.
/* --------------------------------------------------------------------------------------------
* 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)
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Copy 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;
}
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~StmtHnd()
{
Drop();
}
/* --------------------------------------------------------------------------------------------
* Copy assignment operator.
*/
StmtHnd & operator = (const StmtHnd & o)
{
if (m_Hnd != o.m_Hnd)
{
Drop();
m_Hnd = o.m_Hnd;
Grab();
}
return *this;
}
/* --------------------------------------------------------------------------------------------
* Move assignment operator.
*/
StmtHnd & operator = (StmtHnd && o)
{
if (m_Hnd != o.m_Hnd)
{
m_Hnd = o.m_Hnd;
o.m_Hnd = nullptr;
}
return *this;
}
/* --------------------------------------------------------------------------------------------
* Status assignment operator.
*/
StmtHnd & operator = (Uint32 status)
{
if (m_Hnd)
{
m_Hnd->mErrNo = status;
}
return *this;
}
/* --------------------------------------------------------------------------------------------
* Perform an equality comparison between two statement handles.
*/
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;
}
};
} // Namespace:: SqMod
#endif // _SQMYSQL_HANDLE_STATEMENT_HPP_