From 03237f9c152fa5061c54d2e07c60298507dced5f Mon Sep 17 00:00:00 2001 From: Sandu Liviu Catalin Date: Tue, 28 Jun 2016 01:15:31 +0300 Subject: [PATCH] Partial and untested revision of the MySQL module. --- cbp/ModMySQL.cbp | 6 +- cbp/default.workspace | 2 +- modules/mysql/Account.cpp | 44 ++ modules/mysql/Common.hpp | 31 +- modules/mysql/Connection.cpp | 209 +++---- modules/mysql/Connection.hpp | 289 +++++----- modules/mysql/Handle/Connection.cpp | 147 ++--- modules/mysql/Handle/Connection.hpp | 364 ++----------- modules/mysql/Handle/Result.hpp | 409 -------------- .../Handle/{Result.cpp => ResultSet.cpp} | 270 +++++---- modules/mysql/Handle/ResultSet.hpp | 209 +++++++ modules/mysql/Handle/Statement.cpp | 210 ++++--- modules/mysql/Handle/Statement.hpp | 514 +++++------------- modules/mysql/Module.cpp | 6 + modules/mysql/ResultSet.cpp | 158 ++++-- modules/mysql/ResultSet.hpp | 101 +++- modules/mysql/Statement.cpp | 276 ++++++---- modules/mysql/Statement.hpp | 101 +++- 18 files changed, 1599 insertions(+), 1747 deletions(-) delete mode 100644 modules/mysql/Handle/Result.hpp rename modules/mysql/Handle/{Result.cpp => ResultSet.cpp} (56%) create mode 100644 modules/mysql/Handle/ResultSet.hpp diff --git a/cbp/ModMySQL.cbp b/cbp/ModMySQL.cbp index 4a9f67de..52d572fa 100644 --- a/cbp/ModMySQL.cbp +++ b/cbp/ModMySQL.cbp @@ -448,8 +448,8 @@ - - + + @@ -461,6 +461,8 @@ + + diff --git a/cbp/default.workspace b/cbp/default.workspace index 96a5c598..f59c0a67 100644 --- a/cbp/default.workspace +++ b/cbp/default.workspace @@ -8,8 +8,8 @@ - + diff --git a/modules/mysql/Account.cpp b/modules/mysql/Account.cpp index 528919d8..c62d5a08 100644 --- a/modules/mysql/Account.cpp +++ b/modules/mysql/Account.cpp @@ -202,4 +202,48 @@ Connection Account::Connect() const return Connection(*this); } +// ================================================================================================ +void Register_Account(Table & sqlns) +{ + sqlns.Bind(_SC("Account") + , Class< Account >(sqlns.GetVM(), _SC("SqMySQLAccount")) + // Constructors + .Ctor< const Account & >() + .Ctor< CSStr, CSStr >() + .Ctor< CSStr, CSStr, CSStr >() + .Ctor< CSStr, CSStr, CSStr, CSStr >() + .Ctor< CSStr, CSStr, CSStr, CSStr, SQInteger >() + .Ctor< CSStr, CSStr, CSStr, CSStr, SQInteger, CSStr >() + // Core Meta-methods + .Func(_SC("_cmp"), &Account::Cmp) + .SquirrelFunc(_SC("_typename"), &Account::Typename) + .Func(_SC("_tostring"), &Account::ToString) + // Properties + .Prop(_SC("Port"), &Account::GetPortNum, &Account::SetPortNum) + .Prop(_SC("Host"), &Account::GetHost, &Account::SetHost) + .Prop(_SC("User"), &Account::GetUser, &Account::SetUser) + .Prop(_SC("Pass"), &Account::GetPass, &Account::SetPass) + .Prop(_SC("Socket"), &Account::GetSocket, &Account::SetSocket) + .Prop(_SC("Flags"), &Account::GetFlags, &Account::SetFlags) + .Prop(_SC("SSL_Key"), &Account::GetSSL_Key, &Account::SetSSL_Key) + .Prop(_SC("SSL_Cert"), &Account::GetSSL_Cert, &Account::SetSSL_Cert) + .Prop(_SC("SSL_CA"), &Account::GetSSL_CA, &Account::SetSSL_CA) + .Prop(_SC("SSL_CA_Path"), &Account::GetSSL_CA_Path, &Account::SetSSL_CA_Path) + .Prop(_SC("SSL_Cipher"), &Account::GetSSL_Cipher, &Account::SetSSL_Cipher) + .Prop(_SC("AutoCommit"), &Account::GetAutoCommit, &Account::SetAutoCommit) + .Prop(_SC("Options"), &Account::GetOptionsTable) + .Prop(_SC("OptionsCount"), &Account::OptionsCount) + .Prop(_SC("OptionsEmpty"), &Account::OptionsEmpty) + // Member Methods + .Func(_SC("EnableFlags"), &Account::EnableFlags) + .Func(_SC("DisableFlags"), &Account::DisableFlags) + .Func(_SC("SetSSL"), &Account::SetSSL) + .Func(_SC("GetOption"), &Account::GetOption) + .Func(_SC("SetOption"), &Account::SetOption) + .Func(_SC("RemoveOption"), &Account::RemoveOption) + .Func(_SC("OptionsClear"), &Account::OptionsClear) + .Func(_SC("Connect"), &Account::Connect) + ); +} + } // Namespace:: SqMod diff --git a/modules/mysql/Common.hpp b/modules/mysql/Common.hpp index d710788b..5b6945e2 100644 --- a/modules/mysql/Common.hpp +++ b/modules/mysql/Common.hpp @@ -27,16 +27,32 @@ namespace SqMod { * Handle validation. */ #if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) - #define THROW_CURRENT(x, a) x.GetHnd().ThrowCurrent(a, __FILE__, __LINE__) - #define THROW_CURRENT_HND(x, a) x.ThrowCurrent(a, __FILE__, __LINE__) + #define SQMOD_THROW_CURRENT(x, a) (x).ThrowCurrent(a, __FILE__, __LINE__) + #define SQMOD_VALIDATE(x) (x).Validate(__FILE__, __LINE__) + #define SQMOD_VALIDATE_CREATED(x) (x).ValidateCreated(__FILE__, __LINE__) + #define SQMOD_VALIDATE_PARAM(x, i) (x).ValidateParam((i), __FILE__, __LINE__) + #define SQMOD_VALIDATE_FIELD(x, i) (x).ValidateField((i), __FILE__, __LINE__) + #define SQMOD_GET_VALID(x) (x).GetValid(__FILE__, __LINE__) + #define SQMOD_GET_CREATED(x) (x).GetCreated(__FILE__, __LINE__) #else - #define THROW_CURRENT(x, a) x.GetHnd().ThrowCurrent(a) - #define THROW_CURRENT_HND(x, a) x.ThrowCurrent(a) + #define SQMOD_THROW_CURRENT(x, a) (x).ThrowCurrent(a) + #define SQMOD_VALIDATE(x) (x).Validate() + #define SQMOD_VALIDATE_CREATED(x) (x).ValidateCreated() + #define SQMOD_VALIDATE_PARAM(x, i) (x).ValidateParam((i)) + #define SQMOD_VALIDATE_FIELD(x, i) (x).ValidateField((i)) + #define SQMOD_VALIDATE_ROW(x) (x).ValidateRow() + #define SQMOD_GET_VALID(x) (x).GetValid() + #define SQMOD_GET_CREATED(x) (x).GetCreated() #endif // _DEBUG /* ------------------------------------------------------------------------------------------------ * Forward declarations. */ +struct ConnHnd; +struct StmtHnd; +struct ResHnd; + +// ------------------------------------------------------------------------------------------------ class Account; class Column; class Connection; @@ -44,6 +60,13 @@ class ResultSet; class Statement; class Transaction; +/* ------------------------------------------------------------------------------------------------ + * Common typedefs. +*/ +typedef SharedPtr< ConnHnd > ConnRef; +typedef SharedPtr< StmtHnd > StmtRef; +typedef SharedPtr< ResHnd > ResRef; + /* ------------------------------------------------------------------------------------------------ * Replicate the values of a script Date type to a database time type. */ diff --git a/modules/mysql/Connection.cpp b/modules/mysql/Connection.cpp index 4fc1d064..bc03103d 100644 --- a/modules/mysql/Connection.cpp +++ b/modules/mysql/Connection.cpp @@ -1,5 +1,6 @@ // ------------------------------------------------------------------------------------------------ #include "Connection.hpp" +#include "Account.hpp" #include "Statement.hpp" #include "ResultSet.hpp" #include "Transaction.hpp" @@ -19,151 +20,119 @@ SQInteger Connection::Typename(HSQUIRRELVM vm) } // ------------------------------------------------------------------------------------------------ -Int32 Connection::Cmp(const Connection & o) const +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +void Connection::Validate(CCStr file, Int32 line) const { - if (m_Handle == o.m_Handle) + if (!m_Handle) { - return 0; - } - else if (m_Handle.HndPtr() > o.m_Handle.HndPtr()) - { - return 1; - } - else - { - return -1; + SqThrowF("Invalid MySQL connection reference =>[%s:%d]", file, line); } } +#else +void Connection::Validate() const +{ + if (!m_Handle) + { + SqThrowF("Invalid MySQL connection reference"); + } +} +#endif // _DEBUG // ------------------------------------------------------------------------------------------------ -CSStr Connection::ToString() const +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +void Connection::ValidateCreated(CCStr file, Int32 line) const { - // Do we have a valid handle? - if (m_Handle) + if (!m_Handle) { - ToStringF("%s:%s@%s:%u", m_Handle->mUser.c_str(), m_Handle->mPass.c_str(), - m_Handle->mHost.c_str(), m_Handle->mPort); + SqThrowF("Invalid MySQL connection reference =>[%s:%d]", file, line); } - // Default to an empty string - return _SC(""); -} - -// ------------------------------------------------------------------------------------------------ -SQInteger Connection::GetErrNo() const -{ - // Validate the managed handle - m_Handle.Validate(); - // Return the requested information - return static_cast< SQInteger >(mysql_errno(m_Handle)); -} - -// ------------------------------------------------------------------------------------------------ -CSStr Connection::GetErrStr() const -{ - // Validate the managed handle - m_Handle.Validate(); - // Return the requested information - return mysql_error(m_Handle); -} - -// ------------------------------------------------------------------------------------------------ -void Connection::SetName(CSStr name) -{ - // Validate the managed handle - m_Handle.Validate(); - // Attempt to select the database with the given name - if (mysql_select_db(m_Handle, name) != 0) + else if (m_Handle->mPtr == nullptr) { - THROW_CURRENT(m_Handle, "Cannot select database"); - } - // Remember the database name - m_Handle->mName.assign(name); -} - -// ------------------------------------------------------------------------------------------------ -void Connection::SetCharset(CSStr charset) -{ - // Validate the managed handle - m_Handle.Validate(); - // Attempt to Set the default character set for the managed connection - if (mysql_set_character_set(m_Handle, charset) != 0) - { - THROW_CURRENT(m_Handle, "Cannot apply character set"); - } - // Remember the character set - m_Handle->mCharset.assign(charset); -} - -// ------------------------------------------------------------------------------------------------ -void Connection::SetAutoCommit(bool toggle) -{ - // Validate the managed handle - m_Handle.Validate(); - // Attempt to toggle auto-commit if necessary - if (m_Handle->mAutoCommit != toggle && mysql_autocommit(m_Handle, toggle) != 0) - { - THROW_CURRENT(m_Handle, "Cannot toggle auto-commit"); - } - else - { - m_Handle->mAutoCommit = toggle; + SqThrowF("Invalid MySQL connection =>[%s:%d]", file, line); } } +#else +void Connection::ValidateCreated() const +{ + if (!m_Handle) + { + SqThrowF("Invalid MySQL connection reference"); + } + else if (m_Handle->mPtr == nullptr) + { + SqThrowF("Invalid MySQL connection"); + } +} +#endif // _DEBUG // ------------------------------------------------------------------------------------------------ -Object Connection::Execute(CSStr query) +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +const ConnRef & Connection::GetValid(CCStr file, Int32 line) const { - // Validate the managed handle - m_Handle.Validate(); - // Perform the requested operation - return MakeULongObj(m_Handle->Execute(query)); + Validate(file, line); + return m_Handle; } +#else +const ConnRef & Connection::GetValid() const +{ + Validate(); + return m_Handle; +} +#endif // _DEBUG + +// ------------------------------------------------------------------------------------------------ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +const ConnRef & Connection::GetCreated(CCStr file, Int32 line) const +{ + ValidateCreated(file, line); + return m_Handle; +} +#else +const ConnRef & Connection::GetCreated() const +{ + ValidateCreated(); + return m_Handle; +} +#endif // _DEBUG // ------------------------------------------------------------------------------------------------ Object Connection::Insert(CSStr query) { - // Validate the managed handle - m_Handle.Validate(); // Make sure the specified query is valid if (!query || *query == '\0') { STHROWF("Invalid or empty MySQL query"); } // Attempt to execute the specified query - else if (mysql_real_query(m_Handle, query, std::strlen(query)) != 0) + else if (mysql_real_query(SQMOD_GET_CREATED(*this)->mPtr, query, std::strlen(query)) != 0) { - THROW_CURRENT(m_Handle, "Unable to execute query"); + SQMOD_THROW_CURRENT(*m_Handle, "Unable to execute MySQL query"); } // Return the identifier of the inserted row - return MakeULongObj(mysql_insert_id(m_Handle)); + return MakeULongObj(mysql_insert_id(m_Handle->mPtr)); } // ------------------------------------------------------------------------------------------------ ResultSet Connection::Query(CSStr query) { - // Validate the managed handle - m_Handle.Validate(); // Make sure the specified query is valid if (!query || *query == '\0') { STHROWF("Invalid or empty MySQL query"); } // Attempt to execute the specified query - else if (mysql_real_query(m_Handle, query, std::strlen(query)) != 0) + else if (mysql_real_query(SQMOD_GET_CREATED(*this)->mPtr, query, std::strlen(query)) != 0) { - THROW_CURRENT(m_Handle, "Unable to execute query"); + SQMOD_THROW_CURRENT(*m_Handle, "Unable to execute MySQL query"); } // Return the identifier of the inserted row - return ResultSet(ResHnd(m_Handle)); + return ResultSet(m_Handle); } // ------------------------------------------------------------------------------------------------ Statement Connection::GetStatement(CSStr query) { - // Validate the managed handle - m_Handle.Validate(); - // Return the requested information - return Statement(m_Handle, query); + return Statement(SQMOD_GET_CREATED(*this), query); } // ------------------------------------------------------------------------------------------------ @@ -172,4 +141,50 @@ Transaction Connection::GetTransaction() return Transaction(); } +// ================================================================================================ +void Register_Connection(Table & sqlns) +{ + sqlns.Bind(_SC("Connection") + , Class< Connection >(sqlns.GetVM(), _SC("SqMySQLConnection")) + // Constructors + .Ctor() + .Ctor< const Account & >() + // Core Meta-methods + .Func(_SC("_cmp"), &Connection::Cmp) + .SquirrelFunc(_SC("_typename"), &Connection::Typename) + .Func(_SC("_tostring"), &Connection::ToString) + // Properties + .Prop(_SC("IsValid"), &Connection::IsValid) + .Prop(_SC("Connected"), &Connection::IsConnected) + .Prop(_SC("References"), &Connection::GetRefCount) + .Prop(_SC("ErrNo"), &Connection::GetErrNo) + .Prop(_SC("ErrStr"), &Connection::GetErrStr) + .Prop(_SC("LastErrNo"), &Connection::GetLastErrNo) + .Prop(_SC("LastErrStr"), &Connection::GetLastErrStr) + .Prop(_SC("Port"), &Connection::GetPortNum) + .Prop(_SC("Host"), &Connection::GetHost) + .Prop(_SC("User"), &Connection::GetUser) + .Prop(_SC("Pass"), &Connection::GetPass) + .Prop(_SC("Name"), &Connection::GetName, &Connection::SetName) + .Prop(_SC("Socket"), &Connection::GetSocket) + .Prop(_SC("Flags"), &Connection::GetFlags) + .Prop(_SC("SSL_Key"), &Connection::GetSSL_Key) + .Prop(_SC("SSL_Cert"), &Connection::GetSSL_Cert) + .Prop(_SC("SSL_CA"), &Connection::GetSSL_CA) + .Prop(_SC("SSL_CA_Path"), &Connection::GetSSL_CA_Path) + .Prop(_SC("SSL_Cipher"), &Connection::GetSSL_Cipher) + .Prop(_SC("Charset"), &Connection::GetCharset, &Connection::SetCharset) + .Prop(_SC("AutoCommit"), &Connection::GetAutoCommit, &Connection::SetAutoCommit) + .Prop(_SC("InTransaction"), &Connection::GetInTransaction) + // Member Methods + .Func(_SC("Disconnect"), &Connection::Disconnect) + .Func(_SC("SelectDb"), &Connection::SetName) + .Func(_SC("Execute"), &Connection::Execute) + .Func(_SC("Insert"), &Connection::Insert) + .Func(_SC("Query"), &Connection::Query) + .Func(_SC("Statement"), &Connection::GetStatement) + .Func(_SC("Transaction"), &Connection::GetTransaction) + ); +} + } // Namespace:: SqMod diff --git a/modules/mysql/Connection.hpp b/modules/mysql/Connection.hpp index a05b980f..c658596d 100644 --- a/modules/mysql/Connection.hpp +++ b/modules/mysql/Connection.hpp @@ -15,7 +15,45 @@ class Connection private: // -------------------------------------------------------------------------------------------- - ConnHnd m_Handle; // Handle to the actual database connection. + ConnRef m_Handle; // Reference to the actual database connection. + +protected: + + /* -------------------------------------------------------------------------------------------- + * Validate the managed connection handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + void Validate(CCStr file, Int32 line) const; +#else + void Validate() const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the managed connection handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + void ValidateCreated(CCStr file, Int32 line) const; +#else + void ValidateCreated() const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the managed connection handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + const ConnRef & GetValid(CCStr file, Int32 line) const; +#else + const ConnRef & GetValid() const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the managed connection handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + const ConnRef & GetCreated(CCStr file, Int32 line) const; +#else + const ConnRef & GetCreated() const; +#endif // _DEBUG public: @@ -32,15 +70,15 @@ public: * Base constructor. */ Connection(const Account & acc) - : m_Handle(acc) + : m_Handle(new ConnHnd()) { - /* ... */ + m_Handle->Create(acc); } /* -------------------------------------------------------------------------------------------- * Base constructor. */ - Connection(const ConnHnd & conn) + Connection(const ConnRef & conn) : m_Handle(conn) { /* ... */ @@ -56,14 +94,6 @@ public: */ Connection(Connection && o) = default; - /* -------------------------------------------------------------------------------------------- - * Destructor. - */ - ~Connection() - { - // Let the handle deal with closing the connection if necessary - } - /* -------------------------------------------------------------------------------------------- * Copy assignment operator. */ @@ -77,18 +107,43 @@ public: /* -------------------------------------------------------------------------------------------- * Used by the script engine to compare two instances of this type. */ - Int32 Cmp(const Connection & o) const; + Int32 Cmp(const Connection & o) const + { + if (m_Handle.Get() == o.m_Handle.Get()) + { + return 0; + } + else if (m_Handle.Get() > o.m_Handle.Get()) + { + return 1; + } + else + { + return -1; + } + } /* -------------------------------------------------------------------------------------------- * Used by the script engine to convert an instance of this type to a string. */ - CSStr ToString() const; + CSStr ToString() const + { + return m_Handle ? mysql_get_host_info(m_Handle->mPtr) : _SC(""); + } /* -------------------------------------------------------------------------------------------- * Used by the script engine to retrieve the name from instances of this type. */ static SQInteger Typename(HSQUIRRELVM vm); + /* -------------------------------------------------------------------------------------------- + * Retrieve the associated connection handle. + */ + const ConnRef & GetHandle() const + { + return m_Handle; + } + /* -------------------------------------------------------------------------------------------- * See whether the managed handle is valid. */ @@ -98,80 +153,43 @@ public: } /* -------------------------------------------------------------------------------------------- - * Validate the managed connection handle and throw exception if it doesn't exist. + * See whether the managed connection handle was connected. */ - void Validate() const; - - /* -------------------------------------------------------------------------------------------- - * Implicit conversion to the managed connection handle. - */ - operator ConnHnd & () + bool IsConnected() const { - return m_Handle; + return m_Handle && (m_Handle->mPtr != nullptr); } /* -------------------------------------------------------------------------------------------- - * Implicit conversion to the managed connection handle. + * Return the number of active references to this connection handle. */ - operator const ConnHnd & () const + Uint32 GetRefCount() const { - return m_Handle; - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the managed connection handle. - */ - ConnHnd & GetHnd() - { - return m_Handle; - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the managed connection handle. - */ - const ConnHnd & GetHnd() const - { - return m_Handle; - } - - /* -------------------------------------------------------------------------------------------- - * See whether a successful connection was made or not. - */ - bool Connected() const - { - return m_Handle; - } - - /* -------------------------------------------------------------------------------------------- - * Disconnect from the currently connected database. - */ - void Disconnect() - { - // Validate the managed handle - m_Handle.Validate(); - // Perform the requested operation - m_Handle->Disconnect(); + return m_Handle.Count(); } /* -------------------------------------------------------------------------------------------- * Retrieve the current error number. */ - SQInteger GetErrNo() const; + SQInteger GetErrNo() const + { + return static_cast< SQInteger >(mysql_errno(SQMOD_GET_CREATED(*this)->mPtr)); + } /* -------------------------------------------------------------------------------------------- * Retrieve the current error message. */ - CSStr GetErrStr() const; + CSStr GetErrStr() const + { + return mysql_error(SQMOD_GET_CREATED(*this)->mPtr); + } /* -------------------------------------------------------------------------------------------- * Retrieve the last received error number. */ SQInteger GetLastErrNo() const { - // Validate the managed handle - m_Handle.Validate(); - // Return the requested information - return static_cast< SQInteger >(m_Handle->mErrNo); + return static_cast< SQInteger >(SQMOD_GET_VALID(*this)->mErrNo); } /* -------------------------------------------------------------------------------------------- @@ -179,10 +197,7 @@ public: */ const String & GetLastErrStr() const { - // Validate the managed handle - m_Handle.Validate(); - // Return the requested information - return m_Handle->mErrStr; + return SQMOD_GET_VALID(*this)->mErrStr; } /* -------------------------------------------------------------------------------------------- @@ -190,10 +205,7 @@ public: */ SQInteger GetPortNum() const { - // Validate the managed handle - m_Handle.Validate(); - // Return the requested information - return static_cast< SQInteger >(m_Handle->mPort); + return static_cast< SQInteger >(SQMOD_GET_VALID(*this)->mPort); } /* -------------------------------------------------------------------------------------------- @@ -201,10 +213,7 @@ public: */ const String & GetHost() const { - // Validate the managed handle - m_Handle.Validate(); - // Return the requested information - return m_Handle->mHost; + return SQMOD_GET_VALID(*this)->mHost; } /* -------------------------------------------------------------------------------------------- @@ -212,10 +221,7 @@ public: */ const String & GetUser() const { - // Validate the managed handle - m_Handle.Validate(); - // Return the requested information - return m_Handle->mUser; + return SQMOD_GET_VALID(*this)->mUser; } /* -------------------------------------------------------------------------------------------- @@ -223,10 +229,7 @@ public: */ const String & GetPass() const { - // Validate the managed handle - m_Handle.Validate(); - // Return the requested information - return m_Handle->mPass; + return SQMOD_GET_VALID(*this)->mPass; } /* -------------------------------------------------------------------------------------------- @@ -234,26 +237,34 @@ public: */ const String & GetName() const { - // Validate the managed handle - m_Handle.Validate(); - // Return the requested information - return m_Handle->mName; + return SQMOD_GET_VALID(*this)->mName; } /* -------------------------------------------------------------------------------------------- * Modify the selected database name. */ - void SetName(CSStr name); + void SetName(CSStr name) + { + // Validate the specified name + if (!name) + { + STHROWF("Invalid MySQL database name"); + } + // Attempt to select the database with the given name + else if (mysql_select_db(SQMOD_GET_CREATED(*this)->mPtr, name) != 0) + { + SQMOD_THROW_CURRENT(*m_Handle, "Cannot select MySQL database"); + } + // Remember the database name + m_Handle->mName.assign(name); + } /* -------------------------------------------------------------------------------------------- * Retrieve the connection socket. */ const String & GetSocket() const { - // Validate the managed handle - m_Handle.Validate(); - // Return the requested information - return m_Handle->mSocket; + return SQMOD_GET_VALID(*this)->mSocket; } /* -------------------------------------------------------------------------------------------- @@ -261,10 +272,7 @@ public: */ SQInteger GetFlags() const { - // Validate the managed handle - m_Handle.Validate(); - // Return the requested information - return static_cast< SQInteger >(m_Handle->mFlags); + return static_cast< SQInteger >(SQMOD_GET_VALID(*this)->mFlags); } /* -------------------------------------------------------------------------------------------- @@ -272,10 +280,7 @@ public: */ const String & GetSSL_Key() const { - // Validate the managed handle - m_Handle.Validate(); - // Return the requested information - return m_Handle->mSSL_Key; + return SQMOD_GET_VALID(*this)->mSSL_Key; } /* -------------------------------------------------------------------------------------------- @@ -283,10 +288,7 @@ public: */ const String & GetSSL_Cert() const { - // Validate the managed handle - m_Handle.Validate(); - // Return the requested information - return m_Handle->mSSL_Cert; + return SQMOD_GET_VALID(*this)->mSSL_Cert; } /* -------------------------------------------------------------------------------------------- @@ -294,10 +296,7 @@ public: */ const String & GetSSL_CA() const { - // Validate the managed handle - m_Handle.Validate(); - // Return the requested information - return m_Handle->mSSL_CA; + return SQMOD_GET_VALID(*this)->mSSL_CA; } /* -------------------------------------------------------------------------------------------- @@ -305,10 +304,7 @@ public: */ const String & GetSSL_CA_Path() const { - // Validate the managed handle - m_Handle.Validate(); - // Return the requested information - return m_Handle->mSSL_CA_Path; + return SQMOD_GET_VALID(*this)->mSSL_CA_Path; } /* -------------------------------------------------------------------------------------------- @@ -316,10 +312,7 @@ public: */ const String & GetSSL_Cipher() const { - // Validate the managed handle - m_Handle.Validate(); - // Return the requested information - return m_Handle->mSSL_Cipher; + return SQMOD_GET_VALID(*this)->mSSL_Cipher; } /* -------------------------------------------------------------------------------------------- @@ -327,48 +320,76 @@ public: */ const String & GetCharset() const { - // Validate the managed handle - m_Handle.Validate(); - // Return the requested information - return m_Handle->mCharset; + return SQMOD_GET_VALID(*this)->mCharset; } /* -------------------------------------------------------------------------------------------- * Modify the default character set for the managed connection. */ - void SetCharset(CSStr charset); + void SetCharset(CSStr charset) + { + // Validate the specified string + if (!charset) + { + STHROWF("Invalid charset string"); + } + // Attempt to Set the default character set for the managed connection + else if (mysql_set_character_set(SQMOD_GET_CREATED(*this)->mPtr, charset) != 0) + { + SQMOD_THROW_CURRENT(*m_Handle, "Cannot apply character set"); + } + // Remember the character set + m_Handle->mCharset.assign(charset); + } /* -------------------------------------------------------------------------------------------- * See whether auto-commit is enabled or not. */ bool GetAutoCommit() const { - // Validate the managed handle - m_Handle.Validate(); - // Return the requested information - return m_Handle->mAutoCommit; + return SQMOD_GET_VALID((*this))->mAutoCommit; } /* -------------------------------------------------------------------------------------------- * Set whether auto-commit should be enabled or not. */ - void SetAutoCommit(bool toggle); + void SetAutoCommit(bool toggle) + { + // Attempt to toggle auto-commit if necessary + if (SQMOD_GET_CREATED(*this)->mAutoCommit != toggle && + mysql_autocommit(m_Handle->mPtr, toggle) != 0) + { + SQMOD_THROW_CURRENT(*m_Handle, "Cannot toggle auto-commit"); + } + else + { + m_Handle->mAutoCommit = toggle; + } + } /* -------------------------------------------------------------------------------------------- * See whether the connection is in the middle of a transaction. */ bool GetInTransaction() const { - // Validate the managed handle - m_Handle.Validate(); - // Return the requested information - return m_Handle->mInTransaction; + return SQMOD_GET_VALID(*this)->mInTransaction; + } + + /* -------------------------------------------------------------------------------------------- + * Disconnect from the currently connected database. + */ + void Disconnect() + { + SQMOD_GET_CREATED(*this)->Disconnect(); } /* -------------------------------------------------------------------------------------------- * Execute a query on the server. */ - Object Execute(CSStr query); + Object Execute(CSStr query) + { + return MakeULongObj(SQMOD_GET_CREATED(*this)->Execute(query)); + } /* -------------------------------------------------------------------------------------------- * Execute a query on the server. diff --git a/modules/mysql/Handle/Connection.cpp b/modules/mysql/Handle/Connection.cpp index 5ca7ae33..572bbd64 100644 --- a/modules/mysql/Handle/Connection.cpp +++ b/modules/mysql/Handle/Connection.cpp @@ -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 \ No newline at end of file diff --git a/modules/mysql/Handle/Connection.hpp b/modules/mysql/Handle/Connection.hpp index a39b1022..afe2ce0a 100644 --- a/modules/mysql/Handle/Connection.hpp +++ b/modules/mysql/Handle/Connection.hpp @@ -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 diff --git a/modules/mysql/Handle/Result.hpp b/modules/mysql/Handle/Result.hpp deleted file mode 100644 index 3048574c..00000000 --- a/modules/mysql/Handle/Result.hpp +++ /dev/null @@ -1,409 +0,0 @@ -#ifndef _SQMYSQL_HANDLE_RESULT_HPP_ -#define _SQMYSQL_HANDLE_RESULT_HPP_ - -// ------------------------------------------------------------------------------------------------ -#include "Handle/Statement.hpp" - -// ------------------------------------------------------------------------------------------------ -#include - -// ------------------------------------------------------------------------------------------------ -#include - -// ------------------------------------------------------------------------------------------------ -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_ diff --git a/modules/mysql/Handle/Result.cpp b/modules/mysql/Handle/ResultSet.cpp similarity index 56% rename from modules/mysql/Handle/Result.cpp rename to modules/mysql/Handle/ResultSet.cpp index d2222777..072691a1 100644 --- a/modules/mysql/Handle/Result.cpp +++ b/modules/mysql/Handle/ResultSet.cpp @@ -1,5 +1,5 @@ // ------------------------------------------------------------------------------------------------ -#include "Handle/Result.hpp" +#include "Handle/ResultSet.hpp" // ------------------------------------------------------------------------------------------------ #include @@ -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 diff --git a/modules/mysql/Handle/ResultSet.hpp b/modules/mysql/Handle/ResultSet.hpp new file mode 100644 index 00000000..b0a27ae7 --- /dev/null +++ b/modules/mysql/Handle/ResultSet.hpp @@ -0,0 +1,209 @@ +#ifndef _SQMYSQL_HANDLE_RESULTSET_HPP_ +#define _SQMYSQL_HANDLE_RESULTSET_HPP_ + +// ------------------------------------------------------------------------------------------------ +#include "Handle/Statement.hpp" +#include "Base/Buffer.hpp" + +// ------------------------------------------------------------------------------------------------ +#include + +// ------------------------------------------------------------------------------------------------ +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_ diff --git a/modules/mysql/Handle/Statement.cpp b/modules/mysql/Handle/Statement.cpp index 4d0815c5..b57b1ca2 100644 --- a/modules/mysql/Handle/Statement.cpp +++ b/modules/mysql/Handle/Statement.cpp @@ -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 diff --git a/modules/mysql/Handle/Statement.hpp b/modules/mysql/Handle/Statement.hpp index b997ef64..77185796 100644 --- a/modules/mysql/Handle/Statement.hpp +++ b/modules/mysql/Handle/Statement.hpp @@ -3,22 +3,16 @@ // ------------------------------------------------------------------------------------------------ #include "Handle/Connection.hpp" - -// ------------------------------------------------------------------------------------------------ -#include +#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_ diff --git a/modules/mysql/Module.cpp b/modules/mysql/Module.cpp index 9ce2f7bf..7956b5b5 100644 --- a/modules/mysql/Module.cpp +++ b/modules/mysql/Module.cpp @@ -169,6 +169,9 @@ void UnbindCallbacks() // ------------------------------------------------------------------------------------------------ extern void Register_Account(Table & sqlns); +extern void Register_Connection(Table & sqlns); +extern void Register_ResultSet(Table & sqlns); +extern void Register_Statement(Table & sqlns); // ------------------------------------------------------------------------------------------------ void RegisterAPI(HSQUIRRELVM vm) @@ -176,6 +179,9 @@ void RegisterAPI(HSQUIRRELVM vm) Table sqlns(vm); Register_Account(sqlns); + Register_Connection(sqlns); + Register_ResultSet(sqlns); + Register_Statement(sqlns); RootTable(vm).Bind(_SC("SqMySQL"), sqlns); } diff --git a/modules/mysql/ResultSet.cpp b/modules/mysql/ResultSet.cpp index cd4270fd..b208b80d 100644 --- a/modules/mysql/ResultSet.cpp +++ b/modules/mysql/ResultSet.cpp @@ -13,39 +13,100 @@ SQInteger ResultSet::Typename(HSQUIRRELVM vm) } // ------------------------------------------------------------------------------------------------ -Int32 ResultSet::Cmp(const ResultSet & o) const +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +void ResultSet::Validate(CCStr file, Int32 line) const { - if (m_Handle == o.m_Handle) + if (!m_Handle) { - return 0; - } - else if (m_Handle.HndPtr() > o.m_Handle.HndPtr()) - { - return 1; - } - else - { - return -1; + SqThrowF("Invalid MySQL result-set reference =>[%s:%d]", file, line); } } +#else +void ResultSet::Validate() const +{ + if (!m_Handle) + { + SqThrowF("Invalid MySQL result-set reference"); + } +} +#endif // _DEBUG // ------------------------------------------------------------------------------------------------ -CSStr ResultSet::ToString() const +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +void ResultSet::ValidateCreated(CCStr file, Int32 line) const { - // Do we have a valid handle? - if (m_Handle) + if (!m_Handle) { - ToStrF("%u", m_Handle->mFieldCount); + SqThrowF("Invalid MySQL result-set reference =>[%s:%d]", file, line); + } + else if (m_Handle->mPtr == nullptr) + { + SqThrowF("Invalid MySQL result-set =>[%s:%d]", file, line); } - // Default to an empty string - return _SC(""); } +#else +void ResultSet::ValidateCreated() const +{ + if (!m_Handle) + { + SqThrowF("Invalid MySQL result-set reference"); + } + else if (m_Handle->mPtr == nullptr) + { + SqThrowF("Invalid MySQL result-set"); + } +} +#endif // _DEBUG + +// ------------------------------------------------------------------------------------------------ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +const ResRef & ResultSet::GetValid(CCStr file, Int32 line) const +{ + Validate(file, line); + return m_Handle; +} +#else +const ResRef & ResultSet::GetValid() const +{ + Validate(); + return m_Handle; +} +#endif // _DEBUG + +// ------------------------------------------------------------------------------------------------ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +const ResRef & ResultSet::GetCreated(CCStr file, Int32 line) const +{ + ValidateCreated(file, line); + return m_Handle; +} +#else +const ResRef & ResultSet::GetCreated() const +{ + ValidateCreated(); + return m_Handle; +} +#endif // _DEBUG + +// ------------------------------------------------------------------------------------------------ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +void ResultSet::ValidateField(Int32 idx, CCStr file, Int32 line) const +{ + ValidateCreated(file, line); + m_Handle->ValidateField(idx, file, line); +} +#else +void ResultSet::ValidateField(Int32 idx) const +{ + ValidateCreated(); + m_Handle->ValidateField(idx); +} +#endif // _DEBUG // ------------------------------------------------------------------------------------------------ SQInteger ResultSet::GetInt8(Uint32 idx) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_FIELD(*this, idx); // Should we retrieve the value from the bind wrapper? if (m_Handle->mStatement) { @@ -58,8 +119,7 @@ SQInteger ResultSet::GetInt8(Uint32 idx) const // ------------------------------------------------------------------------------------------------ SQInteger ResultSet::GetUint8(Uint32 idx) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_FIELD(*this, idx); // Should we retrieve the value from the bind wrapper? if (m_Handle->mStatement) { @@ -72,8 +132,7 @@ SQInteger ResultSet::GetUint8(Uint32 idx) const // ------------------------------------------------------------------------------------------------ SQInteger ResultSet::GetInt16(Uint32 idx) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_FIELD(*this, idx); // Should we retrieve the value from the bind wrapper? if (m_Handle->mStatement) { @@ -86,8 +145,7 @@ SQInteger ResultSet::GetInt16(Uint32 idx) const // ------------------------------------------------------------------------------------------------ SQInteger ResultSet::GetUint16(Uint32 idx) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_FIELD(*this, idx); // Should we retrieve the value from the bind wrapper? if (m_Handle->mStatement) { @@ -100,8 +158,7 @@ SQInteger ResultSet::GetUint16(Uint32 idx) const // ------------------------------------------------------------------------------------------------ SQInteger ResultSet::GetInt32(Uint32 idx) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_FIELD(*this, idx); // Should we retrieve the value from the bind wrapper? if (m_Handle->mStatement) { @@ -114,8 +171,7 @@ SQInteger ResultSet::GetInt32(Uint32 idx) const // ------------------------------------------------------------------------------------------------ SQInteger ResultSet::GetUint32(Uint32 idx) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_FIELD(*this, idx); // Should we retrieve the value from the bind wrapper? if (m_Handle->mStatement) { @@ -128,8 +184,7 @@ SQInteger ResultSet::GetUint32(Uint32 idx) const // ------------------------------------------------------------------------------------------------ Int64 ResultSet::GetInt64(Uint32 idx) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_FIELD(*this, idx); // Should we retrieve the value from the bind wrapper? if (m_Handle->mStatement) { @@ -142,8 +197,7 @@ Int64 ResultSet::GetInt64(Uint32 idx) const // ------------------------------------------------------------------------------------------------ Uint64 ResultSet::GetUint64(Uint32 idx) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_FIELD(*this, idx); // Should we retrieve the value from the bind wrapper? if (m_Handle->mStatement) { @@ -156,8 +210,7 @@ Uint64 ResultSet::GetUint64(Uint32 idx) const // ------------------------------------------------------------------------------------------------ SQFloat ResultSet::GetFloat32(Uint32 idx) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_FIELD(*this, idx); // Should we retrieve the value from the bind wrapper? if (m_Handle->mStatement) { @@ -170,8 +223,7 @@ SQFloat ResultSet::GetFloat32(Uint32 idx) const // ------------------------------------------------------------------------------------------------ SQFloat ResultSet::GetFloat64(Uint32 idx) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_FIELD(*this, idx); // Should we retrieve the value from the bind wrapper? if (m_Handle->mStatement) { @@ -184,8 +236,7 @@ SQFloat ResultSet::GetFloat64(Uint32 idx) const // ------------------------------------------------------------------------------------------------ bool ResultSet::GetBoolean(Uint32 idx) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_FIELD(*this, idx); // Should we retrieve the value from the bind wrapper? if (m_Handle->mStatement) { @@ -195,5 +246,34 @@ bool ResultSet::GetBoolean(Uint32 idx) const return ConvTo< bool >::From(*reinterpret_cast< Uint8 ** >(m_Handle->mRow)[idx]); } +// ================================================================================================ +void Register_ResultSet(Table & sqlns) +{ + sqlns.Bind(_SC("ResultSet") + , Class< ResultSet >(sqlns.GetVM(), _SC("SqMySQLResultSet")) + // Constructors + .Ctor() + .Ctor< const ResultSet & >() + // Core Meta-methods + .Func(_SC("_cmp"), &ResultSet::Cmp) + .SquirrelFunc(_SC("_typename"), &ResultSet::Typename) + .Func(_SC("_tostring"), &ResultSet::ToString) + // Properties + .Prop(_SC("IsValid"), &ResultSet::IsValid) + // Member Methods + .Func(_SC("GetInt8"), &ResultSet::GetInt8) + .Func(_SC("GetUint8"), &ResultSet::GetUint8) + .Func(_SC("GetInt16"), &ResultSet::GetInt16) + .Func(_SC("GetUint16"), &ResultSet::GetUint16) + .Func(_SC("GetInt32"), &ResultSet::GetInt32) + .Func(_SC("GetUint32"), &ResultSet::GetUint32) + .Func(_SC("GetInt64"), &ResultSet::GetInt64) + .Func(_SC("GetUint64"), &ResultSet::GetUint64) + .Func(_SC("GetFloat32"), &ResultSet::GetFloat32) + .Func(_SC("GetFloat64"), &ResultSet::GetFloat64) + .Func(_SC("GetBool"), &ResultSet::GetBoolean) + .Func(_SC("GetBoolean"), &ResultSet::GetBoolean) + ); +} } // Namespace:: SqMod diff --git a/modules/mysql/ResultSet.hpp b/modules/mysql/ResultSet.hpp index debfb4d7..fffc257c 100644 --- a/modules/mysql/ResultSet.hpp +++ b/modules/mysql/ResultSet.hpp @@ -2,7 +2,7 @@ #define _SQMYSQL_RESULTSET_HPP_ // ------------------------------------------------------------------------------------------------ -#include "Handle/Result.hpp" +#include "Handle/ResultSet.hpp" // ------------------------------------------------------------------------------------------------ namespace SqMod { @@ -15,7 +15,54 @@ class ResultSet private: // -------------------------------------------------------------------------------------------- - ResHnd m_Handle; // The managed result set. + ResRef m_Handle; // Reference to the actual database result-set. + +protected: + + /* -------------------------------------------------------------------------------------------- + * Validate the managed statement handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + void Validate(CCStr file, Int32 line) const; +#else + void Validate() const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the managed statement handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + void ValidateCreated(CCStr file, Int32 line) const; +#else + void ValidateCreated() const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the managed statement handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + const ResRef & GetValid(CCStr file, Int32 line) const; +#else + const ResRef & GetValid() const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the managed statement handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + const ResRef & GetCreated(CCStr file, Int32 line) const; +#else + const ResRef & GetCreated() const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the statement reference and field index, and throw an error if they're invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + void ValidateField(Int32 idx, CCStr file, Int32 line) const; +#else + void ValidateField(Int32 idx) const; +#endif // _DEBUG public: @@ -29,9 +76,27 @@ public: } /* -------------------------------------------------------------------------------------------- - * Base constructor. + * Connection constructor. */ - ResultSet(const ResHnd & hnd) + ResultSet(const ConnRef & conn) + : m_Handle(new ResHnd()) + { + m_Handle->Create(conn); + } + + /* -------------------------------------------------------------------------------------------- + * Statement constructor. + */ + ResultSet(const StmtRef & stmt) + : m_Handle(new ResHnd()) + { + m_Handle->Create(stmt); + } + + /* -------------------------------------------------------------------------------------------- + * Handle constructor. + */ + ResultSet(const ResRef & hnd) : m_Handle(hnd) { /* ... */ @@ -65,12 +130,35 @@ public: /* -------------------------------------------------------------------------------------------- * Used by the script engine to compare two instances of this type. */ - Int32 Cmp(const ResultSet & o) const; + Int32 Cmp(const ResultSet & o) const + { + if (m_Handle.Get() == o.m_Handle.Get()) + { + return 0; + } + else if (m_Handle.Get() > o.m_Handle.Get()) + { + return 1; + } + else + { + return -1; + } + } /* -------------------------------------------------------------------------------------------- * Used by the script engine to convert an instance of this type to a string. */ - CSStr ToString() const; + CSStr ToString() const + { + // Do we have a valid handle? + if (m_Handle) + { + ToStrF("%u", m_Handle->mFieldCount); + } + // Default to a negative value + return _SC("-1"); + } /* -------------------------------------------------------------------------------------------- * Used by the script engine to retrieve the name from instances of this type. @@ -139,7 +227,6 @@ public: * Retrieve a boolean from a field. */ bool GetBoolean(Uint32 idx) const; - }; } // Namespace:: SqMod diff --git a/modules/mysql/Statement.cpp b/modules/mysql/Statement.cpp index f82cd976..e098db18 100644 --- a/modules/mysql/Statement.cpp +++ b/modules/mysql/Statement.cpp @@ -19,135 +19,170 @@ SQInteger Statement::Typename(HSQUIRRELVM vm) } // ------------------------------------------------------------------------------------------------ -Int32 Statement::Cmp(const Statement & o) const +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +void Statement::Validate(CCStr file, Int32 line) const { - if (m_Handle == o.m_Handle) + if (!m_Handle) { - return 0; - } - else if (m_Handle.HndPtr() > o.m_Handle.HndPtr()) - { - return 1; - } - else - { - return -1; + SqThrowF("Invalid MySQL statement reference =>[%s:%d]", file, line); } } +#else +void Statement::Validate() const +{ + if (!m_Handle) + { + SqThrowF("Invalid MySQL statement reference"); + } +} +#endif // _DEBUG // ------------------------------------------------------------------------------------------------ -CSStr Statement::ToString() const +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +void Statement::ValidateCreated(CCStr file, Int32 line) const { - // Do we have a valid handle? - if (m_Handle) + if (!m_Handle) { - m_Handle->mQuery.c_str(); + SqThrowF("Invalid MySQL statement reference =>[%s:%d]", file, line); + } + else if (m_Handle->mPtr == nullptr) + { + SqThrowF("Invalid MySQL statement =>[%s:%d]", file, line); } - // Default to an empty string - return _SC(""); } +#else +void Statement::ValidateCreated() const +{ + if (!m_Handle) + { + SqThrowF("Invalid MySQL statement reference"); + } + else if (m_Handle->mPtr == nullptr) + { + SqThrowF("Invalid MySQL statement"); + } +} +#endif // _DEBUG // ------------------------------------------------------------------------------------------------ -Statement::Statement() - : m_Handle() +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +const StmtRef & Statement::GetValid(CCStr file, Int32 line) const { - + Validate(file, line); + return m_Handle; } +#else +const StmtRef & Statement::GetValid() const +{ + Validate(); + return m_Handle; +} +#endif // _DEBUG // ------------------------------------------------------------------------------------------------ -Statement::Statement(const ConnHnd & connection, CSStr query) - : m_Handle(connection, query) +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +const StmtRef & Statement::GetCreated(CCStr file, Int32 line) const { - + ValidateCreated(file, line); + return m_Handle; } +#else +const StmtRef & Statement::GetCreated() const +{ + ValidateCreated(); + return m_Handle; +} +#endif // _DEBUG + +// ------------------------------------------------------------------------------------------------ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +void Statement::ValidateParam(Int32 idx, CCStr file, Int32 line) const +{ + ValidateCreated(file, line); + m_Handle->ValidateParam(idx, file, line); +} +#else +void Statement::ValidateParam(Int32 idx) const +{ + ValidateCreated(); + m_Handle->ValidateParam(idx); +} +#endif // _DEBUG // ------------------------------------------------------------------------------------------------ Statement::Statement(const Connection & connection, CSStr query) - : m_Handle(connection.GetHnd(), query) + : Statement(connection.GetHandle(), query) { - + /* ... */ } // ------------------------------------------------------------------------------------------------ Connection Statement::GetConnection() const { - // Validate the managed handle - m_Handle.Validate(); - // Return the requested information - return Connection(m_Handle->mConnection); + return Connection(SQMOD_GET_VALID(*this)->mConnection); } // ------------------------------------------------------------------------------------------------ void Statement::SetConnection(const Connection & conn) { - // Validate the managed handle - m_Handle.Validate(); - // Perform the requested operation - m_Handle->mConnection = conn.GetHnd(); + SQMOD_GET_VALID(*this)->mConnection = conn.GetHandle(); } // ------------------------------------------------------------------------------------------------ Int32 Statement::Execute() { - // Validate the managed handle - m_Handle.Validate(); // Attempt to bind the parameters - if (mysql_stmt_bind_param(m_Handle, m_Handle->mMyBinds)) + if (mysql_stmt_bind_param(SQMOD_GET_CREATED(*this)->mPtr, m_Handle->mMyBinds)) { - THROW_CURRENT(m_Handle, "Cannot bind statement parameters"); + SQMOD_THROW_CURRENT(*m_Handle, "Cannot bind MySQL statement parameters"); } // Attempt to execute the statement - else if (mysql_stmt_execute(m_Handle)) + else if (mysql_stmt_execute(m_Handle->mPtr)) { - THROW_CURRENT(m_Handle, "Cannot execute statement"); + SQMOD_THROW_CURRENT(*m_Handle, "Cannot execute MySQL statement"); } // Return the number of rows affected by this query - return mysql_stmt_affected_rows(m_Handle); + return mysql_stmt_affected_rows(m_Handle->mPtr); } // ------------------------------------------------------------------------------------------------ Uint32 Statement::Insert() { - // Validate the managed handle - m_Handle.Validate(); // Attempt to bind the parameters - if (mysql_stmt_bind_param(m_Handle, m_Handle->mMyBinds)) + if (mysql_stmt_bind_param(SQMOD_GET_CREATED(*this)->mPtr, m_Handle->mMyBinds)) { - THROW_CURRENT(m_Handle, "Cannot bind statement parameters"); + SQMOD_THROW_CURRENT(*m_Handle, "Cannot bind MySQL statement parameters"); } // Attempt to execute the statement - else if (mysql_stmt_execute(m_Handle)) + else if (mysql_stmt_execute(m_Handle->mPtr)) { - THROW_CURRENT(m_Handle, "Cannot execute statement"); + SQMOD_THROW_CURRENT(*m_Handle, "Cannot execute MySQL statement"); } // Return the identifier of the inserted row - return mysql_stmt_insert_id(m_Handle); + return mysql_stmt_insert_id(m_Handle->mPtr); } // ------------------------------------------------------------------------------------------------ ResultSet Statement::Query() { - // Validate the managed handle - m_Handle.Validate(); // Attempt to bind the parameters - if (mysql_stmt_bind_param(m_Handle, m_Handle->mMyBinds)) + if (mysql_stmt_bind_param(SQMOD_GET_CREATED(*this)->mPtr, m_Handle->mMyBinds)) { - THROW_CURRENT(m_Handle, "Cannot bind statement parameters"); + SQMOD_THROW_CURRENT(*m_Handle, "Cannot bind MySQL statement parameters"); } // Attempt to execute the statement - else if (mysql_stmt_execute(m_Handle)) + else if (mysql_stmt_execute(m_Handle->mPtr)) { - THROW_CURRENT(m_Handle, "Cannot execute statement"); + SQMOD_THROW_CURRENT(*m_Handle, "Cannot execute MySQL statement"); } // Return the results of this query - return ResultSet(ResHnd(m_Handle)); + return ResultSet(m_Handle); } // ------------------------------------------------------------------------------------------------ void Statement::SetInt8(Uint32 idx, SQInteger val) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_PARAM(*this, idx); // Attempt to set the input value m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_TINY, &(m_Handle->mMyBinds[idx])); // Assign the value to the input @@ -157,8 +192,7 @@ void Statement::SetInt8(Uint32 idx, SQInteger val) const // ------------------------------------------------------------------------------------------------ void Statement::SetUint8(Uint32 idx, SQInteger val) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_PARAM(*this, idx); // Attempt to set the input value m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_TINY, &(m_Handle->mMyBinds[idx])); // Assign the value to the input @@ -170,8 +204,7 @@ void Statement::SetUint8(Uint32 idx, SQInteger val) const // ------------------------------------------------------------------------------------------------ void Statement::SetInt16(Uint32 idx, SQInteger val) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_PARAM(*this, idx); // Attempt to set the input value m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_SHORT, &(m_Handle->mMyBinds[idx])); // Assign the value to the input @@ -181,8 +214,7 @@ void Statement::SetInt16(Uint32 idx, SQInteger val) const // ------------------------------------------------------------------------------------------------ void Statement::SetUint16(Uint32 idx, SQInteger val) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_PARAM(*this, idx); // Attempt to set the input value m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_SHORT, &(m_Handle->mMyBinds[idx])); // Assign the value to the input @@ -194,8 +226,7 @@ void Statement::SetUint16(Uint32 idx, SQInteger val) const // ------------------------------------------------------------------------------------------------ void Statement::SetInt32(Uint32 idx, SQInteger val) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_PARAM(*this, idx); // Attempt to set the input value m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_LONG, &(m_Handle->mMyBinds[idx])); // Assign the value to the input @@ -205,8 +236,7 @@ void Statement::SetInt32(Uint32 idx, SQInteger val) const // ------------------------------------------------------------------------------------------------ void Statement::SetUint32(Uint32 idx, SQInteger val) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_PARAM(*this, idx); // Attempt to set the input value m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_LONG, &(m_Handle->mMyBinds[idx])); // Assign the value to the input @@ -218,8 +248,7 @@ void Statement::SetUint32(Uint32 idx, SQInteger val) const // ------------------------------------------------------------------------------------------------ void Statement::SetInt64(Uint32 idx, SQInteger val) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_PARAM(*this, idx); // Attempt to set the input value m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_LONGLONG, &(m_Handle->mMyBinds[idx])); // Assign the value to the input @@ -229,8 +258,7 @@ void Statement::SetInt64(Uint32 idx, SQInteger val) const // ------------------------------------------------------------------------------------------------ void Statement::SetUint64(Uint32 idx, SQInteger val) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_PARAM(*this, idx); // Attempt to set the input value m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_LONGLONG, &(m_Handle->mMyBinds[idx])); // Assign the value to the input @@ -242,39 +270,23 @@ void Statement::SetUint64(Uint32 idx, SQInteger val) const // ------------------------------------------------------------------------------------------------ void Statement::SetSLongInt(Uint32 idx, Object & val) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_PARAM(*this, idx); // Attempt to set the input value m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_LONGLONG, &(m_Handle->mMyBinds[idx])); - // Obtain the initial stack size - const StackGuard sg; - // Push the specified object onto the stack - Var< Object >::push(_SqVM, val); - // Attempt to get the numeric value inside the specified object - if (SQ_FAILED(_SqMod->GetSLongValue(_SqVM, -1, &(m_Handle->mBinds[idx].mInt64)))) - { - STHROWF("Invalid long integer specified"); - } + // Attempt to assign the numeric value inside the specified object + m_Handle->mBinds[idx].mInt64 = FetchSLongObjVal(val); } // ------------------------------------------------------------------------------------------------ void Statement::SetULongInt(Uint32 idx, Object & val) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_PARAM(*this, idx); // Attempt to set the input value m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_LONGLONG, &(m_Handle->mMyBinds[idx])); + // Attempt to assign the numeric value inside the specified object + m_Handle->mBinds[idx].mUint64 = FetchULongObjVal(val); // Specify that this value is unsigned m_Handle->mMyBinds[idx].is_unsigned = true; - // Obtain the initial stack size - const StackGuard sg; - // Push the specified object onto the stack - Var< Object >::push(_SqVM, val); - // Attempt to get the numeric value inside the specified object - if (SQ_FAILED(_SqMod->GetULongValue(_SqVM, -1, &(m_Handle->mBinds[idx].mUint64)))) - { - STHROWF("Invalid long integer specified"); - } } // ------------------------------------------------------------------------------------------------ @@ -290,8 +302,7 @@ void Statement::SetInteger(Uint32 idx, SQInteger val) const // ------------------------------------------------------------------------------------------------ void Statement::SetFloat32(Uint32 idx, SQFloat val) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_PARAM(*this, idx); // Attempt to set the input value m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_FLOAT, &(m_Handle->mMyBinds[idx])); // Assign the value to the input @@ -301,8 +312,7 @@ void Statement::SetFloat32(Uint32 idx, SQFloat val) const // ------------------------------------------------------------------------------------------------ void Statement::SetFloat64(Uint32 idx, SQFloat val) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_PARAM(*this, idx); // Attempt to set the input value m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_DOUBLE, &(m_Handle->mMyBinds[idx])); // Assign the value to the input @@ -322,8 +332,7 @@ void Statement::SetFloat(Uint32 idx, SQFloat val) const // ------------------------------------------------------------------------------------------------ void Statement::SetBoolean(Uint32 idx, bool val) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_PARAM(*this, idx); // Attempt to set the input value m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_TINY, &(m_Handle->mMyBinds[idx])); // Assign the value to the input @@ -333,8 +342,7 @@ void Statement::SetBoolean(Uint32 idx, bool val) const // ------------------------------------------------------------------------------------------------ void Statement::SetDate(Uint32 idx, Object & val) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_PARAM(*this, idx); // Attempt to set the input value m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_DATE, &(m_Handle->mMyBinds[idx])); // Assign the value to the input @@ -344,8 +352,7 @@ void Statement::SetDate(Uint32 idx, Object & val) const // ------------------------------------------------------------------------------------------------ void Statement::SetTime(Uint32 idx, Object & val) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_PARAM(*this, idx); // Attempt to set the input value m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_TIME, &(m_Handle->mMyBinds[idx])); // Assign the value to the input @@ -355,8 +362,7 @@ void Statement::SetTime(Uint32 idx, Object & val) const // ------------------------------------------------------------------------------------------------ void Statement::SetDatetime(Uint32 idx, Object & val) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_PARAM(*this, idx); // Attempt to set the input value m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_DATETIME, &(m_Handle->mMyBinds[idx])); // Assign the value to the input @@ -366,8 +372,7 @@ void Statement::SetDatetime(Uint32 idx, Object & val) const // ------------------------------------------------------------------------------------------------ void Statement::SetString(Uint32 idx, CSStr val) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_PARAM(*this, idx); // Attempt to set the input value m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_STRING, &(m_Handle->mMyBinds[idx]), val, std::strlen(val)); } @@ -375,8 +380,7 @@ void Statement::SetString(Uint32 idx, CSStr val) const // ------------------------------------------------------------------------------------------------ void Statement::SetEnum(Uint32 idx, CSStr val) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_PARAM(*this, idx); // Attempt to set the input value m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_ENUM, &(m_Handle->mMyBinds[idx]), val, std::strlen(val)); } @@ -384,8 +388,7 @@ void Statement::SetEnum(Uint32 idx, CSStr val) const // ------------------------------------------------------------------------------------------------ void Statement::SetSet(Uint32 idx, CSStr val) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_PARAM(*this, idx); // Attempt to set the input value m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_SET, &(m_Handle->mMyBinds[idx]), val, std::strlen(val)); } @@ -405,10 +408,57 @@ void Statement::SetData(Uint32 /*idx*/, Object & /*val*/) const // ------------------------------------------------------------------------------------------------ void Statement::SetNull(Uint32 idx) const { - // Validate the managed handle and specified index - m_Handle.ValidateIndex(idx); + SQMOD_VALIDATE_PARAM(*this, idx); // Attempt to set the input value m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_NULL, &(m_Handle->mMyBinds[idx])); } -} // Namespace:: SqMod +// ================================================================================================ +void Register_Statement(Table & sqlns) +{ + sqlns.Bind(_SC("Statement") + , Class< Statement >(sqlns.GetVM(), _SC("SqMySQLStatement")) + // Constructors + .Ctor() + .Ctor< const Statement & >() + .Ctor< const Connection &, CSStr >() + // Core Meta-methods + .Func(_SC("_cmp"), &Statement::Cmp) + .SquirrelFunc(_SC("_typename"), &Statement::Typename) + .Func(_SC("_tostring"), &Statement::ToString) + // Properties + .Prop(_SC("IsValid"), &Statement::IsValid) + .Prop(_SC("Connection"), &Statement::GetConnection, &Statement::SetConnection) + // Member Methods + .Func(_SC("Execute"), &Statement::Execute) + .Func(_SC("Insert"), &Statement::Insert) + .Func(_SC("Query"), &Statement::Query) + .Func(_SC("SetInt8"), &Statement::SetInt8) + .Func(_SC("SetUint8"), &Statement::SetUint8) + .Func(_SC("SetInt16"), &Statement::SetInt16) + .Func(_SC("SetUint16"), &Statement::SetUint16) + .Func(_SC("SetInt32"), &Statement::SetInt32) + .Func(_SC("SetUint32"), &Statement::SetUint32) + .Func(_SC("SetInt64"), &Statement::SetInt64) + .Func(_SC("SetUint64"), &Statement::SetUint64) + .Func(_SC("SetSLongInt"), &Statement::SetSLongInt) + .Func(_SC("SetULongInt"), &Statement::SetULongInt) + .Func(_SC("SetInteger"), &Statement::SetInteger) + .Func(_SC("SetFloat32"), &Statement::SetFloat32) + .Func(_SC("SetFloat64"), &Statement::SetFloat64) + .Func(_SC("SetFloat"), &Statement::SetFloat) + .Func(_SC("SetBoolean"), &Statement::SetBoolean) + .Func(_SC("SetDate"), &Statement::SetDate) + .Func(_SC("SetTime"), &Statement::SetTime) + .Func(_SC("SetDatetime"), &Statement::SetDatetime) + .Func(_SC("SetString"), &Statement::SetString) + .Func(_SC("SetEnum"), &Statement::SetEnum) + .Func(_SC("SetSet"), &Statement::SetSet) + .Func(_SC("SetBlob"), &Statement::SetBlob) + .Func(_SC("SetData"), &Statement::SetData) + .Func(_SC("SetBuffer"), &Statement::SetData) + .Func(_SC("SetNull"), &Statement::SetNull) + ); +} + +} // Namespace:: SqMod \ No newline at end of file diff --git a/modules/mysql/Statement.hpp b/modules/mysql/Statement.hpp index 9df5fafe..d7093765 100644 --- a/modules/mysql/Statement.hpp +++ b/modules/mysql/Statement.hpp @@ -15,19 +15,74 @@ class Statement private: // -------------------------------------------------------------------------------------------- - StmtHnd m_Handle; // Reference to the managed statement. + StmtRef m_Handle; // Reference to the actual database statement. + +protected: + + /* -------------------------------------------------------------------------------------------- + * Validate the managed statement handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + void Validate(CCStr file, Int32 line) const; +#else + void Validate() const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the managed statement handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + void ValidateCreated(CCStr file, Int32 line) const; +#else + void ValidateCreated() const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the managed statement handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + const StmtRef & GetValid(CCStr file, Int32 line) const; +#else + const StmtRef & GetValid() const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the managed statement handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + const StmtRef & GetCreated(CCStr file, Int32 line) const; +#else + const StmtRef & GetCreated() const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the statement reference and parameter index, and throw an error if they're invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + void ValidateParam(Int32 idx, CCStr file, Int32 line) const; +#else + void ValidateParam(Int32 idx) const; +#endif // _DEBUG public: /* -------------------------------------------------------------------------------------------- * Default constructor. */ - Statement(); + Statement() + : m_Handle() + { + /* ... */ + } /* -------------------------------------------------------------------------------------------- * Construct a statement under the specified connection using the specified string. */ - Statement(const ConnHnd & connection, CSStr query); + Statement(const ConnRef & connection, CSStr query) + : m_Handle(new StmtHnd()) + { + m_Handle->Create(connection, query); + } /* -------------------------------------------------------------------------------------------- * Construct a statement under the specified connection using the specified string. @@ -44,11 +99,6 @@ public: */ Statement(Statement && o) = default; - /* -------------------------------------------------------------------------------------------- - * Destructor. - */ - ~Statement() = default; - /* -------------------------------------------------------------------------------------------- * Copy assignment operator. */ @@ -62,18 +112,49 @@ public: /* -------------------------------------------------------------------------------------------- * Used by the script engine to compare two instances of this type. */ - Int32 Cmp(const Statement & o) const; + Int32 Cmp(const Statement & o) const + { + if (m_Handle.Get() == o.m_Handle.Get()) + { + return 0; + } + else if (m_Handle.Get() > o.m_Handle.Get()) + { + return 1; + } + else + { + return -1; + } + } /* -------------------------------------------------------------------------------------------- * Used by the script engine to convert an instance of this type to a string. */ - CSStr ToString() const; + const String & ToString() const + { + // Do we have a valid handle? + if (m_Handle) + { + m_Handle->mQuery; + } + // Default to an empty string + return NullString(); + } /* -------------------------------------------------------------------------------------------- * Used by the script engine to retrieve the name from instances of this type. */ static SQInteger Typename(HSQUIRRELVM vm); + /* -------------------------------------------------------------------------------------------- + * Retrieve the associated connection handle. + */ + const StmtRef & GetHandle() const + { + return m_Handle; + } + /* -------------------------------------------------------------------------------------------- * See whether the managed handle is valid. */