From 3affe10c3589b89d8baab0a5632c9699da053308 Mon Sep 17 00:00:00 2001 From: Sandu Liviu Catalin Date: Sun, 5 Jun 2016 05:08:59 +0300 Subject: [PATCH] Initial implementation of the MySQL statement class. Various other additions and improvements to the MySQL module. --- modules/mysql/Common.cpp | 82 ++++++++++++++ modules/mysql/Common.hpp | 15 +++ modules/mysql/Connection.hpp | 9 ++ modules/mysql/Handle/Result.cpp | 1 + modules/mysql/Handle/Statement.cpp | 1 + modules/mysql/Module.cpp | 41 ++++++- modules/mysql/Statement.cpp | 173 ++++++++++++++++++++++++++--- modules/mysql/Statement.hpp | 129 ++++++++++++++------- 8 files changed, 392 insertions(+), 59 deletions(-) diff --git a/modules/mysql/Common.cpp b/modules/mysql/Common.cpp index f54b3f1a..b9bec776 100644 --- a/modules/mysql/Common.cpp +++ b/modules/mysql/Common.cpp @@ -4,6 +4,88 @@ // ------------------------------------------------------------------------------------------------ namespace SqMod { +// ------------------------------------------------------------------------------------------------ +void SqDateToMySQLTime(Object & obj, MYSQL_TIME & t) +{ + // The resulted date values + uint16_t year = 0; + uint8_t month = 0, day = 0; + { + // Obtain the initial stack size + const StackGuard sg(_SqVM); + // Push the specified object onto the stack + Var< Object >::push(_SqVM, obj); + // Attempt to get the values inside the specified object + if (SQ_FAILED(_SqMod->GetDate(_SqVM, -1, &year, &month, &day))) + { + STHROWF("Invalid date specified"); + } + } + // Populate the given structure + t.year = year; + t.month = month; + t.day = day; + t.hour = 0; + t.minute = 0; + t.second = 0; + t.neg = false; + t.second_part = 0; + t.time_type = MYSQL_TIMESTAMP_DATE; +} +// ------------------------------------------------------------------------------------------------ +void SqTimeToMySQLTime(Object & obj, MYSQL_TIME & t) +{ + // The resulted time values + uint8_t hour = 0, minute = 0, second = 0; + uint16_t milli = 0; + { + // Obtain the initial stack size + const StackGuard sg(_SqVM); + // Push the specified object onto the stack + Var< Object >::push(_SqVM, obj); + // Attempt to get the values inside the specified object + if (SQ_FAILED(_SqMod->GetTime(_SqVM, -1, &hour, &minute, &second, &milli))) + { + STHROWF("Invalid time specified"); + } + } + // Populate the given structure + t.year = 0; + t.month = 0; + t.day = 0; + t.neg = false; + t.second_part = (milli * 1000L); + t.time_type = MYSQL_TIMESTAMP_TIME; +} + +// ------------------------------------------------------------------------------------------------ +void SqDatetimeToMySQLTime(Object & obj, MYSQL_TIME & t) +{ + // The resulted date values + uint16_t year = 0, milli = 0; + uint8_t month = 0, day = 0, hour = 0, minute = 0, second = 0; + { + // Obtain the initial stack size + const StackGuard sg(_SqVM); + // Push the specified object onto the stack + Var< Object >::push(_SqVM, obj); + // Attempt to get the values inside the specified object + if (SQ_FAILED(_SqMod->GetDatetime(_SqVM, -1, &year, &month, &day, &hour, &minute, &second, &milli))) + { + STHROWF("Invalid date and time specified"); + } + } + // Populate the given structure + t.year = year; + t.month = month; + t.day = day; + t.hour = hour; + t.minute = minute; + t.second = second; + t.neg = false; + t.second_part = (milli * 1000L); + t.time_type = MYSQL_TIMESTAMP_DATETIME; +} } // Namespace:: SqMod diff --git a/modules/mysql/Common.hpp b/modules/mysql/Common.hpp index 734dca63..d710788b 100644 --- a/modules/mysql/Common.hpp +++ b/modules/mysql/Common.hpp @@ -44,6 +44,21 @@ class ResultSet; class Statement; class Transaction; +/* ------------------------------------------------------------------------------------------------ + * Replicate the values of a script Date type to a database time type. +*/ +void SqDateToMySQLTime(Object & obj, MYSQL_TIME & t); + +/* ------------------------------------------------------------------------------------------------ + * Replicate the values of a script Date type to a database time type. +*/ +void SqTimeToMySQLTime(Object & obj, MYSQL_TIME & t); + +/* ------------------------------------------------------------------------------------------------ + * Replicate the values of a script Date type to a database time type. +*/ +void SqDatetimeToMySQLTime(Object & obj, MYSQL_TIME & t); + } // Namespace:: SqMod #endif // _SQMYSQL_COMMON_HPP_ diff --git a/modules/mysql/Connection.hpp b/modules/mysql/Connection.hpp index b461f9b4..29d8cff5 100644 --- a/modules/mysql/Connection.hpp +++ b/modules/mysql/Connection.hpp @@ -37,6 +37,15 @@ public: /* ... */ } + /* -------------------------------------------------------------------------------------------- + * Base constructor. + */ + Connection(const ConnHnd & conn) + : m_Handle(conn) + { + /* ... */ + } + /* -------------------------------------------------------------------------------------------- * Copy constructor. */ diff --git a/modules/mysql/Handle/Result.cpp b/modules/mysql/Handle/Result.cpp index f272c4ed..d2222777 100644 --- a/modules/mysql/Handle/Result.cpp +++ b/modules/mysql/Handle/Result.cpp @@ -96,6 +96,7 @@ void ResHnd::Bind::SetOutput(const FieldType & field, BindType * bind) case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_BLOB: case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: case MYSQL_TYPE_VARCHAR: case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_STRING: diff --git a/modules/mysql/Handle/Statement.cpp b/modules/mysql/Handle/Statement.cpp index ecf26974..4d0815c5 100644 --- a/modules/mysql/Handle/Statement.cpp +++ b/modules/mysql/Handle/Statement.cpp @@ -116,6 +116,7 @@ void StmtHnd::Bind::SetInput(enum_field_types type, BindType * bind, CCStr buffe case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_BLOB: case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: case MYSQL_TYPE_VARCHAR: case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_STRING: diff --git a/modules/mysql/Module.cpp b/modules/mysql/Module.cpp index 70affb1f..d74a54d2 100644 --- a/modules/mysql/Module.cpp +++ b/modules/mysql/Module.cpp @@ -256,9 +256,37 @@ void RegisterAPI(HSQUIRRELVM vm) .SquirrelFunc(_SC("_typename"), &Statement::Typename) .Func(_SC("_tostring"), &Statement::ToString) // Properties - //.Prop(_SC("Connected"), &Statement::Connected) + .Prop(_SC("IsValid"), &Statement::IsValid) + .Prop(_SC("Connection"), &Statement::GetConnection, &Statement::SetConnection) // Member Methods - //.Func(_SC("Disconnect"), &Statement::Disconnect) + .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) ); sqlns.Bind(_SC("ResultSet"), Class< ResultSet >(vm, _SC("SqMySQLResultSet")) @@ -271,7 +299,14 @@ void RegisterAPI(HSQUIRRELVM vm) // Properties //.Prop(_SC("Connected"), &ResultSet::Connected) // Member Methods - //.Func(_SC("Disconnect"), &ResultSet::Disconnect) + .Func(_SC("SetInt8"), &ResultSet::GetInt8) + .Func(_SC("SetUint8"), &ResultSet::GetUint8) + .Func(_SC("SetInt16"), &ResultSet::GetInt16) + .Func(_SC("SetUint16"), &ResultSet::GetUint16) + .Func(_SC("SetInt32"), &ResultSet::GetInt32) + .Func(_SC("SetUint32"), &ResultSet::GetUint32) + .Func(_SC("SetInt64"), &ResultSet::GetInt64) + .Func(_SC("SetUint64"), &ResultSet::GetUint64) ); } diff --git a/modules/mysql/Statement.cpp b/modules/mysql/Statement.cpp index 37fae743..f82cd976 100644 --- a/modules/mysql/Statement.cpp +++ b/modules/mysql/Statement.cpp @@ -1,9 +1,11 @@ // ------------------------------------------------------------------------------------------------ #include "Statement.hpp" #include "Connection.hpp" +#include "ResultSet.hpp" // ------------------------------------------------------------------------------------------------ #include +#include // ------------------------------------------------------------------------------------------------ namespace SqMod { @@ -66,6 +68,24 @@ Statement::Statement(const Connection & connection, CSStr query) } +// ------------------------------------------------------------------------------------------------ +Connection Statement::GetConnection() const +{ + // Validate the managed handle + m_Handle.Validate(); + // Return the requested information + return Connection(m_Handle->mConnection); +} + +// ------------------------------------------------------------------------------------------------ +void Statement::SetConnection(const Connection & conn) +{ + // Validate the managed handle + m_Handle.Validate(); + // Perform the requested operation + m_Handle->mConnection = conn.GetHnd(); +} + // ------------------------------------------------------------------------------------------------ Int32 Statement::Execute() { @@ -81,12 +101,8 @@ Int32 Statement::Execute() { THROW_CURRENT(m_Handle, "Cannot execute statement"); } - else - { - return mysql_stmt_affected_rows(m_Handle); - } - // Default to a negative value to indicate error - return -1; + // Return the number of rows affected by this query + return mysql_stmt_affected_rows(m_Handle); } // ------------------------------------------------------------------------------------------------ @@ -104,12 +120,27 @@ Uint32 Statement::Insert() { THROW_CURRENT(m_Handle, "Cannot execute statement"); } - else + // Return the identifier of the inserted row + return mysql_stmt_insert_id(m_Handle); +} + +// ------------------------------------------------------------------------------------------------ +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)) { - return mysql_stmt_insert_id(m_Handle); + THROW_CURRENT(m_Handle, "Cannot bind statement parameters"); } - // Default to 0 - return 0; + // Attempt to execute the statement + else if (mysql_stmt_execute(m_Handle)) + { + THROW_CURRENT(m_Handle, "Cannot execute statement"); + } + // Return the results of this query + return ResultSet(ResHnd(m_Handle)); } // ------------------------------------------------------------------------------------------------ @@ -172,7 +203,7 @@ void Statement::SetInt32(Uint32 idx, SQInteger val) const } // ------------------------------------------------------------------------------------------------ -void Statement::SetUint32(Uint32 idx, Uint32 val) const +void Statement::SetUint32(Uint32 idx, SQInteger val) const { // Validate the managed handle and specified index m_Handle.ValidateIndex(idx); @@ -185,7 +216,31 @@ void Statement::SetUint32(Uint32 idx, Uint32 val) const } // ------------------------------------------------------------------------------------------------ -void Statement::SetInt64(Uint32 idx, Object & val) const +void Statement::SetInt64(Uint32 idx, SQInteger val) const +{ + // Validate the managed handle and specified index + m_Handle.ValidateIndex(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 + m_Handle->mBinds[idx].mInt64 = ConvTo< Int64 >::From(val); +} + +// ------------------------------------------------------------------------------------------------ +void Statement::SetUint64(Uint32 idx, SQInteger val) const +{ + // Validate the managed handle and specified index + m_Handle.ValidateIndex(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 + m_Handle->mBinds[idx].mUint64 = ConvTo< Uint64 >::From(val); + // Specify that this value is unsigned + m_Handle->mMyBinds[idx].is_unsigned = true; +} + +// ------------------------------------------------------------------------------------------------ +void Statement::SetSLongInt(Uint32 idx, Object & val) const { // Validate the managed handle and specified index m_Handle.ValidateIndex(idx); @@ -203,7 +258,7 @@ void Statement::SetInt64(Uint32 idx, Object & val) const } // ------------------------------------------------------------------------------------------------ -void Statement::SetUint64(Uint32 idx, Object & val) const +void Statement::SetULongInt(Uint32 idx, Object & val) const { // Validate the managed handle and specified index m_Handle.ValidateIndex(idx); @@ -222,6 +277,16 @@ void Statement::SetUint64(Uint32 idx, Object & val) const } } +// ------------------------------------------------------------------------------------------------ +void Statement::SetInteger(Uint32 idx, SQInteger val) const +{ +#ifdef _SQ64 + SetInt64(idx, val); +#else + SetInt32(idx, val); +#endif // _SQ64 +} + // ------------------------------------------------------------------------------------------------ void Statement::SetFloat32(Uint32 idx, SQFloat val) const { @@ -244,6 +309,16 @@ void Statement::SetFloat64(Uint32 idx, SQFloat val) const m_Handle->mBinds[idx].mFloat64 = ConvTo< Float64 >::From(val); } +// ------------------------------------------------------------------------------------------------ +void Statement::SetFloat(Uint32 idx, SQFloat val) const +{ +#ifdef SQUSEDOUBLE + SetFloat64(idx, val); +#else + SetFloat32(idx, val); +#endif // SQUSEDOUBLE +} + // ------------------------------------------------------------------------------------------------ void Statement::SetBoolean(Uint32 idx, bool val) const { @@ -255,6 +330,78 @@ void Statement::SetBoolean(Uint32 idx, bool val) const m_Handle->mBinds[idx].mUint64 = val; } +// ------------------------------------------------------------------------------------------------ +void Statement::SetDate(Uint32 idx, Object & val) const +{ + // Validate the managed handle and specified index + m_Handle.ValidateIndex(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 + SqDateToMySQLTime(val, m_Handle->mBinds[idx].mTime); +} + +// ------------------------------------------------------------------------------------------------ +void Statement::SetTime(Uint32 idx, Object & val) const +{ + // Validate the managed handle and specified index + m_Handle.ValidateIndex(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 + SqTimeToMySQLTime(val, m_Handle->mBinds[idx].mTime); +} + +// ------------------------------------------------------------------------------------------------ +void Statement::SetDatetime(Uint32 idx, Object & val) const +{ + // Validate the managed handle and specified index + m_Handle.ValidateIndex(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 + SqDatetimeToMySQLTime(val, m_Handle->mBinds[idx].mTime); +} + +// ------------------------------------------------------------------------------------------------ +void Statement::SetString(Uint32 idx, CSStr val) const +{ + // Validate the managed handle and specified index + m_Handle.ValidateIndex(idx); + // Attempt to set the input value + m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_STRING, &(m_Handle->mMyBinds[idx]), val, std::strlen(val)); +} + +// ------------------------------------------------------------------------------------------------ +void Statement::SetEnum(Uint32 idx, CSStr val) const +{ + // Validate the managed handle and specified index + m_Handle.ValidateIndex(idx); + // Attempt to set the input value + m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_ENUM, &(m_Handle->mMyBinds[idx]), val, std::strlen(val)); +} + +// ------------------------------------------------------------------------------------------------ +void Statement::SetSet(Uint32 idx, CSStr val) const +{ + // Validate the managed handle and specified index + m_Handle.ValidateIndex(idx); + // Attempt to set the input value + m_Handle->mBinds[idx].SetInput(MYSQL_TYPE_SET, &(m_Handle->mMyBinds[idx]), val, std::strlen(val)); +} + +// ------------------------------------------------------------------------------------------------ +void Statement::SetBlob(Uint32 /*idx*/, Object & /*val*/) const +{ + // TODO... +} + +// ------------------------------------------------------------------------------------------------ +void Statement::SetData(Uint32 /*idx*/, Object & /*val*/) const +{ + // TODO... +} + // ------------------------------------------------------------------------------------------------ void Statement::SetNull(Uint32 idx) const { diff --git a/modules/mysql/Statement.hpp b/modules/mysql/Statement.hpp index ddad3e10..9df5fafe 100644 --- a/modules/mysql/Statement.hpp +++ b/modules/mysql/Statement.hpp @@ -74,6 +74,24 @@ public: */ static SQInteger Typename(HSQUIRRELVM vm); + /* -------------------------------------------------------------------------------------------- + * See whether the managed handle is valid. + */ + bool IsValid() const + { + return m_Handle; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the currently associated statement connection. + */ + Connection GetConnection() const; + + /* -------------------------------------------------------------------------------------------- + * Modify the currently associated statement connection. + */ + void SetConnection(const Connection & conn); + /* -------------------------------------------------------------------------------------------- * Execute the statement. */ @@ -84,6 +102,11 @@ public: */ Uint32 Insert(); + /* -------------------------------------------------------------------------------------------- + * Execute the statement. + */ + ResultSet Query(); + /* -------------------------------------------------------------------------------------------- * Assign a signed 8bit integer to a parameter. */ @@ -112,17 +135,32 @@ public: /* -------------------------------------------------------------------------------------------- * Assign an unsigned 32bit integer to a parameter. */ - void SetUint32(Uint32 idx, Uint32 val) const; + void SetUint32(Uint32 idx, SQInteger val) const; /* -------------------------------------------------------------------------------------------- * Assign a signed 64bit integer to a parameter. */ - void SetInt64(Uint32 idx, Object & val) const; + void SetInt64(Uint32 idx, SQInteger val) const; /* -------------------------------------------------------------------------------------------- * Assign an unsigned 64bit integer to a parameter. */ - void SetUint64(Uint32 idx, Object & val) const; + void SetUint64(Uint32 idx, SQInteger val) const; + + /* -------------------------------------------------------------------------------------------- + * Assign a signed long integer to a parameter. + */ + void SetSLongInt(Uint32 idx, Object & val) const; + + /* -------------------------------------------------------------------------------------------- + * Assign an unsigned long integer to a parameter. + */ + void SetULongInt(Uint32 idx, Object & val) const; + + /* -------------------------------------------------------------------------------------------- + * Assign a native integer to a parameter. + */ + void SetInteger(Uint32 idx, SQInteger val) const; /* -------------------------------------------------------------------------------------------- * Assign a 32bit floating point to a parameter. @@ -134,56 +172,61 @@ public: */ void SetFloat64(Uint32 idx, SQFloat val) const; + /* -------------------------------------------------------------------------------------------- + * Assign a native float to a parameter. + */ + void SetFloat(Uint32 idx, SQFloat val) const; + /* -------------------------------------------------------------------------------------------- * Assign a boolean to a parameter. */ void SetBoolean(Uint32 idx, bool val) const; + /* -------------------------------------------------------------------------------------------- + * Assign a date to a parameter. + */ + void SetDate(Uint32 idx, Object & val) const; + + /* -------------------------------------------------------------------------------------------- + * Assign a time to a parameter. + */ + void SetTime(Uint32 idx, Object & val) const; + + /* -------------------------------------------------------------------------------------------- + * Assign a date and time to a parameter. + */ + void SetDatetime(Uint32 idx, Object & val) const; + + /* -------------------------------------------------------------------------------------------- + * Assign a string to a parameter. + */ + void SetString(Uint32 idx, CSStr val) const; + + /* -------------------------------------------------------------------------------------------- + * Assign an enumeration to a parameter. + */ + void SetEnum(Uint32 idx, CSStr val) const; + + /* -------------------------------------------------------------------------------------------- + * Assign an enumeration to a parameter. + */ + void SetSet(Uint32 idx, CSStr val) const; + + /* -------------------------------------------------------------------------------------------- + * Assign a blob to a parameter. + */ + void SetBlob(Uint32 idx, Object & val) const; + + /* -------------------------------------------------------------------------------------------- + * Assign a buffer to a paramete. + */ + void SetData(Uint32 idx, Object & val) const; + /* -------------------------------------------------------------------------------------------- * Assign a null to a parameter. */ void SetNull(Uint32 idx) const; - /* -------------------------------------------------------------------------------------------- - * - */ - void SetBlob(Uint32 idx, Object & val) const; - - /* -------------------------------------------------------------------------------------------- - * - */ - void SetData(Uint32 idx, Object & val) const; - - /* -------------------------------------------------------------------------------------------- - * - */ - void SetDate(Uint32 idx, Object & val) const; - - /* -------------------------------------------------------------------------------------------- - * - */ - void SetTime(Uint32 idx, Object & val) const; - - /* -------------------------------------------------------------------------------------------- - * - */ - void SetDatetime(Uint32 idx, Object & val) const; - - /* -------------------------------------------------------------------------------------------- - * - */ - void SetDecimal(Uint32 idx, Object & val) const; - - /* -------------------------------------------------------------------------------------------- - * - */ - void SetString(Uint32 idx, Object & val) const; - - /* -------------------------------------------------------------------------------------------- - * - */ - void SetEnum(Uint32 idx, Object & val) const; - }; } // Namespace:: SqMod