diff --git a/module/PocoLib/Data.cpp b/module/PocoLib/Data.cpp index cfcff6f4..a0333672 100644 --- a/module/PocoLib/Data.cpp +++ b/module/PocoLib/Data.cpp @@ -112,7 +112,7 @@ SqDataStatement SqDataSession::GetStatement(StackStrF & data) } // ------------------------------------------------------------------------------------------------ -SqDataStatement & SqDataStatement::UseEx(LightObj & obj, const std::string & name, Poco::Data::AbstractBinding::Direction dir) +void SqDataStatement::UseEx(LightObj & obj, const std::string & name, Poco::Data::AbstractBinding::Direction dir) { // switch (obj.GetType()) @@ -122,42 +122,64 @@ SqDataStatement & SqDataStatement::UseEx(LightObj & obj, const std::string & nam case OT_FLOAT: case OT_BOOL: case OT_STRING: STHROWF("Use Bind(...) for non-reference types."); break; - case OT_INSTANCE: { - auto type = static_cast< AbstractStaticClassData * >(obj.GetTypeTag()); - // Integer reference? - if (type == StaticClassTypeTag< SqDataBinding< SQInteger > >::Get()) - { - addBind(new Poco::Data::ReferenceBinding< SQInteger >(obj.CastI< SqDataBinding< SQInteger > >()->mV, name, dir)); break; - } // Float reference? - else if (type == StaticClassTypeTag< SqDataBinding< SQFloat > >::Get()) - { - addBind(new Poco::Data::ReferenceBinding< SQFloat >(obj.CastI< SqDataBinding< SQFloat > >()->mV, name, dir)); break; - } // String reference? - else if (type == StaticClassTypeTag< SqDataBinding< String > >::Get()) - { - addBind(new Poco::Data::ReferenceBinding< String >(obj.CastI< SqDataBinding< String > >()->mV, name, dir)); break; - } // Bool reference? - else if (type == StaticClassTypeTag< SqDataBinding< bool > >::Get()) - { - addBind(new Poco::Data::ReferenceBinding< bool >(obj.CastI< SqDataBinding< bool > >()->mV, name, dir)); break; - } // Unknown! - else - { - Var< LightObj >::push(SqVM(), obj); - String type_name = SqTypeName(SqVM(), -1); - sq_poptop(SqVM()); - STHROWF("Can't use (%s) values", type_name.c_str()); break; - } - - } break; + case OT_INSTANCE: UseInst_(obj, name, dir); break; default: STHROWF("Can't use (%s) values", SqTypeName(obj.GetType())); break; } - // - return *this; } // ------------------------------------------------------------------------------------------------ -SqDataStatement & SqDataStatement::BindEx(LightObj & obj, const std::string & name, Poco::Data::AbstractBinding::Direction dir) +void SqDataStatement::UseInst_(LightObj & obj, const std::string & name, Poco::Data::AbstractBinding::Direction dir) +{ + auto type = static_cast< AbstractStaticClassData * >(obj.GetTypeTag()); + // Integer reference? + if (type == StaticClassTypeTag< SqDataBinding< SQInteger > >::Get()) + { + addBind(new Poco::Data::ReferenceBinding< SQInteger >(obj.CastI< SqDataBinding< SQInteger > >()->mV, name, dir)); + } // Float reference? + else if (type == StaticClassTypeTag< SqDataBinding< SQFloat > >::Get()) + { + addBind(new Poco::Data::ReferenceBinding< SQFloat >(obj.CastI< SqDataBinding< SQFloat > >()->mV, name, dir)); + } // String reference? + else if (type == StaticClassTypeTag< SqDataBinding< String > >::Get()) + { + addBind(new Poco::Data::ReferenceBinding< String >(obj.CastI< SqDataBinding< String > >()->mV, name, dir)); + } // Bool reference? + else if (type == StaticClassTypeTag< SqDataBinding< bool > >::Get()) + { + addBind(new Poco::Data::ReferenceBinding< bool >(obj.CastI< SqDataBinding< bool > >()->mV, name, dir)); + } // Integer vector reference? + else if (type == StaticClassTypeTag< SqVector< SQInteger > >::Get()) + { + auto p = obj.CastI< SqVector< SQInteger > >(); + addBind(new Poco::Data::ReferenceBinding< std::vector< SQInteger > >(p->ValidRef(), name, dir)); + } // Float vector reference? + else if (type == StaticClassTypeTag< SqVector< SQFloat > >::Get()) + { + auto p = obj.CastI< SqVector< SQFloat > >(); + addBind(new Poco::Data::ReferenceBinding< std::vector< SQFloat > >(p->ValidRef(), name, dir)); + } // String vector reference? + else if (type == StaticClassTypeTag< SqVector< String > >::Get()) + { + auto p = obj.CastI< SqVector< String > >(); + addBind(new Poco::Data::ReferenceBinding< std::vector< String > >(p->ValidRef(), name, dir)); + } // Bool vector reference? + else if (type == StaticClassTypeTag< SqVector< bool > >::Get()) + { + // There is no point in having these + // Their usefulness is limited and pointless compared to the number of specializations needed get them to work + STHROWF("Boolean vectors are not implemented"); + } // Unknown! + else + { + Var< LightObj >::push(SqVM(), obj); + String type_name = SqTypeName(SqVM(), -1); + sq_poptop(SqVM()); + STHROWF("Can't use (%s) values", type_name.c_str()); + } +} + +// ------------------------------------------------------------------------------------------------ +void SqDataStatement::BindEx(LightObj & obj, const std::string & name, Poco::Data::AbstractBinding::Direction dir) { // Identify the object type switch (obj.GetType()) @@ -190,37 +212,154 @@ SqDataStatement & SqDataStatement::BindEx(LightObj & obj, const std::string & na addBind(new Poco::Data::CopyBinding(str.mPtr, name, dir)); } break; // Special? - case OT_INSTANCE: { - auto type = static_cast< AbstractStaticClassData * >(obj.GetTypeTag()); - // Integer reference? - if (type == StaticClassTypeTag< SqDataBinding< SQInteger > >::Get()) - { - addBind(new Poco::Data::CopyBinding< SQInteger >(*obj.CastI< SqDataBinding< SQInteger > >()->mV, name, dir)); break; - } // Float reference? - else if (type == StaticClassTypeTag< SqDataBinding< SQFloat > >::Get()) - { - addBind(new Poco::Data::CopyBinding< SQFloat >(*obj.CastI< SqDataBinding< SQFloat > >()->mV, name, dir)); break; - } // String reference? - else if (type == StaticClassTypeTag< SqDataBinding< String > >::Get()) - { - addBind(new Poco::Data::CopyBinding< String >(*obj.CastI< SqDataBinding< String > >()->mV, name, dir)); break; - } // Bool reference? - else if (type == StaticClassTypeTag< SqDataBinding< bool > >::Get()) - { - addBind(new Poco::Data::CopyBinding< bool >(*obj.CastI< SqDataBinding< bool > >()->mV, name, dir)); break; - } // Unknown! - else - { - Var< LightObj >::push(SqVM(), obj); - String type_name = SqTypeName(SqVM(), -1); - sq_poptop(SqVM()); - STHROWF("Can't bind (%s) values", type_name.c_str()); break; - } - - } break; + case OT_INSTANCE: BindInst_(obj, name, dir); break; default: STHROWF("Can't bind (%s) values", SqTypeName(obj.GetType())); break; } - // +} + +// ------------------------------------------------------------------------------------------------ +void SqDataStatement::BindInst_(LightObj & obj, const std::string & name, Poco::Data::AbstractBinding::Direction dir) +{ + auto type = static_cast< AbstractStaticClassData * >(obj.GetTypeTag()); + // Integer reference? + if (type == StaticClassTypeTag< SqDataBinding< SQInteger > >::Get()) + { + addBind(new Poco::Data::CopyBinding< SQInteger >(*obj.CastI< SqDataBinding< SQInteger > >()->mV, name, dir)); + } // Float reference? + else if (type == StaticClassTypeTag< SqDataBinding< SQFloat > >::Get()) + { + addBind(new Poco::Data::CopyBinding< SQFloat >(*obj.CastI< SqDataBinding< SQFloat > >()->mV, name, dir)); + } // String reference? + else if (type == StaticClassTypeTag< SqDataBinding< String > >::Get()) + { + addBind(new Poco::Data::CopyBinding< String >(*obj.CastI< SqDataBinding< String > >()->mV, name, dir)); + } // Bool reference? + else if (type == StaticClassTypeTag< SqDataBinding< bool > >::Get()) + { + addBind(new Poco::Data::CopyBinding< bool >(*obj.CastI< SqDataBinding< bool > >()->mV, name, dir)); + } // Integer vector reference? + else if (type == StaticClassTypeTag< SqVector< SQInteger > >::Get()) + { + addBind(new Poco::Data::CopyBinding< std::vector< SQInteger > >(obj.CastI< SqVector< SQInteger > >()->Valid(), name, dir)); + } // Float vector reference? + else if (type == StaticClassTypeTag< SqVector< SQFloat > >::Get()) + { + addBind(new Poco::Data::CopyBinding< std::vector< SQFloat > >(obj.CastI< SqVector< SQFloat > >()->Valid(), name, dir)); + } // String vector reference? + else if (type == StaticClassTypeTag< SqVector< String > >::Get()) + { + addBind(new Poco::Data::CopyBinding< std::vector< String > >(obj.CastI< SqVector< String > >()->Valid(), name, dir)); + } // Bool vector reference? + else if (type == StaticClassTypeTag< SqVector< bool > >::Get()) + { + // There is no point in having these + // Their usefulness is limited and pointless compared to the number of specializations needed get them to work + STHROWF("Boolean vectors are not implemented"); + } // Unknown! + else + { + Var< LightObj >::push(SqVM(), obj); + String type_name = SqTypeName(SqVM(), -1); + sq_poptop(SqVM()); + STHROWF("Can't bind (%s) values", type_name.c_str()); + } +} + +// ------------------------------------------------------------------------------------------------ +SqDataStatement & SqDataStatement::Into(LightObj & obj) +{ + auto type = static_cast< AbstractStaticClassData * >(obj.GetTypeTag()); + // Integer reference? + if (type == StaticClassTypeTag< SqDataBinding< SQInteger > >::Get()) + { + addExtract(new Poco::Data::ReferenceExtraction< SQInteger >(obj.CastI< SqDataBinding< SQInteger > >()->mV)); + } // Float reference? + else if (type == StaticClassTypeTag< SqDataBinding< SQFloat > >::Get()) + { + addExtract(new Poco::Data::ReferenceExtraction< SQFloat >(obj.CastI< SqDataBinding< SQFloat > >()->mV)); + } // String reference? + else if (type == StaticClassTypeTag< SqDataBinding< String > >::Get()) + { + addExtract(new Poco::Data::ReferenceExtraction< String >(obj.CastI< SqDataBinding< String > >()->mV)); + } // Bool reference? + else if (type == StaticClassTypeTag< SqDataBinding< bool > >::Get()) + { + addExtract(new Poco::Data::ReferenceExtraction< bool >(obj.CastI< SqDataBinding< bool > >()->mV)); + } // Integer vector reference? + else if (type == StaticClassTypeTag< SqVector< SQInteger > >::Get()) + { + addExtract(new Poco::Data::ReferenceExtraction< std::vector< SQInteger > >(obj.CastI< SqVector< SQInteger > >()->ValidRef())); + } // Float vector reference? + else if (type == StaticClassTypeTag< SqVector< SQFloat > >::Get()) + { + addExtract(new Poco::Data::ReferenceExtraction< std::vector< SQFloat > >(obj.CastI< SqVector< SQFloat > >()->ValidRef())); + } // String vector reference? + else if (type == StaticClassTypeTag< SqVector< String > >::Get()) + { + addExtract(new Poco::Data::ReferenceExtraction< std::vector< String > >(obj.CastI< SqVector< String > >()->ValidRef())); + } // Bool vector reference? + else if (type == StaticClassTypeTag< SqVector< bool > >::Get()) + { + // There is no point in having these + // Their usefulness is limited and pointless compared to the number of specializations needed get them to work + STHROWF("Boolean vectors are not implemented"); + } // Unknown! + else + { + Var< LightObj >::push(SqVM(), obj); + String type_name = SqTypeName(SqVM(), -1); + sq_poptop(SqVM()); + STHROWF("Can't extract (%s) values", type_name.c_str()); + } + return *this; +} + +// ------------------------------------------------------------------------------------------------ +SqDataStatement & SqDataStatement::Into_(LightObj & obj, LightObj & def) +{ + auto type = static_cast< AbstractStaticClassData * >(obj.GetTypeTag()); + // Integer reference? + if (type == StaticClassTypeTag< SqDataBinding< SQInteger > >::Get()) + { + addExtract(new Poco::Data::ReferenceExtraction< SQInteger >(obj.CastI< SqDataBinding< SQInteger > >()->mV, def.Cast< SQInteger >())); + } // Float reference? + else if (type == StaticClassTypeTag< SqDataBinding< SQFloat > >::Get()) + { + addExtract(new Poco::Data::ReferenceExtraction< SQFloat >(obj.CastI< SqDataBinding< SQFloat > >()->mV, def.Cast< SQFloat >())); + } // String reference? + else if (type == StaticClassTypeTag< SqDataBinding< String > >::Get()) + { + addExtract(new Poco::Data::ReferenceExtraction< String >(obj.CastI< SqDataBinding< String > >()->mV, def.Cast< String >())); + } // Bool reference? + else if (type == StaticClassTypeTag< SqDataBinding< bool > >::Get()) + { + addExtract(new Poco::Data::ReferenceExtraction< bool >(obj.CastI< SqDataBinding< bool > >()->mV, def.Cast< bool >())); + } // Integer vector reference? + else if (type == StaticClassTypeTag< SqVector< SQInteger > >::Get()) + { + addExtract(new Poco::Data::ReferenceExtraction< std::vector< SQInteger > >(obj.CastI< SqVector< SQInteger > >()->ValidRef(), def.Cast< SQInteger >())); + } // Float vector reference? + else if (type == StaticClassTypeTag< SqVector< SQFloat > >::Get()) + { + addExtract(new Poco::Data::ReferenceExtraction< std::vector< SQFloat > >(obj.CastI< SqVector< SQFloat > >()->ValidRef(), def.Cast< SQFloat >())); + } // String vector reference? + else if (type == StaticClassTypeTag< SqVector< String > >::Get()) + { + addExtract(new Poco::Data::ReferenceExtraction< std::vector< String > >(obj.CastI< SqVector< String > >()->ValidRef(), def.Cast< String >())); + } // Bool vector reference? + else if (type == StaticClassTypeTag< SqVector< bool > >::Get()) + { + // There is no point in having these + // Their usefulness is limited and pointless compared to the number of specializations needed get them to work + STHROWF("Boolean vectors are not implemented"); + } // Unknown! + else + { + Var< LightObj >::push(SqVM(), obj); + String type_name = SqTypeName(SqVM(), -1); + sq_poptop(SqVM()); + STHROWF("Can't extract (%s) values", type_name.c_str()); + } return *this; } @@ -245,6 +384,8 @@ static void Register_POCO_Data_Binding(HSQUIRRELVM vm, Table & ns, const SQChar .Func(_SC("Set"), &Binding::SetEx) .Func(_SC("Bind"), &Binding::Bind) .Func(_SC("BindAs"), &Binding::BindAs) + .Func(_SC("Use"), &Binding::Use) + .Func(_SC("UseAs"), &Binding::UseAs) ); } @@ -252,7 +393,7 @@ static void Register_POCO_Data_Binding(HSQUIRRELVM vm, Table & ns, const SQChar void Register_POCO_Data(HSQUIRRELVM vm) { Table ns(vm); - + //Poco::Data::Keywords::into() // -------------------------------------------------------------------------------------------- ns.Bind(_SC("Session"), Class< SqDataSession >(vm, SqPcDataSession::Str) @@ -307,16 +448,27 @@ void Register_POCO_Data(HSQUIRRELVM vm) .Prop(_SC("Initialized"), &SqDataStatement::Initialized) .Prop(_SC("Paused"), &SqDataStatement::Paused) .Prop(_SC("Done"), &SqDataStatement::Done) + .Prop(_SC("HasMoreDataSets"), &SqDataStatement::HasMoreDataSets) // Member Methods .Func(_SC("Add"), &SqDataStatement::Add) - .Func(_SC("Execute"), &SqDataStatement::Execute) - .Func(_SC("ExecuteAsync"), &SqDataStatement::ExecuteAsync) .Func(_SC("SetAsync"), &SqDataStatement::SetAsync) .Func(_SC("Reset"), &SqDataStatement::Reset) .Func(_SC("Use"), &SqDataStatement::Use) .Func(_SC("UseAs"), &SqDataStatement::UseAs) + .Func(_SC("In"), &SqDataStatement::In) + .Func(_SC("InAs"), &SqDataStatement::InAs) + .Func(_SC("Out"), &SqDataStatement::Out) + .Func(_SC("OutAs"), &SqDataStatement::OutAs) .Func(_SC("Bind"), &SqDataStatement::Bind) .Func(_SC("BindAs"), &SqDataStatement::BindAs) + .Func(_SC("Io"), &SqDataStatement::Io) + // Overloaded Member Methods + .Overload(_SC("Execute"), &SqDataStatement::Execute) + .Overload(_SC("Execute"), &SqDataStatement::Execute_) + .Overload(_SC("ExecuteAsync"), &SqDataStatement::ExecuteAsync) + .Overload(_SC("ExecuteAsync"), &SqDataStatement::ExecuteAsync_) + .Overload(_SC("Into"), &SqDataStatement::Into) + .Overload(_SC("Into"), &SqDataStatement::Into_) ); // -------------------------------------------------------------------------------------------- Register_POCO_Data_Binding< SQInteger, SqIntegerBinding >(vm, ns, _SC("IntBind")); diff --git a/module/PocoLib/Data.hpp b/module/PocoLib/Data.hpp index a6685a9e..20686d6a 100644 --- a/module/PocoLib/Data.hpp +++ b/module/PocoLib/Data.hpp @@ -2,6 +2,7 @@ // ------------------------------------------------------------------------------------------------ #include "Core/Utility.hpp" +#include "Library/Utils/Vector.hpp" // ------------------------------------------------------------------------------------------------ #include @@ -102,7 +103,7 @@ template struct ReferenceBinding : public AbstractBinding /* -------------------------------------------------------------------------------------------- * Reset the binding. */ - void reset () override + void reset() override { m_Bound = false; AbstractBinder::Ptr pBinder = getBinder(); @@ -116,6 +117,337 @@ private: bool m_Bound; }; +/* ------------------------------------------------------------------------------------------------ + * Implementation of AbstractBinding for shared ownership binding of values. + * Because we cannot take references to script variables, we use this as a proxy. +*/ +template struct ReferenceBinding> : public AbstractBinding +{ + using ValType = std::vector; + using ValPtr = SharedPtr; + using Ptr = SharedPtr>; + using Iterator = typename ValType::const_iterator; + + /* -------------------------------------------------------------------------------------------- + * Base constructor. + */ + explicit ReferenceBinding(const ValPtr& val, const std::string& name = "", Direction direction = PD_IN) + : AbstractBinding(name, direction), m_Value(val), m_Begin(), m_End() + { + if (PD_IN == direction && m_Value->size() == 0) + { + throw BindingException("It is illegal to bind to an empty data collection"); + } + m_Begin = m_Value->begin(); + m_End = m_Value->end(); + } + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~ReferenceBinding() override = default; + + /* -------------------------------------------------------------------------------------------- + * Retrieve columns occupied. + */ + SQMOD_NODISCARD std::size_t numOfColumnsHandled() const override + { + return TypeHandler::size(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve rows occupied. + */ + SQMOD_NODISCARD std::size_t numOfRowsHandled() const override + { + return m_Value->size(); + } + + /* -------------------------------------------------------------------------------------------- + * Check if binding is available. + */ + SQMOD_NODISCARD bool canBind() const override + { + return (m_Begin != m_End); + } + + /* -------------------------------------------------------------------------------------------- + * Bind the value. + */ + void bind(std::size_t pos) override + { + poco_assert_dbg(!getBinder().isNull()); + poco_assert_dbg(canBind()); + TypeHandler::bind(pos, *m_Begin, getBinder(), getDirection()); + ++m_Begin; + } + + /* -------------------------------------------------------------------------------------------- + * Reset the binding. + */ + void reset() override + { + m_Begin = m_Value->begin(); + m_End = m_Value->end(); + } + +private: + + ValPtr m_Value; + Iterator m_Begin; + Iterator m_End; +}; + +/* ------------------------------------------------------------------------------------------------ + * Implementation of AbstractExtraction for shared ownership binding of values. + * Because we cannot take references to script variables, we use this as a proxy. +*/ +template +class ReferenceExtraction: public AbstractExtraction +{ +public: + using ValType = T; + using Result = SharedPtr; + using ValPtr = SharedPtr; + using Type = Extraction; + using Ptr = SharedPtr; + + /* -------------------------------------------------------------------------------------------- + * Creates an Extraction object at specified position. Uses an empty object T as default value. + */ + explicit ReferenceExtraction(const Result& result, const Position& pos = Position(0)) + : AbstractExtraction(Limit::LIMIT_UNLIMITED, pos.value()) + , m_Result(result),m_Default(),m_Extracted(false),m_Null(false) + { + } + + /* -------------------------------------------------------------------------------------------- + * Creates an Extraction object at specified position. Uses the provided def object as default value. + */ + ReferenceExtraction(const Result& result, const T& def, const Position& pos = Position(0)) + : AbstractExtraction(Limit::LIMIT_UNLIMITED, pos.value()) + , m_Result(result), m_Default(def), m_Extracted(false), m_Null(false) + { + } + + /* -------------------------------------------------------------------------------------------- + * Creates an Extraction object at specified position. Uses the provided def object as default value. + */ + ReferenceExtraction(const Result& result, T&& def, const Position& pos = Position(0)) + : AbstractExtraction(Limit::LIMIT_UNLIMITED, pos.value()) + , m_Result(result), m_Default(std::move(def)), m_Extracted(false), m_Null(false) + { + } + + /* -------------------------------------------------------------------------------------------- + * Destroys the Extraction object. + */ + ~ReferenceExtraction() override = default; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the number of columns handled. + */ + SQMOD_NODISCARD std::size_t numOfColumnsHandled() const override + { + return TypeHandler::size(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the number of rows handled. + */ + SQMOD_NODISCARD std::size_t numOfRowsHandled() const override + { + return m_Extracted ? 1u : 0; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the number of rows allowed. + */ + SQMOD_NODISCARD std::size_t numOfRowsAllowed() const override + { + return 1u; + } + + /* -------------------------------------------------------------------------------------------- + * Check if null. + */ + SQMOD_NODISCARD bool isNull(std::size_t /*row*/) const override + { + return m_Null; + } + + /* -------------------------------------------------------------------------------------------- + * Extract the value. + */ + std::size_t extract(std::size_t pos) override + { + if (m_Extracted) + { + throw ExtractException("value already extracted"); + } + + m_Extracted = true; + AbstractExtractor::Ptr pExt = getExtractor(); + TypeHandler::extract(pos, *m_Result, m_Default, pExt); + m_Null = isValueNull(*m_Result, pExt->isNull(pos)); + + return 1u; + } + + /* -------------------------------------------------------------------------------------------- + * Reset state. + */ + void reset() override + { + m_Extracted = false; + } + + /* -------------------------------------------------------------------------------------------- + * See if a value was extracted. + */ + SQMOD_NODISCARD bool canExtract() const override + { + return !m_Extracted; + } + + /* -------------------------------------------------------------------------------------------- + * Create a preparation instance for this type. + */ + AbstractPreparation::Ptr createPreparation(AbstractPreparator::Ptr& pPrep, std::size_t pos) override + { + return new Preparation(pPrep, pos, *m_Result); + } + +private: + + Result m_Result; + T m_Default; + bool m_Extracted; + bool m_Null; +}; + +/* ------------------------------------------------------------------------------------------------ + * Implementation of AbstractExtraction for shared ownership binding of values. + * Because we cannot take references to script variables, we use this as a proxy. +*/ +template +class ReferenceExtraction>: public AbstractExtraction +{ +public: + using ValType = std::vector; + using Result = SharedPtr>; + using ValPtr = SharedPtr; + using Type = Extraction; + using Ptr = SharedPtr; + + /* -------------------------------------------------------------------------------------------- + * Creates an Extraction object at specified position. Uses an empty object T as default value. + */ + explicit ReferenceExtraction(const Result& result, const Position& pos = Position(0)) + : AbstractExtraction(Limit::LIMIT_UNLIMITED, pos.value()) + , m_Result(result), m_Default(), m_Nulls() + { + m_Result->clear(); + } + + /* -------------------------------------------------------------------------------------------- + * Creates an Extraction object at specified position. Uses the provided def object as default value. + */ + ReferenceExtraction(const Result& result, const T& def, const Position& pos = Position(0)) + : AbstractExtraction(Limit::LIMIT_UNLIMITED, pos.value()) + , m_Result(result), m_Default(def), m_Nulls() + { + m_Result->clear(); + } + + /* -------------------------------------------------------------------------------------------- + * Destroys the Extraction object. + */ + ~ReferenceExtraction() override = default; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the number of columns handled. + */ + SQMOD_NODISCARD std::size_t numOfColumnsHandled() const override + { + return TypeHandler::size(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the number of rows handled. + */ + SQMOD_NODISCARD std::size_t numOfRowsHandled() const override + { + return static_cast(m_Result->size()); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the number of rows allowed. + */ + SQMOD_NODISCARD std::size_t numOfRowsAllowed() const override + { + return getLimit(); + } + + /* -------------------------------------------------------------------------------------------- + * Check if null. + */ + SQMOD_NODISCARD bool isNull(std::size_t row) const override + { + try + { + return m_Nulls.at(row); + } + catch (std::out_of_range& ex) + { + throw RangeException(ex.what()); + } + } + + /* -------------------------------------------------------------------------------------------- + * Extract the value. + */ + std::size_t extract(std::size_t pos) override + { + AbstractExtractor::Ptr ext = getExtractor(); + m_Result->push_back(m_Default); + TypeHandler::extract(pos, m_Result->back(), m_Default, ext); + m_Nulls.push_back(isValueNull(m_Result->back(), ext->isNull(pos))); + return 1u; + } + + /* -------------------------------------------------------------------------------------------- + * Create a preparation instance for this type. + */ + AbstractPreparation::Ptr createPreparation(AbstractPreparator::Ptr& pPrep, std::size_t pos) override + { + return new Preparation(pPrep, pos, m_Default); + } + + /* -------------------------------------------------------------------------------------------- + * Reset state. + */ + void reset() override + { + m_Nulls.clear(); + } + +protected: + + /* -------------------------------------------------------------------------------------------- + * Retrieve the container with the extracted values. + */ + const std::vector& result() const + { + return *m_Result; + } + +private: + Result m_Result; + T m_Default; + std::deque< bool > m_Nulls; +}; + } // Namespace:: Data } // Namespace:: Poco @@ -256,6 +588,16 @@ template < class T > struct SqDataBinding */ SqDataBinding & SetEx(OptimalArg v) { SqDataBindingOpt< T >::Put(*mV, v); return *this; } + /* -------------------------------------------------------------------------------------------- + * Use the value to a statement. + */ + SqDataBinding & Use(SqDataStatement & stmt); + + /* -------------------------------------------------------------------------------------------- + * Use the value to a statement with a specific name. + */ + SqDataBinding & UseAs(SqDataStatement & stmt, StackStrF & name); + /* -------------------------------------------------------------------------------------------- * Bind the value to a statement. */ @@ -551,7 +893,15 @@ struct SqDataStatement : public Statement /* -------------------------------------------------------------------------------------------- * Executes the statement synchronously or asynchronously. */ - SQInteger Execute(bool reset) + SQInteger Execute() + { + return static_cast< SQInteger >(execute(true)); + } + + /* -------------------------------------------------------------------------------------------- + * Executes the statement synchronously or asynchronously. + */ + SQInteger Execute_(bool reset) { return static_cast< SQInteger >(execute(reset)); } @@ -559,7 +909,16 @@ struct SqDataStatement : public Statement /* -------------------------------------------------------------------------------------------- * Executes the statement asynchronously. */ - SqDataStatement & ExecuteAsync(bool reset) + SqDataStatement & ExecuteAsync() + { + executeAsync(true); + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Executes the statement asynchronously. + */ + SqDataStatement & ExecuteAsync_(bool reset) { executeAsync(reset); return *this; @@ -583,57 +942,155 @@ struct SqDataStatement : public Statement } /* -------------------------------------------------------------------------------------------- - * + * Bind a reference to the statement. */ SqDataStatement & Use(LightObj & obj) { - return UseEx(obj, String(), Poco::Data::AbstractBinding::PD_IN); + UseEx(obj, String(), Poco::Data::AbstractBinding::PD_IN); + return *this; } /* -------------------------------------------------------------------------------------------- - * + * Bind a named reference to the statement. */ SqDataStatement & UseAs(LightObj & obj, StackStrF & name) { - return UseEx(obj, String(name.mPtr, name.GetSize()), Poco::Data::AbstractBinding::PD_IN); + UseEx(obj, String(name.mPtr, name.GetSize()), Poco::Data::AbstractBinding::PD_IN); + return *this; } /* -------------------------------------------------------------------------------------------- - * + * Internal function used internally to bind a reference to the statement. */ - SqDataStatement & UseEx(LightObj & obj, const std::string & name, Poco::Data::AbstractBinding::Direction dir); + void UseEx(LightObj & obj, const std::string & name, Poco::Data::AbstractBinding::Direction dir); /* -------------------------------------------------------------------------------------------- - * + * Internal function used internally to bind a instance reference to the statement. + */ + void UseInst_(LightObj & obj, const std::string & name, Poco::Data::AbstractBinding::Direction dir); + + /* -------------------------------------------------------------------------------------------- + * Bind a value to the statement and mark it as input (i.e alias of Use). + */ + SqDataStatement & In(LightObj & obj) + { + return Use(obj); + } + + /* -------------------------------------------------------------------------------------------- + * Bind a named value to the statement mark it as input (i.e alias of UseAs). + */ + SqDataStatement & InAs(LightObj & obj, StackStrF & name) + { + return UseAs(obj, name); + } + + /* -------------------------------------------------------------------------------------------- + * Bind a reference to the statement and mark it as output. + */ + SqDataStatement & Out(LightObj & obj) + { + UseEx(obj, String(), Poco::Data::AbstractBinding::PD_OUT); + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Bind a named reference to the statement and mark it as output. + */ + SqDataStatement & OutAs(LightObj & obj, StackStrF & name) + { + UseEx(obj, String(name.mPtr, name.GetSize()), Poco::Data::AbstractBinding::PD_OUT); + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Bind a value to the statement. */ SqDataStatement & Bind(LightObj & obj) { - return BindEx(obj, String(), Poco::Data::AbstractBinding::PD_IN); + BindEx(obj, String(), Poco::Data::AbstractBinding::PD_IN); + return *this; } /* -------------------------------------------------------------------------------------------- - * + * Bind a named value to the statement. */ SqDataStatement & BindAs(LightObj & obj, StackStrF & name) { - return BindEx(obj, String(name.mPtr, name.GetSize()), Poco::Data::AbstractBinding::PD_IN); + BindEx(obj, String(name.mPtr, name.GetSize()), Poco::Data::AbstractBinding::PD_IN); + return *this; } /* -------------------------------------------------------------------------------------------- - * + * Internal function used internally to bind a value to the statement. */ - SqDataStatement & BindEx(LightObj & obj, const std::string & name, Poco::Data::AbstractBinding::Direction dir); + void BindEx(LightObj & obj, const std::string & name, Poco::Data::AbstractBinding::Direction dir); + + /* -------------------------------------------------------------------------------------------- + * Internal function used internally to bind a instance value to the statement. + */ + void BindInst_(LightObj & obj, const std::string & name, Poco::Data::AbstractBinding::Direction dir); + + /* -------------------------------------------------------------------------------------------- + * Bind a value to the statement and mark it as input/output. + */ + SqDataStatement & Io(LightObj & obj) + { + if (obj.GetType() == OT_INSTANCE) + { + UseInst_(obj, String(), Poco::Data::AbstractBinding::PD_IN_OUT); + } + else + { + Bind(obj); + } + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Register a single extraction with the statement. + */ + SqDataStatement & Into(LightObj & obj); + + /* -------------------------------------------------------------------------------------------- + * Register a single extraction with the statement with a default value. + */ + SqDataStatement & Into_(LightObj & obj, LightObj & def); + + /* -------------------------------------------------------------------------------------------- + * Returns false if the current data set index points to the last data set. Otherwise, it returns true. + */ + bool HasMoreDataSets() const + { + return hasMoreDataSets(); + } }; +// ------------------------------------------------------------------------------------------------ +template < class T > inline SqDataBinding< T > & SqDataBinding< T >::Use(SqDataStatement & stmt) +{ + stmt.addBind(new Poco::Data::ReferenceBinding< T >(mV, String(), Poco::Data::AbstractBinding::PD_IN)); + return *this; +} + +// ------------------------------------------------------------------------------------------------ +template < class T > inline SqDataBinding< T > & SqDataBinding< T >::UseAs(SqDataStatement & stmt, StackStrF & name) +{ + stmt.addBind(new Poco::Data::ReferenceBinding< T >(mV, name.ToStr(), Poco::Data::AbstractBinding::PD_IN)); + return *this; +} + // ------------------------------------------------------------------------------------------------ template < class T > inline SqDataBinding< T > & SqDataBinding< T >::Bind(SqDataStatement & stmt) { + stmt.addBind(new Poco::Data::CopyBinding< T >(*mV, String(), Poco::Data::AbstractBinding::PD_IN)); return *this; } // ------------------------------------------------------------------------------------------------ template < class T > inline SqDataBinding< T > & SqDataBinding< T >::BindAs(SqDataStatement & stmt, StackStrF & name) { + stmt.addBind(new Poco::Data::CopyBinding< T >(*mV, name.ToStr(), Poco::Data::AbstractBinding::PD_IN)); return *this; }