diff --git a/module/PocoLib/Data.cpp b/module/PocoLib/Data.cpp index 22e7f307..bde5f37e 100644 --- a/module/PocoLib/Data.cpp +++ b/module/PocoLib/Data.cpp @@ -27,6 +27,7 @@ SQMOD_DECL_TYPENAME(SqBoolBinding, _SC("SqBoolBinding")) SQMOD_DECL_TYPENAME(SqPcDataSession, _SC("SqDataSession")) SQMOD_DECL_TYPENAME(SqPcDataStatement, _SC("SqDataStatement")) SQMOD_DECL_TYPENAME(SqPcDataRecordSet, _SC("SqDataRecordSet")) +SQMOD_DECL_TYPENAME(SqPcDataSessionPool, _SC("SqDataSessionPool")) SQMOD_DECL_TYPENAME(SqPcDataStatementResult, _SC("SqDataStatementResult")) // ------------------------------------------------------------------------------------------------ @@ -393,6 +394,45 @@ SqDataStatement & SqDataStatement::Into_(LightObj & obj, LightObj & def) return *this; } +// ------------------------------------------------------------------------------------------------ +LightObj SqDataSessionPool::GetProperty(StackStrF & name) +{ + HSQUIRRELVM vm = name.mVM; + // Preserve stack + const StackGuard sg(vm); + // Retrieve the property value + Poco::Any a = getProperty(name.ToStr()); + // Retrieve the value type + const auto & ti = a.type(); + // Identify the stored value + if (a.empty() || ti == typeid(void) || ti == typeid(nullptr)) sq_pushnull(vm); + else if (ti == typeid(bool)) sq_pushbool(vm, Poco::AnyCast< bool >(a)); + else if (ti == typeid(char)) sq_pushinteger(vm, ConvTo< SQInteger >::From(Poco::AnyCast< char >(a))); + else if (ti == typeid(wchar_t)) sq_pushinteger(vm, ConvTo< SQInteger >::From(Poco::AnyCast< wchar_t >(a))); + else if (ti == typeid(signed char)) sq_pushinteger(vm, ConvTo< SQInteger >::From(Poco::AnyCast< signed char >(a))); + else if (ti == typeid(unsigned char)) sq_pushinteger(vm, ConvTo< SQInteger >::From(Poco::AnyCast< unsigned char >(a))); + else if (ti == typeid(short int)) sq_pushinteger(vm, ConvTo< SQInteger >::From(Poco::AnyCast< short int >(a))); + else if (ti == typeid(unsigned short int)) sq_pushinteger(vm, ConvTo< SQInteger >::From(Poco::AnyCast< unsigned short int >(a))); + else if (ti == typeid(int)) sq_pushinteger(vm, ConvTo< SQInteger >::From(Poco::AnyCast< int >(a))); + else if (ti == typeid(unsigned int)) sq_pushinteger(vm, ConvTo< SQInteger >::From(Poco::AnyCast< unsigned int >(a))); + else if (ti == typeid(long int)) sq_pushinteger(vm, ConvTo< SQInteger >::From(Poco::AnyCast< long int >(a))); + else if (ti == typeid(unsigned long int)) sq_pushinteger(vm, ConvTo< SQInteger >::From(Poco::AnyCast< unsigned long int >(a))); + else if (ti == typeid(long long int)) sq_pushinteger(vm, ConvTo< SQInteger >::From(Poco::AnyCast< long long int >(a))); + else if (ti == typeid(unsigned long long int)) sq_pushinteger(vm, ConvTo< SQInteger >::From(Poco::AnyCast< unsigned long long int >(a))); + else if (ti == typeid(float)) sq_pushfloat(vm, ConvTo< SQFloat >::From(Poco::AnyCast< float >(a))); + else if (ti == typeid(double)) sq_pushfloat(vm, ConvTo< SQFloat >::From(Poco::AnyCast< double >(a))); + else if (ti == typeid(long double)) sq_pushfloat(vm, ConvTo< SQFloat >::From(Poco::AnyCast< long double >(a))); + else if (ti == typeid(std::string)) { + const auto & s = Poco::RefAnyCast< std::string >(a); + sq_pushstring(vm, s.data(), ConvTo< SQFloat >::From(s.size())); + } else { + sq_throwerrorf(vm, "Unable to convert value of type (%s) to squirrel.", a.type().name()); + sq_pushnull(vm); + } + // Return the object from the stack + return Var< LightObj >(vm, -1).value; +} + // ------------------------------------------------------------------------------------------------ template < class T, class U > static void Register_POCO_Data_Binding(HSQUIRRELVM vm, Table & ns, const SQChar * name) @@ -613,6 +653,35 @@ void Register_POCO_Data(HSQUIRRELVM vm, Table &) .Overload(_SC("Value"), &SqDataRecordSet::GetValueOr) ); // -------------------------------------------------------------------------------------------- + ns.Bind(_SC("SessionPool"), + Class< SqDataSessionPool, NoCopy< SqDataSessionPool > >(vm, SqPcDataSessionPool::Str) + // Constructors + .Ctor< StackStrF &, StackStrF & >() + .Ctor< StackStrF &, int, int, int, StackStrF & >() + // Meta-methods + .SquirrelFunc(_SC("_typename"), &SqPcDataSessionPool::Fn) + // Properties + .Prop(_SC("Capacity"), &SqDataSessionPool::GetCapacity) + .Prop(_SC("Used"), &SqDataSessionPool::GetUsed) + .Prop(_SC("Idle"), &SqDataSessionPool::GetIdle) + .Prop(_SC("Dead"), &SqDataSessionPool::GetDead) + .Prop(_SC("Allocated"), &SqDataSessionPool::GetAllocated) + .Prop(_SC("Available"), &SqDataSessionPool::GetAvailable) + .Prop(_SC("Name"), &SqDataSessionPool::GetName) + .Prop(_SC("IsActive"), &SqDataSessionPool::IsActive) + // Member Methods + .Func(_SC("Get"), &SqDataSessionPool::Get) + .FmtFunc(_SC("GetWithProperty"), &SqDataSessionPool::GetWithProperty) + .FmtFunc(_SC("GetWithFeature"), &SqDataSessionPool::GetWithFeature) + .FmtFunc(_SC("SetFeature"), &SqDataSessionPool::SetFeature) + .FmtFunc(_SC("GetFeature"), &SqDataSessionPool::GetFeature) + .FmtFunc(_SC("SetProperty"), &SqDataSessionPool::SetProperty) + .FmtFunc(_SC("GetProperty"), &SqDataSessionPool::GetProperty) + .Func(_SC("Shutdown"), &SqDataSessionPool::Shutdown) + // Static Functions + .StaticFunc(_SC("GetName"), &SqDataSessionPool::GetName_) + ); + // -------------------------------------------------------------------------------------------- ns.Func(_SC("Process"), ProcessPocoData); // -------------------------------------------------------------------------------------------- Register_POCO_Data_Binding< SQInteger, SqIntegerBinding >(vm, ns, _SC("IntBind")); diff --git a/module/PocoLib/Data.hpp b/module/PocoLib/Data.hpp index c9738e7a..2aafbcc2 100644 --- a/module/PocoLib/Data.hpp +++ b/module/PocoLib/Data.hpp @@ -8,6 +8,7 @@ #include #include #include +#include // ------------------------------------------------------------------------------------------------ namespace std { // NOLINT(cert-dcl58-cpp) @@ -471,6 +472,7 @@ using namespace Poco::Data::Keywords; using Poco::Data::Session; using Poco::Data::Statement; using Poco::Data::RecordSet; +using Poco::Data::SessionPool; using Poco::Data::ReferenceBinding; // ------------------------------------------------------------------------------------------------ @@ -652,6 +654,22 @@ struct SqDataSession : public Session */ SqDataSession(SqDataSession &&) noexcept = default; + /* -------------------------------------------------------------------------------------------- + * Creates a session by copying another one. + */ + SqDataSession(const Session & s) + : Session(s) + { + } + + /* -------------------------------------------------------------------------------------------- + * Creates a session by moving another one. + */ + SqDataSession(Session && s) noexcept + : Session(std::move(s)) + { + } + /* -------------------------------------------------------------------------------------------- * Destroys the Session. */ @@ -1677,4 +1695,225 @@ protected: } }; +/* ------------------------------------------------------------------------------------------------ + * SessionPool implements session pooling for POCO Data. +*/ +struct SqDataSessionPool : public SessionPool +{ + + /* -------------------------------------------------------------------------------------------- + * Creates the SessionPool for sessions with the given connector and connection string. + */ + SqDataSessionPool(StackStrF & connector, StackStrF & connection) + : SessionPool(connector.ToStr(), connection.ToStr()) + { + } + + /* -------------------------------------------------------------------------------------------- + * Creates the SessionPool for sessions with the given connector and connection string. + */ + SqDataSessionPool(StackStrF & connector, int min_ses, int max_ses, int idle_time, StackStrF & connection) + : SessionPool(connector.ToStr(), connection.ToStr(), min_ses, max_ses, idle_time) + { + } + + /* -------------------------------------------------------------------------------------------- + * Copy constructor (disabled). + */ + SqDataSessionPool(const SqDataSessionPool &) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move constructor (disabled). + */ + SqDataSessionPool(SqDataSessionPool &&) noexcept = delete; + + /* -------------------------------------------------------------------------------------------- + * Destroys the SessionPool. + */ + ~SqDataSessionPool() = default; + + /* -------------------------------------------------------------------------------------------- + * Assignment operator (disabled). + */ + SqDataSessionPool & operator = (const SqDataSessionPool &) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move assignment (disabled). + */ + SqDataSessionPool & operator = (SqDataSessionPool &&) noexcept = delete; + + /* -------------------------------------------------------------------------------------------- + * Retrieve a Session. + */ + LightObj Get() + { + return LightObj(SqTypeIdentity< SqDataSession >{}, SqVM(), get()); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve a Session with requested property set. + */ + LightObj GetWithProperty(const LightObj & value, StackStrF & name) + { + switch (value.GetType()) + { + case OT_NULL: { + return LightObj(SqTypeIdentity< SqDataSession >{}, SqVM(), get(name.ToStr(), nullptr)); + } break; + case OT_INTEGER: { + return LightObj(SqTypeIdentity< SqDataSession >{}, SqVM(), get(name.ToStr(), value.Cast< SQInteger >())); + } break; + case OT_FLOAT: { + return LightObj(SqTypeIdentity< SqDataSession >{}, SqVM(), get(name.ToStr(), value.Cast< SQFloat >())); + } break; + case OT_BOOL: { + return LightObj(SqTypeIdentity< SqDataSession >{}, SqVM(), get(name.ToStr(), value.Cast< bool >())); + } break; + case OT_STRING: { + return LightObj(SqTypeIdentity< SqDataSession >{}, SqVM(), get(name.ToStr(), value.Cast< std::string >())); + } break; + default: STHROWF("Unsupported property value type"); + } + // Should never get here + SQ_UNREACHABLE + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve a Session with requested feature set. + */ + LightObj GetWithFeature(bool value, StackStrF & name) + { + return LightObj(SqTypeIdentity< SqDataSession >{}, SqVM(), get(name.ToStr(), value)); + } + + /* -------------------------------------------------------------------------------------------- + * Returns the maximum number of sessions the SessionPool will manage. + */ + SQInteger GetCapacity() const + { + return capacity(); + } + + /* -------------------------------------------------------------------------------------------- + * Returns the number of sessions currently in use. + */ + SQInteger GetUsed() const + { + return used(); + } + + /* -------------------------------------------------------------------------------------------- + * Returns the number of idle sessions. + */ + SQInteger GetIdle() const + { + return idle(); + } + + /* -------------------------------------------------------------------------------------------- + * Returns the number of not connected active sessions. + */ + SQInteger GetDead() + { + return dead(); + } + + /* -------------------------------------------------------------------------------------------- + * Returns the number of allocated sessions. + */ + SQInteger GetAllocated() const + { + return allocated(); + } + + /* -------------------------------------------------------------------------------------------- + * Returns the number of available (idle + remaining capacity) sessions. + */ + SQInteger GetAvailable() const + { + return available(); + } + + /* -------------------------------------------------------------------------------------------- + * Returns the name for this pool. + */ + String GetName() const + { + return name(); + } + + /* -------------------------------------------------------------------------------------------- + * Returns the name formatted from supplied arguments as "connector:///connection". + */ + static String GetName_(StackStrF & connector, StackStrF & connection) + { + return name(connector.ToStr(), connection.ToStr()); + } + + /* -------------------------------------------------------------------------------------------- + * Sets feature for all the sessions. + */ + SqDataSessionPool & SetFeature(StackStrF & name, bool state) + { + setFeature(name.ToStr(), state); + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Returns the requested feature. + */ + bool GetFeature(StackStrF & name) + { + return getFeature(name.ToStr()); + } + + /* -------------------------------------------------------------------------------------------- + * Sets property for all sessions. + */ + SqDataSessionPool & SetProperty(const LightObj & value, StackStrF & name) + { + switch (value.GetType()) + { + case OT_NULL: { + setProperty(name.ToStr(), Poco::Any(nullptr)); + } break; + case OT_INTEGER: { + setProperty(name.ToStr(), Poco::Any(value.Cast< SQInteger >())); + } break; + case OT_FLOAT: { + setProperty(name.ToStr(), Poco::Any(value.Cast< SQFloat >())); + } break; + case OT_BOOL: { + setProperty(name.ToStr(), Poco::Any(value.Cast())); + } break; + case OT_STRING: { + setProperty(name.ToStr(), Poco::Any(value.Cast())); + } break; + default: STHROWF("Unsupported property value type"); + } + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Returns the requested property. + */ + LightObj GetProperty(StackStrF & name); + + /* -------------------------------------------------------------------------------------------- + * Shuts down the session pool. + */ + void Shutdown() + { + shutdown(); + } + + /* -------------------------------------------------------------------------------------------- + * Returns true if session pool is active (not shut down). + */ + bool IsActive() const + { + return isActive(); + } +}; + } // Namespace:: SqMod